From e63814cc3adf168d094ea09527e6fac3b045e9c6 Mon Sep 17 00:00:00 2001 From: skhokhlov Date: Fri, 12 May 2023 10:53:24 +0300 Subject: [PATCH 1/2] feat(config): Make MaximumNumberOfResults and MaximumNumberOfEvents configurable --- Makefile | 2 +- README.md | 14 ++--- api/api.go | 2 +- api/endpoint_status.go | 42 +++++++-------- api/endpoint_status_test.go | 13 ++++- api/util.go | 10 ++-- api/util_test.go | 68 ++++++++++++++----------- config.yaml | 4 +- config/config.go | 5 +- config/config_test.go | 5 ++ config/ui/ui.go | 14 +++-- storage/config.go | 17 +++++++ storage/store/common/limits.go | 9 ---- storage/store/memory/memory.go | 13 +++-- storage/store/memory/memory_test.go | 5 +- storage/store/memory/uptime_test.go | 3 +- storage/store/memory/util.go | 11 ++-- storage/store/memory/util_bench_test.go | 6 +-- storage/store/memory/util_test.go | 18 +++---- storage/store/sql/sql.go | 30 +++++++---- storage/store/sql/sql_test.go | 35 +++++++------ storage/store/store.go | 8 ++- storage/store/store_bench_test.go | 13 ++--- storage/store/store_test.go | 16 +++--- web/app/public/index.html | 2 +- web/app/src/components/Pagination.vue | 10 +++- web/app/src/views/Details.vue | 5 +- web/static/css/app.css | 2 +- web/static/index.html | 2 +- web/static/js/app.js | 2 +- 30 files changed, 233 insertions(+), 153 deletions(-) delete mode 100644 storage/store/common/limits.go diff --git a/Makefile b/Makefile index 26ee58a64..e13218adb 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ clean: rm $(BINARY) test: - go test ./... -cover + go test ./... -cover -race ########## diff --git a/README.md b/README.md index 7335d44d2..db661ea81 100644 --- a/README.md +++ b/README.md @@ -298,12 +298,14 @@ Here are some examples of conditions you can use: ### Storage -| Parameter | Description | Default | -|:------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|:-----------| -| `storage` | Storage configuration | `{}` | -| `storage.path` | Path to persist the data in. Only supported for types `sqlite` and `postgres`. | `""` | -| `storage.type` | Type of storage. Valid types: `memory`, `sqlite`, `postgres`. | `"memory"` | -| `storage.caching` | Whether to use write-through caching. Improves loading time for large dashboards.
Only supported if `storage.type` is `sqlite` or `postgres` | `false` | +| Parameter | Description | Default | +|:------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|:-----------| +| `storage` | Storage configuration | `{}` | +| `storage.path` | Path to persist the data in. Only supported for types `sqlite` and `postgres`. | `""` | +| `storage.type` | Type of storage. Valid types: `memory`, `sqlite`, `postgres`. | `"memory"` | +| `storage.caching` | Whether to use write-through caching. Improves loading time for large dashboards.
Only supported if `storage.type` is `sqlite` or `postgres` | `false` | +| `storage.maximum-number-of-results` | The maximum number of results that an endpoint can have | `100` | +| `storage.maximum-number-of-events` | The maximum number of events that an endpoint can have | `50` | The results for each endpoint health check as well as the data for uptime and the past events must be persisted so that they can be displayed on the dashboard. These parameters allow you to configure the storage in question. diff --git a/api/api.go b/api/api.go index 08bbca9dd..7e6ec136d 100644 --- a/api/api.go +++ b/api/api.go @@ -107,6 +107,6 @@ func (a *API) createRouter(cfg *config.Config) *fiber.App { } } protectedAPIRouter.Get("/v1/endpoints/statuses", EndpointStatuses(cfg)) - protectedAPIRouter.Get("/v1/endpoints/:key/statuses", EndpointStatus) + protectedAPIRouter.Get("/v1/endpoints/:key/statuses", EndpointStatus(cfg)) return app } diff --git a/api/endpoint_status.go b/api/endpoint_status.go index 14a1d55c3..50d446155 100644 --- a/api/endpoint_status.go +++ b/api/endpoint_status.go @@ -20,7 +20,7 @@ import ( // Due to how intensive this operation can be on the storage, this function leverages a cache. func EndpointStatuses(cfg *config.Config) fiber.Handler { return func(c *fiber.Ctx) error { - page, pageSize := extractPageAndPageSizeFromRequest(c) + page, pageSize := extractPageAndPageSizeFromRequest(c, cfg.Storage.MaximumNumberOfResults) value, exists := cache.Get(fmt.Sprintf("endpoint-status-%d-%d", page, pageSize)) var data []byte if !exists { @@ -83,25 +83,27 @@ func getEndpointStatusesFromRemoteInstances(remoteConfig *remote.Config) ([]*cor } // EndpointStatus retrieves a single core.EndpointStatus by group and endpoint name -func EndpointStatus(c *fiber.Ctx) error { - page, pageSize := extractPageAndPageSizeFromRequest(c) - endpointStatus, err := store.Get().GetEndpointStatusByKey(c.Params("key"), paging.NewEndpointStatusParams().WithResults(page, pageSize).WithEvents(1, common.MaximumNumberOfEvents)) - if err != nil { - if err == common.ErrEndpointNotFound { - return c.Status(404).SendString(err.Error()) +func EndpointStatus(cfg *config.Config) fiber.Handler { + return func(c *fiber.Ctx) error { + page, pageSize := extractPageAndPageSizeFromRequest(c, cfg.Storage.MaximumNumberOfResults) + endpointStatus, err := store.Get().GetEndpointStatusByKey(c.Params("key"), paging.NewEndpointStatusParams().WithResults(page, pageSize).WithEvents(1, cfg.Storage.MaximumNumberOfEvents)) + if err != nil { + if err == common.ErrEndpointNotFound { + return c.Status(404).SendString(err.Error()) + } + log.Printf("[api][EndpointStatus] Failed to retrieve endpoint status: %s", err.Error()) + return c.Status(500).SendString(err.Error()) } - log.Printf("[api][EndpointStatus] Failed to retrieve endpoint status: %s", err.Error()) - return c.Status(500).SendString(err.Error()) - } - if endpointStatus == nil { // XXX: is this check necessary? - log.Printf("[api][EndpointStatus] Endpoint with key=%s not found", c.Params("key")) - return c.Status(404).SendString("not found") - } - output, err := json.Marshal(endpointStatus) - if err != nil { - log.Printf("[api][EndpointStatus] Unable to marshal object to JSON: %s", err.Error()) - return c.Status(500).SendString("unable to marshal object to JSON") + if endpointStatus == nil { // XXX: is this check necessary? + log.Printf("[api][EndpointStatus] Endpoint with key=%s not found", c.Params("key")) + return c.Status(404).SendString("not found") + } + output, err := json.Marshal(endpointStatus) + if err != nil { + log.Printf("[api][EndpointStatus] Unable to marshal object to JSON: %s", err.Error()) + return c.Status(500).SendString("unable to marshal object to JSON") + } + c.Set("Content-Type", "application/json") + return c.Status(200).Send(output) } - c.Set("Content-Type", "application/json") - return c.Status(200).Send(output) } diff --git a/api/endpoint_status_test.go b/api/endpoint_status_test.go index b88a915f7..3ca6d9773 100644 --- a/api/endpoint_status_test.go +++ b/api/endpoint_status_test.go @@ -11,6 +11,7 @@ import ( "github.com/TwiN/gatus/v5/core" "github.com/TwiN/gatus/v5/storage/store" "github.com/TwiN/gatus/v5/watchdog" + "github.com/TwiN/gatus/v5/storage" ) var ( @@ -95,6 +96,10 @@ func TestEndpointStatus(t *testing.T) { Group: "core", }, }, + Storage: &storage.Config{ + MaximumNumberOfResults: storage.DefaultMaximumNumberOfResults, + MaximumNumberOfEvents: storage.DefaultMaximumNumberOfEvents, + }, } watchdog.UpdateEndpointStatuses(cfg.Endpoints[0], &core.Result{Success: true, Duration: time.Millisecond, Timestamp: time.Now()}) watchdog.UpdateEndpointStatuses(cfg.Endpoints[1], &core.Result{Success: false, Duration: time.Second, Timestamp: time.Now()}) @@ -156,7 +161,13 @@ func TestEndpointStatuses(t *testing.T) { // Can't be bothered dealing with timezone issues on the worker that runs the automated tests firstResult.Timestamp = time.Time{} secondResult.Timestamp = time.Time{} - api := New(&config.Config{Metrics: true}) + api := New(&config.Config{ + Metrics: true, + Storage: &storage.Config{ + MaximumNumberOfResults: storage.DefaultMaximumNumberOfResults, + MaximumNumberOfEvents: storage.DefaultMaximumNumberOfEvents, + }, + }) router := api.Router() type Scenario struct { Name string diff --git a/api/util.go b/api/util.go index 90e647b5f..766ab7820 100644 --- a/api/util.go +++ b/api/util.go @@ -3,7 +3,6 @@ package api import ( "strconv" - "github.com/TwiN/gatus/v5/storage/store/common" "github.com/gofiber/fiber/v2" ) @@ -13,12 +12,9 @@ const ( // DefaultPageSize is the default page siZE to use if none is specified or an invalid value is provided DefaultPageSize = 20 - - // MaximumPageSize is the maximum page size allowed - MaximumPageSize = common.MaximumNumberOfResults ) -func extractPageAndPageSizeFromRequest(c *fiber.Ctx) (page, pageSize int) { +func extractPageAndPageSizeFromRequest(c *fiber.Ctx, maximumNumberOfResults int) (page, pageSize int) { var err error if pageParameter := c.Query("page"); len(pageParameter) == 0 { page = DefaultPage @@ -38,8 +34,8 @@ func extractPageAndPageSizeFromRequest(c *fiber.Ctx) (page, pageSize int) { if err != nil { pageSize = DefaultPageSize } - if pageSize > MaximumPageSize { - pageSize = MaximumPageSize + if pageSize > maximumNumberOfResults { + pageSize = maximumNumberOfResults } else if pageSize < 1 { pageSize = DefaultPageSize } diff --git a/api/util_test.go b/api/util_test.go index 652146edf..a0e846a92 100644 --- a/api/util_test.go +++ b/api/util_test.go @@ -4,54 +4,62 @@ import ( "fmt" "testing" + "github.com/TwiN/gatus/v5/storage" "github.com/gofiber/fiber/v2" "github.com/valyala/fasthttp" ) func TestExtractPageAndPageSizeFromRequest(t *testing.T) { type Scenario struct { - Name string - Page string - PageSize string - ExpectedPage int - ExpectedPageSize int + Name string + Page string + PageSize string + ExpectedPage int + ExpectedPageSize int + MaximumNumberOfResults int } scenarios := []Scenario{ { - Page: "1", - PageSize: "20", - ExpectedPage: 1, - ExpectedPageSize: 20, + Page: "1", + PageSize: "20", + ExpectedPage: 1, + ExpectedPageSize: 20, + MaximumNumberOfResults: 20, }, { - Page: "2", - PageSize: "10", - ExpectedPage: 2, - ExpectedPageSize: 10, + Page: "2", + PageSize: "10", + ExpectedPage: 2, + ExpectedPageSize: 10, + MaximumNumberOfResults: 40, }, { - Page: "2", - PageSize: "10", - ExpectedPage: 2, - ExpectedPageSize: 10, + Page: "2", + PageSize: "10", + ExpectedPage: 2, + ExpectedPageSize: 10, + MaximumNumberOfResults: 200, }, { - Page: "1", - PageSize: "999999", - ExpectedPage: 1, - ExpectedPageSize: MaximumPageSize, + Page: "1", + PageSize: "999999", + ExpectedPage: 1, + ExpectedPageSize: storage.DefaultMaximumNumberOfResults, + MaximumNumberOfResults: 100, }, { - Page: "-1", - PageSize: "-1", - ExpectedPage: DefaultPage, - ExpectedPageSize: DefaultPageSize, + Page: "-1", + PageSize: "-1", + ExpectedPage: DefaultPage, + ExpectedPageSize: DefaultPageSize, + MaximumNumberOfResults: 20, }, { - Page: "invalid", - PageSize: "invalid", - ExpectedPage: DefaultPage, - ExpectedPageSize: DefaultPageSize, + Page: "invalid", + PageSize: "invalid", + ExpectedPage: DefaultPage, + ExpectedPageSize: DefaultPageSize, + MaximumNumberOfResults: 100, }, } for _, scenario := range scenarios { @@ -61,7 +69,7 @@ func TestExtractPageAndPageSizeFromRequest(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) c.Request().SetRequestURI(fmt.Sprintf("/api/v1/statuses?page=%s&pageSize=%s", scenario.Page, scenario.PageSize)) - actualPage, actualPageSize := extractPageAndPageSizeFromRequest(c) + actualPage, actualPageSize := extractPageAndPageSizeFromRequest(c, scenario.MaximumNumberOfResults) if actualPage != scenario.ExpectedPage { t.Errorf("expected %d, got %d", scenario.ExpectedPage, actualPage) } diff --git a/config.yaml b/config.yaml index ee49818fd..cc4d357be 100644 --- a/config.yaml +++ b/config.yaml @@ -2,7 +2,7 @@ endpoints: - name: front-end group: core url: "https://twin.sh/health" - interval: 5m + interval: 1s conditions: - "[STATUS] == 200" - "[BODY].status == UP" @@ -51,3 +51,5 @@ endpoints: interval: 1h conditions: - "[DOMAIN_EXPIRATION] > 720h" +storage: + maximum-number-of-results: 1000 \ No newline at end of file diff --git a/config/config.go b/config/config.go index 298ab9326..1c14eff22 100644 --- a/config/config.go +++ b/config/config.go @@ -259,6 +259,7 @@ func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) { if err := validateConnectivityConfig(config); err != nil { return nil, err } + config.UI.MaximumNumberOfResults = config.Storage.MaximumNumberOfResults } return } @@ -282,7 +283,9 @@ func validateRemoteConfig(config *Config) error { func validateStorageConfig(config *Config) error { if config.Storage == nil { config.Storage = &storage.Config{ - Type: storage.TypeMemory, + Type: storage.TypeMemory, + MaximumNumberOfResults: storage.DefaultMaximumNumberOfResults, + MaximumNumberOfEvents: storage.DefaultMaximumNumberOfEvents, } } else { if err := config.Storage.ValidateAndSetDefaults(); err != nil { diff --git a/config/config_test.go b/config/config_test.go index ef1068a7d..3156a8074 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -303,6 +303,8 @@ func TestParseAndValidateConfigBytes(t *testing.T) { storage: type: sqlite path: %s + maximum-number-of-results: 10 + maximum-number-of-events: 5 maintenance: enabled: true start: 00:00 @@ -351,6 +353,9 @@ endpoints: if config.Storage == nil || config.Storage.Path != file || config.Storage.Type != storage.TypeSQLite { t.Error("expected storage to be set to sqlite, got", config.Storage) } + if config.Storage == nil || config.Storage.MaximumNumberOfResults != 10 || config.Storage.MaximumNumberOfEvents != 5 { + t.Error("expected MaximumNumberOfResults and MaximumNumberOfEvents to be set to 10 and 5, got", config.Storage.MaximumNumberOfResults, config.Storage.MaximumNumberOfEvents) + } if config.UI == nil || config.UI.Title != "T" || config.UI.Header != "H" || config.UI.Link != "https://example.org" || len(config.UI.Buttons) != 2 || config.UI.Buttons[0].Name != "Home" || config.UI.Buttons[0].Link != "https://example.org" || config.UI.Buttons[1].Name != "Status page" || config.UI.Buttons[1].Link != "https://status.example.org" { t.Error("expected ui to be set to T, H, https://example.org, 2 buttons, Home and Status page, got", config.UI) } diff --git a/config/ui/ui.go b/config/ui/ui.go index e61440aff..192a8e3a9 100644 --- a/config/ui/ui.go +++ b/config/ui/ui.go @@ -5,6 +5,7 @@ import ( "errors" "html/template" + "github.com/TwiN/gatus/v5/storage" static "github.com/TwiN/gatus/v5/web" ) @@ -28,6 +29,8 @@ type Config struct { Logo string `yaml:"logo,omitempty"` // Logo to display on the page Link string `yaml:"link,omitempty"` // Link to open when clicking on the logo Buttons []Button `yaml:"buttons,omitempty"` // Buttons to display below the header + + MaximumNumberOfResults int // MaximumNumberOfResults to display on the page, it's not configurable because we're passing it from the storage config } // Button is the configuration for a button on the UI @@ -47,11 +50,12 @@ func (btn *Button) Validate() error { // GetDefaultConfig returns a Config struct with the default values func GetDefaultConfig() *Config { return &Config{ - Title: defaultTitle, - Description: defaultDescription, - Header: defaultHeader, - Logo: defaultLogo, - Link: defaultLink, + Title: defaultTitle, + Description: defaultDescription, + Header: defaultHeader, + Logo: defaultLogo, + Link: defaultLink, + MaximumNumberOfResults: storage.DefaultMaximumNumberOfResults, } } diff --git a/storage/config.go b/storage/config.go index 5ee3539de..bd701b8aa 100644 --- a/storage/config.go +++ b/storage/config.go @@ -4,6 +4,11 @@ import ( "errors" ) +const ( + DefaultMaximumNumberOfResults = 100 + DefaultMaximumNumberOfEvents = 50 +) + var ( ErrSQLStorageRequiresPath = errors.New("sql storage requires a non-empty path to be defined") ErrMemoryStorageDoesNotSupportPath = errors.New("memory storage does not support persistence, use sqlite if you want persistence on file") @@ -25,6 +30,12 @@ type Config struct { // as they happen, also known as the write-through caching strategy. // Does not apply if Config.Type is not TypePostgres or TypeSQLite. Caching bool `yaml:"caching,omitempty"` + + // MaximumNumberOfResults is the maximum number of results that an endpoint can have + MaximumNumberOfResults int `yaml:"maximum-number-of-results,omitempty"` + + // MaximumNumberOfEvents is the maximum number of events that an endpoint can have + MaximumNumberOfEvents int `yaml:"maximum-number-of-events,omitempty"` } // ValidateAndSetDefaults validates the configuration and sets the default values (if applicable) @@ -38,5 +49,11 @@ func (c *Config) ValidateAndSetDefaults() error { if c.Type == TypeMemory && len(c.Path) > 0 { return ErrMemoryStorageDoesNotSupportPath } + if c.MaximumNumberOfResults <= 0 { + c.MaximumNumberOfResults = DefaultMaximumNumberOfResults + } + if c.MaximumNumberOfEvents <= 0 { + c.MaximumNumberOfEvents = DefaultMaximumNumberOfEvents + } return nil } diff --git a/storage/store/common/limits.go b/storage/store/common/limits.go deleted file mode 100644 index 92007220f..000000000 --- a/storage/store/common/limits.go +++ /dev/null @@ -1,9 +0,0 @@ -package common - -const ( - // MaximumNumberOfResults is the maximum number of results that an endpoint can have - MaximumNumberOfResults = 100 - - // MaximumNumberOfEvents is the maximum number of events that an endpoint can have - MaximumNumberOfEvents = 50 -) diff --git a/storage/store/memory/memory.go b/storage/store/memory/memory.go index 281e4a595..644d1fc71 100644 --- a/storage/store/memory/memory.go +++ b/storage/store/memory/memory.go @@ -17,15 +17,22 @@ type Store struct { sync.RWMutex cache *gocache.Cache + + // maximumNumberOfResults is the maximum number of results that an endpoint can have + maximumNumberOfResults int + // maximumNumberOfEvents is the maximum number of events that an endpoint can have + maximumNumberOfEvents int } // NewStore creates a new store using gocache.Cache // // This store holds everything in memory, and if the file parameter is not blank, // supports eventual persistence. -func NewStore() (*Store, error) { +func NewStore(maximumNumberOfResults int, maximumNumberOfEvents int) (*Store, error) { store := &Store{ - cache: gocache.NewCache().WithMaxSize(gocache.NoMaxSize), + cache: gocache.NewCache().WithMaxSize(gocache.NoMaxSize), + maximumNumberOfResults: maximumNumberOfResults, + maximumNumberOfEvents: maximumNumberOfEvents, } return store, nil } @@ -151,7 +158,7 @@ func (s *Store) Insert(endpoint *core.Endpoint, result *core.Result) error { Timestamp: time.Now(), }) } - AddResult(status.(*core.EndpointStatus), result) + AddResult(status.(*core.EndpointStatus), result, s.maximumNumberOfResults, s.maximumNumberOfEvents) s.cache.Set(key, status) s.Unlock() return nil diff --git a/storage/store/memory/memory_test.go b/storage/store/memory/memory_test.go index ea0bd1cd6..e9ecf5c09 100644 --- a/storage/store/memory/memory_test.go +++ b/storage/store/memory/memory_test.go @@ -1,6 +1,7 @@ package memory import ( + "github.com/TwiN/gatus/v5/storage" "testing" "time" @@ -82,7 +83,7 @@ var ( // Note that are much more extensive tests in /storage/store/store_test.go. // This test is simply an extra sanity check func TestStore_SanityCheck(t *testing.T) { - store, _ := NewStore() + store, _ := NewStore(storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() store.Insert(&testEndpoint, &testSuccessfulResult) endpointStatuses, _ := store.GetAllEndpointStatuses(paging.NewEndpointStatusParams()) @@ -122,7 +123,7 @@ func TestStore_SanityCheck(t *testing.T) { } func TestStore_Save(t *testing.T) { - store, err := NewStore() + store, err := NewStore(storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { t.Fatal("expected no error, got", err.Error()) } diff --git a/storage/store/memory/uptime_test.go b/storage/store/memory/uptime_test.go index 071bb4ce3..41d808510 100644 --- a/storage/store/memory/uptime_test.go +++ b/storage/store/memory/uptime_test.go @@ -1,6 +1,7 @@ package memory import ( + "github.com/TwiN/gatus/v5/storage" "testing" "time" @@ -50,7 +51,7 @@ func TestAddResultUptimeIsCleaningUpAfterItself(t *testing.T) { // Start 12 days ago timestamp := now.Add(-12 * 24 * time.Hour) for timestamp.Unix() <= now.Unix() { - AddResult(status, &core.Result{Timestamp: timestamp, Success: true}) + AddResult(status, &core.Result{Timestamp: timestamp, Success: true}, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if len(status.Uptime.HourlyStatistics) > numberOfHoursInTenDays { t.Errorf("At no point in time should there be more than %d entries in status.SuccessfulExecutionsPerHour, but there are %d", numberOfHoursInTenDays, len(status.Uptime.HourlyStatistics)) } diff --git a/storage/store/memory/util.go b/storage/store/memory/util.go index 7ba757e1e..bd77aab27 100644 --- a/storage/store/memory/util.go +++ b/storage/store/memory/util.go @@ -2,7 +2,6 @@ package memory import ( "github.com/TwiN/gatus/v5/core" - "github.com/TwiN/gatus/v5/storage/store/common" "github.com/TwiN/gatus/v5/storage/store/common/paging" ) @@ -51,7 +50,7 @@ func getStartAndEndIndex(numberOfResults int, page, pageSize int) (int, int) { // AddResult adds a Result to EndpointStatus.Results and makes sure that there are // no more than MaximumNumberOfResults results in the Results slice -func AddResult(ss *core.EndpointStatus, result *core.Result) { +func AddResult(ss *core.EndpointStatus, result *core.Result, maximumNumberOfResults int, maximumNumberOfEvents int) { if ss == nil { return } @@ -59,11 +58,11 @@ func AddResult(ss *core.EndpointStatus, result *core.Result) { // Check if there's any change since the last result if ss.Results[len(ss.Results)-1].Success != result.Success { ss.Events = append(ss.Events, core.NewEventFromResult(result)) - if len(ss.Events) > common.MaximumNumberOfEvents { + if len(ss.Events) > maximumNumberOfEvents { // Doing ss.Events[1:] would usually be sufficient, but in the case where for some reason, the slice has // more than one extra element, we can get rid of all of them at once and thus returning the slice to a // length of MaximumNumberOfEvents by using ss.Events[len(ss.Events)-MaximumNumberOfEvents:] instead - ss.Events = ss.Events[len(ss.Events)-common.MaximumNumberOfEvents:] + ss.Events = ss.Events[len(ss.Events)-maximumNumberOfEvents:] } } } else { @@ -71,11 +70,11 @@ func AddResult(ss *core.EndpointStatus, result *core.Result) { ss.Events = append(ss.Events, core.NewEventFromResult(result)) } ss.Results = append(ss.Results, result) - if len(ss.Results) > common.MaximumNumberOfResults { + if len(ss.Results) > maximumNumberOfResults { // Doing ss.Results[1:] would usually be sufficient, but in the case where for some reason, the slice has more // than one extra element, we can get rid of all of them at once and thus returning the slice to a length of // MaximumNumberOfResults by using ss.Results[len(ss.Results)-MaximumNumberOfResults:] instead - ss.Results = ss.Results[len(ss.Results)-common.MaximumNumberOfResults:] + ss.Results = ss.Results[len(ss.Results)-maximumNumberOfResults:] } processUptimeAfterResult(ss.Uptime, result) } diff --git a/storage/store/memory/util_bench_test.go b/storage/store/memory/util_bench_test.go index e832f1493..1e6a9a6ea 100644 --- a/storage/store/memory/util_bench_test.go +++ b/storage/store/memory/util_bench_test.go @@ -1,18 +1,18 @@ package memory import ( + "github.com/TwiN/gatus/v5/storage" "testing" "github.com/TwiN/gatus/v5/core" - "github.com/TwiN/gatus/v5/storage/store/common" "github.com/TwiN/gatus/v5/storage/store/common/paging" ) func BenchmarkShallowCopyEndpointStatus(b *testing.B) { endpoint := &testEndpoint status := core.NewEndpointStatus(endpoint.Group, endpoint.Name) - for i := 0; i < common.MaximumNumberOfResults; i++ { - AddResult(status, &testSuccessfulResult) + for i := 0; i < storage.DefaultMaximumNumberOfResults; i++ { + AddResult(status, &testSuccessfulResult, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) } for n := 0; n < b.N; n++ { ShallowCopyEndpointStatus(status, paging.NewEndpointStatusParams().WithResults(1, 20)) diff --git a/storage/store/memory/util_test.go b/storage/store/memory/util_test.go index 8f88299e2..27ec655c6 100644 --- a/storage/store/memory/util_test.go +++ b/storage/store/memory/util_test.go @@ -5,24 +5,24 @@ import ( "time" "github.com/TwiN/gatus/v5/core" - "github.com/TwiN/gatus/v5/storage/store/common" + "github.com/TwiN/gatus/v5/storage" "github.com/TwiN/gatus/v5/storage/store/common/paging" ) func TestAddResult(t *testing.T) { endpoint := &core.Endpoint{Name: "name", Group: "group"} endpointStatus := core.NewEndpointStatus(endpoint.Group, endpoint.Name) - for i := 0; i < (common.MaximumNumberOfResults+common.MaximumNumberOfEvents)*2; i++ { - AddResult(endpointStatus, &core.Result{Success: i%2 == 0, Timestamp: time.Now()}) + for i := 0; i < (storage.DefaultMaximumNumberOfResults+storage.DefaultMaximumNumberOfEvents)*2; i++ { + AddResult(endpointStatus, &core.Result{Success: i%2 == 0, Timestamp: time.Now()}, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) } - if len(endpointStatus.Results) != common.MaximumNumberOfResults { - t.Errorf("expected endpointStatus.Results to not exceed a length of %d", common.MaximumNumberOfResults) + if len(endpointStatus.Results) != storage.DefaultMaximumNumberOfResults { + t.Errorf("expected endpointStatus.Results to not exceed a length of %d", storage.DefaultMaximumNumberOfResults) } - if len(endpointStatus.Events) != common.MaximumNumberOfEvents { - t.Errorf("expected endpointStatus.Events to not exceed a length of %d", common.MaximumNumberOfEvents) + if len(endpointStatus.Events) != storage.DefaultMaximumNumberOfEvents { + t.Errorf("expected endpointStatus.Events to not exceed a length of %d", storage.DefaultMaximumNumberOfEvents) } // Try to add nil endpointStatus - AddResult(nil, &core.Result{Timestamp: time.Now()}) + AddResult(nil, &core.Result{Timestamp: time.Now()}, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) } func TestShallowCopyEndpointStatus(t *testing.T) { @@ -30,7 +30,7 @@ func TestShallowCopyEndpointStatus(t *testing.T) { endpointStatus := core.NewEndpointStatus(endpoint.Group, endpoint.Name) ts := time.Now().Add(-25 * time.Hour) for i := 0; i < 25; i++ { - AddResult(endpointStatus, &core.Result{Success: i%2 == 0, Timestamp: ts}) + AddResult(endpointStatus, &core.Result{Success: i%2 == 0, Timestamp: ts}, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) ts = ts.Add(time.Hour) } if len(ShallowCopyEndpointStatus(endpointStatus, paging.NewEndpointStatusParams().WithResults(-1, -1)).Results) != 0 { diff --git a/storage/store/sql/sql.go b/storage/store/sql/sql.go index 8f520f99e..3c349d10d 100644 --- a/storage/store/sql/sql.go +++ b/storage/store/sql/sql.go @@ -28,13 +28,15 @@ const ( // for aesthetic purposes, I deemed it wasn't worth the performance impact of yet another one-to-many table. arraySeparator = "|~|" - uptimeCleanUpThreshold = 10 * 24 * time.Hour // Maximum uptime age before triggering a clean up - eventsCleanUpThreshold = common.MaximumNumberOfEvents + 10 // Maximum number of events before triggering a clean up - resultsCleanUpThreshold = common.MaximumNumberOfResults + 10 // Maximum number of results before triggering a clean up + uptimeCleanUpThreshold = 10 * 24 * time.Hour // Maximum uptime age before triggering a clean up uptimeRetention = 7 * 24 * time.Hour cacheTTL = 10 * time.Minute + + eventsAboveMaximumCleanUpThreshold = 10 + + resultsAboveMaximumCleanUpThreshold = 10 ) var ( @@ -56,17 +58,27 @@ type Store struct { // writeThroughCache is a cache used to drastically decrease read latency by pre-emptively // caching writes as they happen. If nil, writes are not cached. writeThroughCache *gocache.Cache + + // maximumNumberOfResults is the maximum number of results that an endpoint can have + maximumNumberOfResults int + // maximumNumberOfEvents is the maximum number of events that an endpoint can have + maximumNumberOfEvents int } // NewStore initializes the database and creates the schema if it doesn't already exist in the path specified -func NewStore(driver, path string, caching bool) (*Store, error) { +func NewStore(driver, path string, caching bool, maximumNumberOfResults int, maximumNumberOfEvents int) (*Store, error) { if len(driver) == 0 { return nil, ErrDatabaseDriverNotSpecified } if len(path) == 0 { return nil, ErrPathNotSpecified } - store := &Store{driver: driver, path: path} + store := &Store{ + driver: driver, + path: path, + maximumNumberOfResults: maximumNumberOfResults, + maximumNumberOfEvents: maximumNumberOfEvents, + } var err error if store.db, err = sql.Open(driver, path); err != nil { return nil, err @@ -294,7 +306,7 @@ func (s *Store) Insert(endpoint *core.Endpoint, result *core.Result) error { // Clean up old events if there's more than twice the maximum number of events // This lets us both keep the table clean without impacting performance too much // (since we're only deleting MaximumNumberOfEvents at a time instead of 1) - if numberOfEvents > eventsCleanUpThreshold { + if numberOfEvents > int64(s.maximumNumberOfEvents+eventsAboveMaximumCleanUpThreshold) { if err = s.deleteOldEndpointEvents(tx, endpointID); err != nil { log.Printf("[sql][Insert] Failed to delete old events for group=%s; endpoint=%s: %s", endpoint.Group, endpoint.Name, err.Error()) } @@ -311,7 +323,7 @@ func (s *Store) Insert(endpoint *core.Endpoint, result *core.Result) error { if err != nil { log.Printf("[sql][Insert] Failed to retrieve total number of results for group=%s; endpoint=%s: %s", endpoint.Group, endpoint.Name, err.Error()) } else { - if numberOfResults > resultsCleanUpThreshold { + if numberOfResults > int64(s.maximumNumberOfResults+resultsAboveMaximumCleanUpThreshold) { if err = s.deleteOldEndpointResults(tx, endpointID); err != nil { log.Printf("[sql][Insert] Failed to delete old results for group=%s; endpoint=%s: %s", endpoint.Group, endpoint.Name, err.Error()) } @@ -811,7 +823,7 @@ func (s *Store) deleteOldEndpointEvents(tx *sql.Tx, endpointID int64) error { ) `, endpointID, - common.MaximumNumberOfEvents, + s.maximumNumberOfEvents, ) return err } @@ -831,7 +843,7 @@ func (s *Store) deleteOldEndpointResults(tx *sql.Tx, endpointID int64) error { ) `, endpointID, - common.MaximumNumberOfResults, + s.maximumNumberOfResults, ) return err } diff --git a/storage/store/sql/sql_test.go b/storage/store/sql/sql_test.go index cfd3c8bdb..5c4fe440d 100644 --- a/storage/store/sql/sql_test.go +++ b/storage/store/sql/sql_test.go @@ -5,7 +5,7 @@ import ( "time" "github.com/TwiN/gatus/v5/core" - "github.com/TwiN/gatus/v5/storage/store/common" + "github.com/TwiN/gatus/v5/storage" "github.com/TwiN/gatus/v5/storage/store/common/paging" ) @@ -81,13 +81,13 @@ var ( ) func TestNewStore(t *testing.T) { - if _, err := NewStore("", "TestNewStore.db", false); err != ErrDatabaseDriverNotSpecified { + if _, err := NewStore("", "TestNewStore.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents); err != ErrDatabaseDriverNotSpecified { t.Error("expected error due to blank driver parameter") } - if _, err := NewStore("sqlite", "", false); err != ErrPathNotSpecified { + if _, err := NewStore("sqlite", "", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents); err != ErrPathNotSpecified { t.Error("expected error due to blank path parameter") } - if store, err := NewStore("sqlite", t.TempDir()+"/TestNewStore.db", false); err != nil { + if store, err := NewStore("sqlite", t.TempDir()+"/TestNewStore.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents); err != nil { t.Error("shouldn't have returned any error, got", err.Error()) } else { _ = store.db.Close() @@ -95,7 +95,7 @@ func TestNewStore(t *testing.T) { } func TestStore_InsertCleansUpOldUptimeEntriesProperly(t *testing.T) { - store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InsertCleansUpOldUptimeEntriesProperly.db", false) + store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InsertCleansUpOldUptimeEntriesProperly.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() now := time.Now().Truncate(time.Hour) now = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) @@ -152,12 +152,15 @@ func TestStore_InsertCleansUpOldUptimeEntriesProperly(t *testing.T) { } func TestStore_InsertCleansUpEventsAndResultsProperly(t *testing.T) { - store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InsertCleansUpEventsAndResultsProperly.db", false) + store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InsertCleansUpEventsAndResultsProperly.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() + resultsCleanUpThreshold := store.maximumNumberOfResults + resultsAboveMaximumCleanUpThreshold + eventsCleanUpThreshold := store.maximumNumberOfEvents + eventsAboveMaximumCleanUpThreshold for i := 0; i < resultsCleanUpThreshold+eventsCleanUpThreshold; i++ { store.Insert(&testEndpoint, &testSuccessfulResult) store.Insert(&testEndpoint, &testUnsuccessfulResult) - ss, _ := store.GetEndpointStatusByKey(testEndpoint.Key(), paging.NewEndpointStatusParams().WithResults(1, common.MaximumNumberOfResults*5).WithEvents(1, common.MaximumNumberOfEvents*5)) + ss, _ := store.GetEndpointStatusByKey(testEndpoint.Key(), paging.NewEndpointStatusParams().WithResults(1, storage.DefaultMaximumNumberOfResults*5).WithEvents(1, storage.DefaultMaximumNumberOfEvents*5)) + if len(ss.Results) > resultsCleanUpThreshold+1 { t.Errorf("number of results shouldn't have exceeded %d, reached %d", resultsCleanUpThreshold, len(ss.Results)) } @@ -170,7 +173,7 @@ func TestStore_InsertCleansUpEventsAndResultsProperly(t *testing.T) { func TestStore_Persistence(t *testing.T) { path := t.TempDir() + "/TestStore_Persistence.db" - store, _ := NewStore("sqlite", path, false) + store, _ := NewStore("sqlite", path, false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) store.Insert(&testEndpoint, &testSuccessfulResult) store.Insert(&testEndpoint, &testUnsuccessfulResult) if uptime, _ := store.GetUptimeByKey(testEndpoint.Key(), time.Now().Add(-time.Hour), time.Now()); uptime != 0.5 { @@ -182,15 +185,15 @@ func TestStore_Persistence(t *testing.T) { if uptime, _ := store.GetUptimeByKey(testEndpoint.Key(), time.Now().Add(-time.Hour*24*7), time.Now()); uptime != 0.5 { t.Errorf("the uptime over the past 7d should've been 0.5, got %f", uptime) } - ssFromOldStore, _ := store.GetEndpointStatus(testEndpoint.Group, testEndpoint.Name, paging.NewEndpointStatusParams().WithResults(1, common.MaximumNumberOfResults).WithEvents(1, common.MaximumNumberOfEvents)) + ssFromOldStore, _ := store.GetEndpointStatus(testEndpoint.Group, testEndpoint.Name, paging.NewEndpointStatusParams().WithResults(1, storage.DefaultMaximumNumberOfResults).WithEvents(1, storage.DefaultMaximumNumberOfEvents)) if ssFromOldStore == nil || ssFromOldStore.Group != "group" || ssFromOldStore.Name != "name" || len(ssFromOldStore.Events) != 3 || len(ssFromOldStore.Results) != 2 { store.Close() t.Fatal("sanity check failed") } store.Close() - store, _ = NewStore("sqlite", path, false) + store, _ = NewStore("sqlite", path, false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() - ssFromNewStore, _ := store.GetEndpointStatus(testEndpoint.Group, testEndpoint.Name, paging.NewEndpointStatusParams().WithResults(1, common.MaximumNumberOfResults).WithEvents(1, common.MaximumNumberOfEvents)) + ssFromNewStore, _ := store.GetEndpointStatus(testEndpoint.Group, testEndpoint.Name, paging.NewEndpointStatusParams().WithResults(1, storage.DefaultMaximumNumberOfResults).WithEvents(1, storage.DefaultMaximumNumberOfEvents)) if ssFromNewStore == nil || ssFromNewStore.Group != "group" || ssFromNewStore.Name != "name" || len(ssFromNewStore.Events) != 3 || len(ssFromNewStore.Results) != 2 { t.Fatal("failed sanity check") } @@ -252,7 +255,7 @@ func TestStore_Persistence(t *testing.T) { } func TestStore_Save(t *testing.T) { - store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_Save.db", false) + store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_Save.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() if store.Save() != nil { t.Error("Save shouldn't do anything for this store") @@ -262,7 +265,7 @@ func TestStore_Save(t *testing.T) { // Note that are much more extensive tests in /storage/store/store_test.go. // This test is simply an extra sanity check func TestStore_SanityCheck(t *testing.T) { - store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_SanityCheck.db", false) + store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_SanityCheck.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() store.Insert(&testEndpoint, &testSuccessfulResult) endpointStatuses, _ := store.GetAllEndpointStatuses(paging.NewEndpointStatusParams()) @@ -306,7 +309,7 @@ func TestStore_SanityCheck(t *testing.T) { // TestStore_InvalidTransaction tests what happens if an invalid transaction is passed as parameter func TestStore_InvalidTransaction(t *testing.T) { - store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InvalidTransaction.db", false) + store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InvalidTransaction.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() tx, _ := store.db.Begin() tx.Commit() @@ -364,7 +367,7 @@ func TestStore_InvalidTransaction(t *testing.T) { } func TestStore_NoRows(t *testing.T) { - store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_NoRows.db", false) + store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_NoRows.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() tx, _ := store.db.Begin() defer tx.Rollback() @@ -378,7 +381,7 @@ func TestStore_NoRows(t *testing.T) { // This tests very unlikely cases where a table is deleted. func TestStore_BrokenSchema(t *testing.T) { - store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_BrokenSchema.db", false) + store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_BrokenSchema.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) defer store.Close() if err := store.Insert(&testEndpoint, &testSuccessfulResult); err != nil { t.Fatal("expected no error, got", err.Error()) diff --git a/storage/store/store.go b/storage/store/store.go index 3e7d83421..f9c37e43f 100644 --- a/storage/store/store.go +++ b/storage/store/store.go @@ -97,20 +97,24 @@ func Initialize(cfg *storage.Config) error { log.Println("[store][Initialize] nil storage config passed as parameter. This should only happen in tests. Defaulting to an empty config.") cfg = &storage.Config{} } + if cfg.MaximumNumberOfResults == 0 && cfg.MaximumNumberOfEvents == 0 { + cfg.MaximumNumberOfResults = storage.DefaultMaximumNumberOfResults + cfg.MaximumNumberOfEvents = storage.DefaultMaximumNumberOfEvents + } if len(cfg.Path) == 0 && cfg.Type != storage.TypePostgres { log.Printf("[store][Initialize] Creating storage provider of type=%s", cfg.Type) } ctx, cancelFunc = context.WithCancel(context.Background()) switch cfg.Type { case storage.TypeSQLite, storage.TypePostgres: - store, err = sql.NewStore(string(cfg.Type), cfg.Path, cfg.Caching) + store, err = sql.NewStore(string(cfg.Type), cfg.Path, cfg.Caching, cfg.MaximumNumberOfResults, cfg.MaximumNumberOfEvents) if err != nil { return err } case storage.TypeMemory: fallthrough default: - store, _ = memory.NewStore() + store, _ = memory.NewStore(cfg.MaximumNumberOfResults, cfg.MaximumNumberOfEvents) } return nil } diff --git a/storage/store/store_bench_test.go b/storage/store/store_bench_test.go index 67a8e06c4..9583995ca 100644 --- a/storage/store/store_bench_test.go +++ b/storage/store/store_bench_test.go @@ -1,6 +1,7 @@ package store import ( + "github.com/TwiN/gatus/v5/storage" "strconv" "testing" "time" @@ -12,11 +13,11 @@ import ( ) func BenchmarkStore_GetAllEndpointStatuses(b *testing.B) { - memoryStore, err := memory.NewStore() + memoryStore, err := memory.NewStore(storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { b.Fatal("failed to create store:", err.Error()) } - sqliteStore, err := sql.NewStore("sqlite", b.TempDir()+"/BenchmarkStore_GetAllEndpointStatuses.db", false) + sqliteStore, err := sql.NewStore("sqlite", b.TempDir()+"/BenchmarkStore_GetAllEndpointStatuses.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { b.Fatal("failed to create store:", err.Error()) } @@ -81,11 +82,11 @@ func BenchmarkStore_GetAllEndpointStatuses(b *testing.B) { } func BenchmarkStore_Insert(b *testing.B) { - memoryStore, err := memory.NewStore() + memoryStore, err := memory.NewStore(storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { b.Fatal("failed to create store:", err.Error()) } - sqliteStore, err := sql.NewStore("sqlite", b.TempDir()+"/BenchmarkStore_Insert.db", false) + sqliteStore, err := sql.NewStore("sqlite", b.TempDir()+"/BenchmarkStore_Insert.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { b.Fatal("failed to create store:", err.Error()) } @@ -153,11 +154,11 @@ func BenchmarkStore_Insert(b *testing.B) { } func BenchmarkStore_GetEndpointStatusByKey(b *testing.B) { - memoryStore, err := memory.NewStore() + memoryStore, err := memory.NewStore(storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { b.Fatal("failed to create store:", err.Error()) } - sqliteStore, err := sql.NewStore("sqlite", b.TempDir()+"/BenchmarkStore_GetEndpointStatusByKey.db", false) + sqliteStore, err := sql.NewStore("sqlite", b.TempDir()+"/BenchmarkStore_GetEndpointStatusByKey.db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { b.Fatal("failed to create store:", err.Error()) } diff --git a/storage/store/store_test.go b/storage/store/store_test.go index eacf18777..f3e1918fe 100644 --- a/storage/store/store_test.go +++ b/storage/store/store_test.go @@ -90,15 +90,15 @@ type Scenario struct { } func initStoresAndBaseScenarios(t *testing.T, testName string) []*Scenario { - memoryStore, err := memory.NewStore() + memoryStore, err := memory.NewStore(storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { t.Fatal("failed to create store:", err.Error()) } - sqliteStore, err := sql.NewStore("sqlite", t.TempDir()+"/"+testName+".db", false) + sqliteStore, err := sql.NewStore("sqlite", t.TempDir()+"/"+testName+".db", false, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { t.Fatal("failed to create store:", err.Error()) } - sqliteStoreWithCaching, err := sql.NewStore("sqlite", t.TempDir()+"/"+testName+"-with-caching.db", true) + sqliteStoreWithCaching, err := sql.NewStore("sqlite", t.TempDir()+"/"+testName+"-with-caching.db", true, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) if err != nil { t.Fatal("failed to create store:", err.Error()) } @@ -135,7 +135,7 @@ func TestStore_GetEndpointStatusByKey(t *testing.T) { t.Run(scenario.Name, func(t *testing.T) { scenario.Store.Insert(&testEndpoint, &firstResult) scenario.Store.Insert(&testEndpoint, &secondResult) - endpointStatus, err := scenario.Store.GetEndpointStatusByKey(testEndpoint.Key(), paging.NewEndpointStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults)) + endpointStatus, err := scenario.Store.GetEndpointStatusByKey(testEndpoint.Key(), paging.NewEndpointStatusParams().WithEvents(1, storage.DefaultMaximumNumberOfEvents).WithResults(1, storage.DefaultMaximumNumberOfResults)) if err != nil { t.Fatal("shouldn't have returned an error, got", err.Error()) } @@ -165,21 +165,21 @@ func TestStore_GetEndpointStatusForMissingStatusReturnsNil(t *testing.T) { for _, scenario := range scenarios { t.Run(scenario.Name, func(t *testing.T) { scenario.Store.Insert(&testEndpoint, &testSuccessfulResult) - endpointStatus, err := scenario.Store.GetEndpointStatus("nonexistantgroup", "nonexistantname", paging.NewEndpointStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults)) + endpointStatus, err := scenario.Store.GetEndpointStatus("nonexistantgroup", "nonexistantname", paging.NewEndpointStatusParams().WithEvents(1, storage.DefaultMaximumNumberOfEvents).WithResults(1, storage.DefaultMaximumNumberOfResults)) if err != common.ErrEndpointNotFound { t.Error("should've returned ErrEndpointNotFound, got", err) } if endpointStatus != nil { t.Errorf("Returned endpoint status for group '%s' and name '%s' not nil after inserting the endpoint into the store", testEndpoint.Group, testEndpoint.Name) } - endpointStatus, err = scenario.Store.GetEndpointStatus(testEndpoint.Group, "nonexistantname", paging.NewEndpointStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults)) + endpointStatus, err = scenario.Store.GetEndpointStatus(testEndpoint.Group, "nonexistantname", paging.NewEndpointStatusParams().WithEvents(1, storage.DefaultMaximumNumberOfEvents).WithResults(1, storage.DefaultMaximumNumberOfResults)) if err != common.ErrEndpointNotFound { t.Error("should've returned ErrEndpointNotFound, got", err) } if endpointStatus != nil { t.Errorf("Returned endpoint status for group '%s' and name '%s' not nil after inserting the endpoint into the store", testEndpoint.Group, "nonexistantname") } - endpointStatus, err = scenario.Store.GetEndpointStatus("nonexistantgroup", testEndpoint.Name, paging.NewEndpointStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults)) + endpointStatus, err = scenario.Store.GetEndpointStatus("nonexistantgroup", testEndpoint.Name, paging.NewEndpointStatusParams().WithEvents(1, storage.DefaultMaximumNumberOfEvents).WithResults(1, storage.DefaultMaximumNumberOfResults)) if err != common.ErrEndpointNotFound { t.Error("should've returned ErrEndpointNotFound, got", err) } @@ -459,7 +459,7 @@ func TestStore_Insert(t *testing.T) { t.Run(scenario.Name, func(t *testing.T) { scenario.Store.Insert(&testEndpoint, &testSuccessfulResult) scenario.Store.Insert(&testEndpoint, &testUnsuccessfulResult) - ss, err := scenario.Store.GetEndpointStatusByKey(testEndpoint.Key(), paging.NewEndpointStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults)) + ss, err := scenario.Store.GetEndpointStatusByKey(testEndpoint.Key(), paging.NewEndpointStatusParams().WithEvents(1, storage.DefaultMaximumNumberOfEvents).WithResults(1, storage.DefaultMaximumNumberOfResults)) if err != nil { t.Error("shouldn't have returned an error, got", err) } diff --git a/web/app/public/index.html b/web/app/public/index.html index 5fbd4cd1f..0d0e97055 100644 --- a/web/app/public/index.html +++ b/web/app/public/index.html @@ -3,7 +3,7 @@ {{ .Title }} diff --git a/web/app/src/components/Pagination.vue b/web/app/src/components/Pagination.vue index 3f909e1ff..99d6d4e58 100644 --- a/web/app/src/components/Pagination.vue +++ b/web/app/src/components/Pagination.vue @@ -1,7 +1,7 @@