Major fixes and improvements
This commit is contained in:
parent
fed32d3909
commit
d3a81a2d57
@ -176,7 +176,9 @@ func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) {
|
|||||||
|
|
||||||
func validateStorageConfig(config *Config) error {
|
func validateStorageConfig(config *Config) error {
|
||||||
if config.Storage == nil {
|
if config.Storage == nil {
|
||||||
config.Storage = &storage.Config{}
|
config.Storage = &storage.Config{
|
||||||
|
Type: storage.TypeInMemory,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err := storage.Initialize(config.Storage)
|
err := storage.Initialize(config.Storage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1028,6 +1028,49 @@ services:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseAndValidateConfigBytesWithInvalidServiceName(t *testing.T) {
|
||||||
|
_, err := parseAndValidateConfigBytes([]byte(`
|
||||||
|
services:
|
||||||
|
- name: ""
|
||||||
|
url: https://twinnation.org/health
|
||||||
|
conditions:
|
||||||
|
- "[STATUS] == 200"
|
||||||
|
`))
|
||||||
|
if err != core.ErrServiceWithNoName {
|
||||||
|
t.Error("should've returned an error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseAndValidateConfigBytesWithInvalidStorageConfig(t *testing.T) {
|
||||||
|
_, err := parseAndValidateConfigBytes([]byte(`
|
||||||
|
storage:
|
||||||
|
type: sqlite
|
||||||
|
services:
|
||||||
|
- name: example
|
||||||
|
url: https://example.org
|
||||||
|
conditions:
|
||||||
|
- "[STATUS] == 200"
|
||||||
|
`))
|
||||||
|
if err == nil {
|
||||||
|
t.Error("should've returned an error, because a file must be specified for a storage of type sqlite")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseAndValidateConfigBytesWithInvalidYAML(t *testing.T) {
|
||||||
|
_, err := parseAndValidateConfigBytes([]byte(`
|
||||||
|
storage:
|
||||||
|
invalid yaml
|
||||||
|
services:
|
||||||
|
- name: example
|
||||||
|
url: https://example.org
|
||||||
|
conditions:
|
||||||
|
- "[STATUS] == 200"
|
||||||
|
`))
|
||||||
|
if err == nil {
|
||||||
|
t.Error("should've returned an error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseAndValidateConfigBytesWithInvalidSecurityConfig(t *testing.T) {
|
func TestParseAndValidateConfigBytesWithInvalidSecurityConfig(t *testing.T) {
|
||||||
_, err := parseAndValidateConfigBytes([]byte(`
|
_, err := parseAndValidateConfigBytes([]byte(`
|
||||||
security:
|
security:
|
||||||
@ -1041,7 +1084,7 @@ services:
|
|||||||
- "[STATUS] == 200"
|
- "[STATUS] == 200"
|
||||||
`))
|
`))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Function should've returned an error")
|
t.Error("should've returned an error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1173,7 +1216,7 @@ kubernetes:
|
|||||||
target-path: "/health"
|
target-path: "/health"
|
||||||
`))
|
`))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Function should've returned an error because providing a service-template is mandatory")
|
t.Error("should've returned an error because providing a service-template is mandatory")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1192,7 +1235,7 @@ kubernetes:
|
|||||||
target-path: "/health"
|
target-path: "/health"
|
||||||
`))
|
`))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Function should've returned an error because testing with ClusterModeIn isn't supported")
|
t.Error("should've returned an error because testing with ClusterModeIn isn't supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,11 +39,11 @@ var (
|
|||||||
server *http.Server
|
server *http.Server
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
//func init() { XXX: Don't think there's any value in using the janitor since the cache max size is this small
|
||||||
if err := cache.StartJanitor(); err != nil {
|
// if err := cache.StartJanitor(); err != nil {
|
||||||
log.Fatal("[controller][init] Failed to start cache janitor:", err.Error())
|
// log.Fatal("[controller][init] Failed to start cache janitor:", err.Error())
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Handle creates the router and starts the server
|
// Handle creates the router and starts the server
|
||||||
func Handle(securityConfig *security.Config, webConfig *config.WebConfig, enableMetrics bool) {
|
func Handle(securityConfig *security.Config, webConfig *config.WebConfig, enableMetrics bool) {
|
||||||
|
1
main.go
1
main.go
@ -42,6 +42,7 @@ func start(cfg *config.Config) {
|
|||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
watchdog.Shutdown()
|
watchdog.Shutdown()
|
||||||
|
storage.Get().Close()
|
||||||
controller.Shutdown()
|
controller.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
// Config is the configuration for alerting providers
|
// Config is the configuration for storage
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// File is the path of the file to use for persistence
|
// File is the path of the file to use for persistence
|
||||||
// If blank, persistence is disabled.
|
// If blank, persistence is disabled
|
||||||
File string `yaml:"file"`
|
File string `yaml:"file"`
|
||||||
|
|
||||||
|
// Type of store
|
||||||
|
// If blank, uses the default in-memory store
|
||||||
|
Type Type `yaml:"type"`
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/TwinProduction/gatus/storage/store"
|
"github.com/TwinProduction/gatus/storage/store"
|
||||||
|
"github.com/TwinProduction/gatus/storage/store/database"
|
||||||
"github.com/TwinProduction/gatus/storage/store/memory"
|
"github.com/TwinProduction/gatus/storage/store/memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,36 +39,52 @@ func Initialize(cfg *Config) error {
|
|||||||
initialized = true
|
initialized = true
|
||||||
var err error
|
var err error
|
||||||
if cancelFunc != nil {
|
if cancelFunc != nil {
|
||||||
// Stop the active autoSave task
|
// Stop the active autoSaveStore task, if there's already one
|
||||||
cancelFunc()
|
cancelFunc()
|
||||||
}
|
}
|
||||||
if cfg == nil || len(cfg.File) == 0 {
|
if cfg == nil {
|
||||||
log.Println("[storage][Initialize] Creating storage provider")
|
cfg = &Config{}
|
||||||
provider, _ = memory.NewStore("")
|
}
|
||||||
|
if len(cfg.File) == 0 {
|
||||||
|
log.Printf("[storage][Initialize] Creating storage provider with type=%s", cfg.Type)
|
||||||
} else {
|
} else {
|
||||||
ctx, cancelFunc = context.WithCancel(context.Background())
|
log.Printf("[storage][Initialize] Creating storage provider with type=%s and file=%s", cfg.Type, cfg.File)
|
||||||
log.Printf("[storage][Initialize] Creating storage provider with file=%s", cfg.File)
|
}
|
||||||
provider, err = memory.NewStore(cfg.File)
|
ctx, cancelFunc = context.WithCancel(context.Background())
|
||||||
|
switch cfg.Type {
|
||||||
|
case TypeSQLite:
|
||||||
|
provider, err = database.NewStore(string(cfg.Type), cfg.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
go autoSave(7*time.Minute, ctx)
|
case TypeInMemory:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
if len(cfg.File) > 0 {
|
||||||
|
provider, err = memory.NewStore(cfg.File)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go autoSaveStore(ctx, provider, 7*time.Minute)
|
||||||
|
} else {
|
||||||
|
provider, _ = memory.NewStore("")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// autoSave automatically calls the SaveFunc function of the provider at every interval
|
// autoSaveStore automatically calls the Save function of the provider at every interval
|
||||||
func autoSave(interval time.Duration, ctx context.Context) {
|
func autoSaveStore(ctx context.Context, provider store.Store, interval time.Duration) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.Printf("[storage][autoSave] Stopping active job")
|
log.Printf("[storage][autoSaveStore] Stopping active job")
|
||||||
return
|
return
|
||||||
case <-time.After(interval):
|
case <-time.After(interval):
|
||||||
log.Printf("[storage][autoSave] Saving")
|
log.Printf("[storage][autoSaveStore] Saving")
|
||||||
err := provider.Save()
|
err := provider.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[storage][autoSave] Save failed:", err.Error())
|
log.Println("[storage][autoSaveStore] Save failed:", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,89 @@
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/TwinProduction/gatus/storage/store/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInitialize(t *testing.T) {
|
func TestInitialize(t *testing.T) {
|
||||||
file := t.TempDir() + "/test.db"
|
type Scenario struct {
|
||||||
err := Initialize(&Config{File: file})
|
Name string
|
||||||
if err != nil {
|
Cfg *Config
|
||||||
t.Fatal("shouldn't have returned an error")
|
ExpectedErr error
|
||||||
}
|
}
|
||||||
if cancelFunc == nil {
|
scenarios := []Scenario{
|
||||||
t.Error("cancelFunc shouldn't have been nil")
|
{
|
||||||
|
Name: "nil",
|
||||||
|
Cfg: nil,
|
||||||
|
ExpectedErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "blank",
|
||||||
|
Cfg: &Config{},
|
||||||
|
ExpectedErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "inmemory-no-file",
|
||||||
|
Cfg: &Config{Type: TypeInMemory},
|
||||||
|
ExpectedErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "inmemory-with-file",
|
||||||
|
Cfg: &Config{Type: TypeInMemory, File: t.TempDir() + "/TestInitialize_inmemory-with-file.db"},
|
||||||
|
ExpectedErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "sqlite-no-file",
|
||||||
|
Cfg: &Config{Type: TypeSQLite},
|
||||||
|
ExpectedErr: database.ErrFilePathNotSpecified,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "sqlite-with-file",
|
||||||
|
Cfg: &Config{Type: TypeSQLite, File: t.TempDir() + "/TestInitialize_sqlite-with-file.db"},
|
||||||
|
ExpectedErr: nil,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
if ctx == nil {
|
for _, scenario := range scenarios {
|
||||||
t.Error("ctx shouldn't have been nil")
|
t.Run(scenario.Name, func(t *testing.T) {
|
||||||
|
err := Initialize(scenario.Cfg)
|
||||||
|
if err != scenario.ExpectedErr {
|
||||||
|
t.Errorf("expected %v, got %v", scenario.ExpectedErr, err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cancelFunc == nil {
|
||||||
|
t.Error("cancelFunc shouldn't have been nil")
|
||||||
|
}
|
||||||
|
if ctx == nil {
|
||||||
|
t.Error("ctx shouldn't have been nil")
|
||||||
|
}
|
||||||
|
if provider == nil {
|
||||||
|
fmt.Println("wtf?")
|
||||||
|
}
|
||||||
|
provider.Close()
|
||||||
|
// Try to initialize it again
|
||||||
|
err = Initialize(scenario.Cfg)
|
||||||
|
if err != scenario.ExpectedErr {
|
||||||
|
t.Errorf("expected %v, got %v", scenario.ExpectedErr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
provider.Close()
|
||||||
|
provider = nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// Try to initialize it again
|
|
||||||
err = Initialize(&Config{File: file})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("shouldn't have returned an error")
|
|
||||||
}
|
|
||||||
cancelFunc()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoSave(t *testing.T) {
|
func TestAutoSave(t *testing.T) {
|
||||||
file := t.TempDir() + "/test.db"
|
file := t.TempDir() + "/TestAutoSave.db"
|
||||||
if err := Initialize(&Config{File: file}); err != nil {
|
if err := Initialize(&Config{File: file}); err != nil {
|
||||||
t.Fatal("shouldn't have returned an error")
|
t.Fatal("shouldn't have returned an error")
|
||||||
}
|
}
|
||||||
go autoSave(3*time.Millisecond, ctx)
|
go autoSaveStore(ctx, provider, 3*time.Millisecond)
|
||||||
time.Sleep(15 * time.Millisecond)
|
time.Sleep(15 * time.Millisecond)
|
||||||
cancelFunc()
|
cancelFunc()
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package database
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -306,7 +307,18 @@ func (s *Store) Insert(service *core.Service, result *core.Result) {
|
|||||||
|
|
||||||
// DeleteAllServiceStatusesNotInKeys removes all rows owned by a service whose key is not within the keys provided
|
// DeleteAllServiceStatusesNotInKeys removes all rows owned by a service whose key is not within the keys provided
|
||||||
func (s *Store) DeleteAllServiceStatusesNotInKeys(keys []string) int {
|
func (s *Store) DeleteAllServiceStatusesNotInKeys(keys []string) int {
|
||||||
panic("implement me")
|
if len(keys) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
args := make([]interface{}, 0, len(keys))
|
||||||
|
for i := range keys {
|
||||||
|
args = append(args, keys[i])
|
||||||
|
}
|
||||||
|
_, err := s.db.Exec(fmt.Sprintf("DELETE FROM service WHERE service_key NOT IN (%s)", strings.Trim(strings.Repeat("?,", len(keys)), ",")), args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("err: %v", err)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear deletes everything from the store
|
// Clear deletes everything from the store
|
||||||
@ -439,7 +451,7 @@ func (s *Store) getAllServiceKeys(tx *sql.Tx) (keys []string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) getServiceStatusByKey(tx *sql.Tx, key string, parameters *paging.ServiceStatusParams) (*core.ServiceStatus, error) {
|
func (s *Store) getServiceStatusByKey(tx *sql.Tx, key string, parameters *paging.ServiceStatusParams) (*core.ServiceStatus, error) {
|
||||||
serviceID, serviceName, serviceGroup, err := s.getServiceIDGroupAndNameByKey(tx, key)
|
serviceID, serviceGroup, serviceName, err := s.getServiceIDGroupAndNameByKey(tx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -484,7 +496,7 @@ func (s *Store) getEventsByServiceID(tx *sql.Tx, serviceID int64, page, pageSize
|
|||||||
SELECT event_type, event_timestamp
|
SELECT event_type, event_timestamp
|
||||||
FROM service_event
|
FROM service_event
|
||||||
WHERE service_id = $1
|
WHERE service_id = $1
|
||||||
ORDER BY service_event_id DESC
|
ORDER BY service_event_id ASC
|
||||||
LIMIT $2 OFFSET $3
|
LIMIT $2 OFFSET $3
|
||||||
`,
|
`,
|
||||||
serviceID,
|
serviceID,
|
||||||
@ -509,7 +521,7 @@ func (s *Store) getResultsByServiceID(tx *sql.Tx, serviceID int64, page, pageSiz
|
|||||||
SELECT service_result_id, success, errors, connected, status, dns_rcode, certificate_expiration, hostname, ip, duration, timestamp
|
SELECT service_result_id, success, errors, connected, status, dns_rcode, certificate_expiration, hostname, ip, duration, timestamp
|
||||||
FROM service_result
|
FROM service_result
|
||||||
WHERE service_id = $1
|
WHERE service_id = $1
|
||||||
ORDER BY timestamp DESC
|
ORDER BY timestamp ASC
|
||||||
LIMIT $2 OFFSET $3
|
LIMIT $2 OFFSET $3
|
||||||
`,
|
`,
|
||||||
serviceID,
|
serviceID,
|
||||||
@ -525,7 +537,9 @@ func (s *Store) getResultsByServiceID(tx *sql.Tx, serviceID int64, page, pageSiz
|
|||||||
var id int64
|
var id int64
|
||||||
var joinedErrors string
|
var joinedErrors string
|
||||||
_ = rows.Scan(&id, &result.Success, &joinedErrors, &result.Connected, &result.HTTPStatus, &result.DNSRCode, &result.CertificateExpiration, &result.Hostname, &result.IP, &result.Duration, &result.Timestamp)
|
_ = rows.Scan(&id, &result.Success, &joinedErrors, &result.Connected, &result.HTTPStatus, &result.DNSRCode, &result.CertificateExpiration, &result.Hostname, &result.IP, &result.Duration, &result.Timestamp)
|
||||||
result.Errors = strings.Split(joinedErrors, arraySeparator)
|
if len(joinedErrors) != 0 {
|
||||||
|
result.Errors = strings.Split(joinedErrors, arraySeparator)
|
||||||
|
}
|
||||||
results = append(results, result)
|
results = append(results, result)
|
||||||
idResultMap[id] = result
|
idResultMap[id] = result
|
||||||
}
|
}
|
||||||
@ -534,7 +548,7 @@ func (s *Store) getResultsByServiceID(tx *sql.Tx, serviceID int64, page, pageSiz
|
|||||||
for serviceResultID, result := range idResultMap {
|
for serviceResultID, result := range idResultMap {
|
||||||
rows, err = tx.Query(
|
rows, err = tx.Query(
|
||||||
`
|
`
|
||||||
SELECT service_result_id, condition, success
|
SELECT condition, success
|
||||||
FROM service_result_condition
|
FROM service_result_condition
|
||||||
WHERE service_result_id = $1
|
WHERE service_result_id = $1
|
||||||
`,
|
`,
|
||||||
@ -545,7 +559,9 @@ func (s *Store) getResultsByServiceID(tx *sql.Tx, serviceID int64, page, pageSiz
|
|||||||
}
|
}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
conditionResult := &core.ConditionResult{}
|
conditionResult := &core.ConditionResult{}
|
||||||
_ = rows.Scan(&conditionResult.Condition, &conditionResult.Success)
|
if err = rows.Scan(&conditionResult.Condition, &conditionResult.Success); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
result.ConditionResults = append(result.ConditionResults, conditionResult)
|
result.ConditionResults = append(result.ConditionResults, conditionResult)
|
||||||
}
|
}
|
||||||
_ = rows.Close()
|
_ = rows.Close()
|
||||||
|
@ -97,7 +97,7 @@ func TestNewStore(t *testing.T) {
|
|||||||
|
|
||||||
func TestStore_Insert(t *testing.T) {
|
func TestStore_Insert(t *testing.T) {
|
||||||
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_Insert.db")
|
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_Insert.db")
|
||||||
defer store.db.Close()
|
defer store.Close()
|
||||||
store.Insert(&testService, &testSuccessfulResult)
|
store.Insert(&testService, &testSuccessfulResult)
|
||||||
store.Insert(&testService, &testUnsuccessfulResult)
|
store.Insert(&testService, &testUnsuccessfulResult)
|
||||||
|
|
||||||
@ -147,102 +147,9 @@ func TestStore_Insert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStore_GetServiceStatus(t *testing.T) {
|
|
||||||
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_GetServiceStatus.db")
|
|
||||||
defer store.db.Close()
|
|
||||||
store.Insert(&testService, &testSuccessfulResult)
|
|
||||||
store.Insert(&testService, &testUnsuccessfulResult)
|
|
||||||
|
|
||||||
serviceStatus := store.GetServiceStatus(testService.Group, testService.Name, paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
|
||||||
if serviceStatus == nil {
|
|
||||||
t.Fatalf("serviceStatus shouldn't have been nil")
|
|
||||||
}
|
|
||||||
if serviceStatus.Uptime == nil {
|
|
||||||
t.Fatalf("serviceStatus.Uptime shouldn't have been nil")
|
|
||||||
}
|
|
||||||
if serviceStatus.Uptime.LastHour != 0.5 {
|
|
||||||
t.Errorf("serviceStatus.Uptime.LastHour should've been 0.5")
|
|
||||||
}
|
|
||||||
if serviceStatus.Uptime.LastTwentyFourHours != 0.5 {
|
|
||||||
t.Errorf("serviceStatus.Uptime.LastTwentyFourHours should've been 0.5")
|
|
||||||
}
|
|
||||||
if serviceStatus.Uptime.LastSevenDays != 0.5 {
|
|
||||||
t.Errorf("serviceStatus.Uptime.LastSevenDays should've been 0.5")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStore_GetServiceStatusForMissingStatusReturnsNil(t *testing.T) {
|
|
||||||
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_GetServiceStatusForMissingStatusReturnsNil.db")
|
|
||||||
defer store.db.Close()
|
|
||||||
store.Insert(&testService, &testSuccessfulResult)
|
|
||||||
|
|
||||||
serviceStatus := store.GetServiceStatus("nonexistantgroup", "nonexistantname", paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
|
||||||
if serviceStatus != nil {
|
|
||||||
t.Errorf("Returned service status for group '%s' and name '%s' not nil after inserting the service into the store", testService.Group, testService.Name)
|
|
||||||
}
|
|
||||||
serviceStatus = store.GetServiceStatus(testService.Group, "nonexistantname", paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
|
||||||
if serviceStatus != nil {
|
|
||||||
t.Errorf("Returned service status for group '%s' and name '%s' not nil after inserting the service into the store", testService.Group, "nonexistantname")
|
|
||||||
}
|
|
||||||
serviceStatus = store.GetServiceStatus("nonexistantgroup", testService.Name, paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
|
||||||
if serviceStatus != nil {
|
|
||||||
t.Errorf("Returned service status for group '%s' and name '%s' not nil after inserting the service into the store", "nonexistantgroup", testService.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStore_GetServiceStatusByKey(t *testing.T) {
|
|
||||||
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_GetServiceStatusByKey.db")
|
|
||||||
defer store.db.Close()
|
|
||||||
store.Insert(&testService, &testSuccessfulResult)
|
|
||||||
store.Insert(&testService, &testUnsuccessfulResult)
|
|
||||||
|
|
||||||
serviceStatus := store.GetServiceStatusByKey(testService.Key(), paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
|
||||||
if serviceStatus == nil {
|
|
||||||
t.Fatalf("serviceStatus shouldn't have been nil")
|
|
||||||
}
|
|
||||||
if serviceStatus.Uptime == nil {
|
|
||||||
t.Fatalf("serviceStatus.Uptime shouldn't have been nil")
|
|
||||||
}
|
|
||||||
if serviceStatus.Uptime.LastHour != 0.5 {
|
|
||||||
t.Errorf("serviceStatus.Uptime.LastHour should've been 0.5")
|
|
||||||
}
|
|
||||||
if serviceStatus.Uptime.LastTwentyFourHours != 0.5 {
|
|
||||||
t.Errorf("serviceStatus.Uptime.LastTwentyFourHours should've been 0.5")
|
|
||||||
}
|
|
||||||
if serviceStatus.Uptime.LastSevenDays != 0.5 {
|
|
||||||
t.Errorf("serviceStatus.Uptime.LastSevenDays should've been 0.5")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStore_GetAllServiceStatuses(t *testing.T) {
|
|
||||||
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_GetAllServiceStatuses.db")
|
|
||||||
defer store.db.Close()
|
|
||||||
firstResult := &testSuccessfulResult
|
|
||||||
secondResult := &testUnsuccessfulResult
|
|
||||||
store.Insert(&testService, firstResult)
|
|
||||||
store.Insert(&testService, secondResult)
|
|
||||||
// Can't be bothered dealing with timezone issues on the worker that runs the automated tests
|
|
||||||
firstResult.Timestamp = time.Time{}
|
|
||||||
secondResult.Timestamp = time.Time{}
|
|
||||||
serviceStatuses := store.GetAllServiceStatuses(paging.NewServiceStatusParams().WithResults(1, 20))
|
|
||||||
if len(serviceStatuses) != 1 {
|
|
||||||
t.Fatal("expected 1 service status")
|
|
||||||
}
|
|
||||||
actual, exists := serviceStatuses[testService.Key()]
|
|
||||||
if !exists {
|
|
||||||
t.Fatal("expected service status to exist")
|
|
||||||
}
|
|
||||||
if len(actual.Results) != 2 {
|
|
||||||
t.Error("expected 2 results, got", len(actual.Results))
|
|
||||||
}
|
|
||||||
if len(actual.Events) != 0 {
|
|
||||||
t.Error("expected 0 events, got", len(actual.Events))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStore_InsertCleansUpOldUptimeEntriesProperly(t *testing.T) {
|
func TestStore_InsertCleansUpOldUptimeEntriesProperly(t *testing.T) {
|
||||||
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InsertCleansUpOldUptimeEntriesProperly.db")
|
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InsertCleansUpOldUptimeEntriesProperly.db")
|
||||||
defer store.db.Close()
|
defer store.Close()
|
||||||
now := time.Now().Round(time.Minute)
|
now := time.Now().Round(time.Minute)
|
||||||
now = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
now = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||||
|
|
||||||
@ -297,9 +204,9 @@ func TestStore_InsertCleansUpOldUptimeEntriesProperly(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStore_InsertCleansUpProperly(t *testing.T) {
|
func TestStore_InsertCleansUpEventsAndResultsProperly(t *testing.T) {
|
||||||
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_deleteOldServiceResults.db")
|
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_InsertCleansUpEventsAndResultsProperly.db")
|
||||||
defer store.db.Close()
|
defer store.Close()
|
||||||
for i := 0; i < resultsCleanUpThreshold+eventsCleanUpThreshold; i++ {
|
for i := 0; i < resultsCleanUpThreshold+eventsCleanUpThreshold; i++ {
|
||||||
store.Insert(&testService, &testSuccessfulResult)
|
store.Insert(&testService, &testSuccessfulResult)
|
||||||
store.Insert(&testService, &testUnsuccessfulResult)
|
store.Insert(&testService, &testUnsuccessfulResult)
|
||||||
@ -311,4 +218,137 @@ func TestStore_InsertCleansUpProperly(t *testing.T) {
|
|||||||
t.Errorf("number of events shouldn't have exceeded %d, reached %d", eventsCleanUpThreshold, len(ss.Events))
|
t.Errorf("number of events shouldn't have exceeded %d, reached %d", eventsCleanUpThreshold, len(ss.Events))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
store.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStore_GetServiceStatus(t *testing.T) {
|
||||||
|
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_GetServiceStatus.db")
|
||||||
|
defer store.Close()
|
||||||
|
firstResult := testSuccessfulResult
|
||||||
|
firstResult.Timestamp = timestamp.Add(-time.Minute)
|
||||||
|
secondResult := testUnsuccessfulResult
|
||||||
|
secondResult.Timestamp = timestamp
|
||||||
|
store.Insert(&testService, &firstResult)
|
||||||
|
store.Insert(&testService, &secondResult)
|
||||||
|
|
||||||
|
serviceStatus := store.GetServiceStatus(testService.Group, testService.Name, paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
||||||
|
if serviceStatus == nil {
|
||||||
|
t.Fatalf("serviceStatus shouldn't have been nil")
|
||||||
|
}
|
||||||
|
if serviceStatus.Uptime == nil {
|
||||||
|
t.Fatalf("serviceStatus.Uptime shouldn't have been nil")
|
||||||
|
}
|
||||||
|
if len(serviceStatus.Results) != 2 {
|
||||||
|
t.Fatalf("serviceStatus.Results should've had 2 entries")
|
||||||
|
}
|
||||||
|
if serviceStatus.Results[0].Timestamp.After(serviceStatus.Results[1].Timestamp) {
|
||||||
|
t.Fatalf("The result at index 0 should've been older than the result at index 1")
|
||||||
|
}
|
||||||
|
if serviceStatus.Uptime.LastHour != 0.5 {
|
||||||
|
t.Errorf("serviceStatus.Uptime.LastHour should've been 0.5")
|
||||||
|
}
|
||||||
|
if serviceStatus.Uptime.LastTwentyFourHours != 0.5 {
|
||||||
|
t.Errorf("serviceStatus.Uptime.LastTwentyFourHours should've been 0.5")
|
||||||
|
}
|
||||||
|
if serviceStatus.Uptime.LastSevenDays != 0.5 {
|
||||||
|
t.Errorf("serviceStatus.Uptime.LastSevenDays should've been 0.5")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStore_GetServiceStatusForMissingStatusReturnsNil(t *testing.T) {
|
||||||
|
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_GetServiceStatusForMissingStatusReturnsNil.db")
|
||||||
|
defer store.Close()
|
||||||
|
store.Insert(&testService, &testSuccessfulResult)
|
||||||
|
|
||||||
|
serviceStatus := store.GetServiceStatus("nonexistantgroup", "nonexistantname", paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
||||||
|
if serviceStatus != nil {
|
||||||
|
t.Errorf("Returned service status for group '%s' and name '%s' not nil after inserting the service into the store", testService.Group, testService.Name)
|
||||||
|
}
|
||||||
|
serviceStatus = store.GetServiceStatus(testService.Group, "nonexistantname", paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
||||||
|
if serviceStatus != nil {
|
||||||
|
t.Errorf("Returned service status for group '%s' and name '%s' not nil after inserting the service into the store", testService.Group, "nonexistantname")
|
||||||
|
}
|
||||||
|
serviceStatus = store.GetServiceStatus("nonexistantgroup", testService.Name, paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
||||||
|
if serviceStatus != nil {
|
||||||
|
t.Errorf("Returned service status for group '%s' and name '%s' not nil after inserting the service into the store", "nonexistantgroup", testService.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStore_GetServiceStatusByKey(t *testing.T) {
|
||||||
|
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_GetServiceStatusByKey.db")
|
||||||
|
defer store.Close()
|
||||||
|
store.Insert(&testService, &testSuccessfulResult)
|
||||||
|
store.Insert(&testService, &testUnsuccessfulResult)
|
||||||
|
|
||||||
|
serviceStatus := store.GetServiceStatusByKey(testService.Key(), paging.NewServiceStatusParams().WithEvents(1, core.MaximumNumberOfEvents).WithResults(1, core.MaximumNumberOfResults).WithUptime())
|
||||||
|
if serviceStatus == nil {
|
||||||
|
t.Fatalf("serviceStatus shouldn't have been nil")
|
||||||
|
}
|
||||||
|
if serviceStatus.Name != testService.Name {
|
||||||
|
t.Fatalf("serviceStatus.Name should've been %s, got %s", testService.Name, serviceStatus.Name)
|
||||||
|
}
|
||||||
|
if serviceStatus.Group != testService.Group {
|
||||||
|
t.Fatalf("serviceStatus.Group should've been %s, got %s", testService.Group, serviceStatus.Group)
|
||||||
|
}
|
||||||
|
if serviceStatus.Uptime == nil {
|
||||||
|
t.Fatalf("serviceStatus.Uptime shouldn't have been nil")
|
||||||
|
}
|
||||||
|
if serviceStatus.Uptime.LastHour != 0.5 {
|
||||||
|
t.Errorf("serviceStatus.Uptime.LastHour should've been 0.5")
|
||||||
|
}
|
||||||
|
if serviceStatus.Uptime.LastTwentyFourHours != 0.5 {
|
||||||
|
t.Errorf("serviceStatus.Uptime.LastTwentyFourHours should've been 0.5")
|
||||||
|
}
|
||||||
|
if serviceStatus.Uptime.LastSevenDays != 0.5 {
|
||||||
|
t.Errorf("serviceStatus.Uptime.LastSevenDays should've been 0.5")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStore_GetAllServiceStatuses(t *testing.T) {
|
||||||
|
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_GetAllServiceStatuses.db")
|
||||||
|
defer store.Close()
|
||||||
|
firstResult := &testSuccessfulResult
|
||||||
|
secondResult := &testUnsuccessfulResult
|
||||||
|
store.Insert(&testService, firstResult)
|
||||||
|
store.Insert(&testService, secondResult)
|
||||||
|
// Can't be bothered dealing with timezone issues on the worker that runs the automated tests
|
||||||
|
firstResult.Timestamp = time.Time{}
|
||||||
|
secondResult.Timestamp = time.Time{}
|
||||||
|
serviceStatuses := store.GetAllServiceStatuses(paging.NewServiceStatusParams().WithResults(1, 20))
|
||||||
|
if len(serviceStatuses) != 1 {
|
||||||
|
t.Fatal("expected 1 service status")
|
||||||
|
}
|
||||||
|
actual, exists := serviceStatuses[testService.Key()]
|
||||||
|
if !exists {
|
||||||
|
t.Fatal("expected service status to exist")
|
||||||
|
}
|
||||||
|
if len(actual.Results) != 2 {
|
||||||
|
t.Error("expected 2 results, got", len(actual.Results))
|
||||||
|
}
|
||||||
|
if len(actual.Events) != 0 {
|
||||||
|
t.Error("expected 0 events, got", len(actual.Events))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStore_DeleteAllServiceStatusesNotInKeys(t *testing.T) {
|
||||||
|
store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_DeleteAllServiceStatusesNotInKeys.db")
|
||||||
|
defer store.Close()
|
||||||
|
firstService := core.Service{Name: "service-1", Group: "group"}
|
||||||
|
secondService := core.Service{Name: "service-2", Group: "group"}
|
||||||
|
result := &testSuccessfulResult
|
||||||
|
store.Insert(&firstService, result)
|
||||||
|
store.Insert(&secondService, result)
|
||||||
|
if store.GetServiceStatusByKey(firstService.Key(), paging.NewServiceStatusParams()) == nil {
|
||||||
|
t.Fatal("firstService should exist")
|
||||||
|
}
|
||||||
|
if store.GetServiceStatusByKey(secondService.Key(), paging.NewServiceStatusParams()) == nil {
|
||||||
|
t.Fatal("secondService should exist")
|
||||||
|
}
|
||||||
|
store.DeleteAllServiceStatusesNotInKeys([]string{firstService.Key()})
|
||||||
|
if store.GetServiceStatusByKey(firstService.Key(), paging.NewServiceStatusParams()) == nil {
|
||||||
|
t.Error("secondService should've been deleted")
|
||||||
|
}
|
||||||
|
if store.GetServiceStatusByKey(secondService.Key(), paging.NewServiceStatusParams()) != nil {
|
||||||
|
t.Error("firstService should still exist")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,3 +112,8 @@ func (s *Store) Save() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close does nothing, because there's nothing to close
|
||||||
|
func (s *Store) Close() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -37,6 +37,9 @@ func ShallowCopyServiceStatus(ss *core.ServiceStatus, params *paging.ServiceStat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getStartAndEndIndex(numberOfResults int, page, pageSize int) (int, int) {
|
func getStartAndEndIndex(numberOfResults int, page, pageSize int) (int, int) {
|
||||||
|
if page < 1 || pageSize < 0 {
|
||||||
|
return -1, -1
|
||||||
|
}
|
||||||
start := numberOfResults - (page * pageSize)
|
start := numberOfResults - (page * pageSize)
|
||||||
end := numberOfResults - ((page - 1) * pageSize)
|
end := numberOfResults - ((page - 1) * pageSize)
|
||||||
if start > numberOfResults {
|
if start > numberOfResults {
|
||||||
|
@ -11,45 +11,69 @@ import (
|
|||||||
func TestAddResult(t *testing.T) {
|
func TestAddResult(t *testing.T) {
|
||||||
service := &core.Service{Name: "name", Group: "group"}
|
service := &core.Service{Name: "name", Group: "group"}
|
||||||
serviceStatus := core.NewServiceStatus(service.Key(), service.Group, service.Name)
|
serviceStatus := core.NewServiceStatus(service.Key(), service.Group, service.Name)
|
||||||
for i := 0; i < core.MaximumNumberOfResults+10; i++ {
|
for i := 0; i < (core.MaximumNumberOfResults+core.MaximumNumberOfEvents)*2; i++ {
|
||||||
AddResult(serviceStatus, &core.Result{Timestamp: time.Now()})
|
AddResult(serviceStatus, &core.Result{Success: i%2 == 0, Timestamp: time.Now()})
|
||||||
}
|
}
|
||||||
if len(serviceStatus.Results) != core.MaximumNumberOfResults {
|
if len(serviceStatus.Results) != core.MaximumNumberOfResults {
|
||||||
t.Errorf("expected serviceStatus.Results to not exceed a length of %d", core.MaximumNumberOfResults)
|
t.Errorf("expected serviceStatus.Results to not exceed a length of %d", core.MaximumNumberOfResults)
|
||||||
}
|
}
|
||||||
|
if len(serviceStatus.Events) != core.MaximumNumberOfEvents {
|
||||||
|
t.Errorf("expected serviceStatus.Events to not exceed a length of %d", core.MaximumNumberOfEvents)
|
||||||
|
}
|
||||||
|
// Try to add nil serviceStatus
|
||||||
|
AddResult(nil, &core.Result{Timestamp: time.Now()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShallowCopyServiceStatus(t *testing.T) {
|
func TestShallowCopyServiceStatus(t *testing.T) {
|
||||||
service := &core.Service{Name: "name", Group: "group"}
|
service := &core.Service{Name: "name", Group: "group"}
|
||||||
serviceStatus := core.NewServiceStatus(service.Key(), service.Group, service.Name)
|
serviceStatus := core.NewServiceStatus(service.Key(), service.Group, service.Name)
|
||||||
|
ts := time.Now().Add(-25 * time.Hour)
|
||||||
for i := 0; i < 25; i++ {
|
for i := 0; i < 25; i++ {
|
||||||
AddResult(serviceStatus, &core.Result{Timestamp: time.Now()})
|
AddResult(serviceStatus, &core.Result{Success: i%2 == 0, Timestamp: ts})
|
||||||
|
ts = ts.Add(time.Hour)
|
||||||
|
}
|
||||||
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(-1, -1)).Results) != 0 {
|
||||||
|
t.Error("expected to have 0 result")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, 1)).Results) != 1 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, 1)).Results) != 1 {
|
||||||
t.Errorf("expected to have 1 result")
|
t.Error("expected to have 1 result")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(5, 0)).Results) != 0 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(5, 0)).Results) != 0 {
|
||||||
t.Errorf("expected to have 0 results")
|
t.Error("expected to have 0 results")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(-1, 20)).Results) != 0 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(-1, 20)).Results) != 0 {
|
||||||
t.Errorf("expected to have 0 result, because the page was invalid")
|
t.Error("expected to have 0 result, because the page was invalid")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, -1)).Results) != 0 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, -1)).Results) != 0 {
|
||||||
t.Errorf("expected to have 0 result, because the page size was invalid")
|
t.Error("expected to have 0 result, because the page size was invalid")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, 10)).Results) != 10 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, 10)).Results) != 10 {
|
||||||
t.Errorf("expected to have 10 results, because given a page size of 10, page 1 should have 10 elements")
|
t.Error("expected to have 10 results, because given a page size of 10, page 1 should have 10 elements")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(2, 10)).Results) != 10 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(2, 10)).Results) != 10 {
|
||||||
t.Errorf("expected to have 10 results, because given a page size of 10, page 2 should have 10 elements")
|
t.Error("expected to have 10 results, because given a page size of 10, page 2 should have 10 elements")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(3, 10)).Results) != 5 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(3, 10)).Results) != 5 {
|
||||||
t.Errorf("expected to have 5 results, because given a page size of 10, page 3 should have 5 elements")
|
t.Error("expected to have 5 results, because given a page size of 10, page 3 should have 5 elements")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(4, 10)).Results) != 0 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(4, 10)).Results) != 0 {
|
||||||
t.Errorf("expected to have 0 results, because given a page size of 10, page 4 should have 0 elements")
|
t.Error("expected to have 0 results, because given a page size of 10, page 4 should have 0 elements")
|
||||||
}
|
}
|
||||||
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, 50)).Results) != 25 {
|
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, 50)).Results) != 25 {
|
||||||
t.Errorf("expected to have 25 results, because there's only 25 results")
|
t.Error("expected to have 25 results, because there's only 25 results")
|
||||||
|
}
|
||||||
|
uptime := ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithUptime()).Uptime
|
||||||
|
if uptime == nil {
|
||||||
|
t.Error("expected uptime to not be nil")
|
||||||
|
} else {
|
||||||
|
if uptime.LastHour != 1 {
|
||||||
|
t.Error("expected uptime.LastHour to not be 1, got", uptime.LastHour)
|
||||||
|
}
|
||||||
|
if uptime.LastTwentyFourHours != 0.5 {
|
||||||
|
t.Error("expected uptime.LastTwentyFourHours to not be 0.5, got", uptime.LastTwentyFourHours)
|
||||||
|
}
|
||||||
|
if uptime.LastSevenDays != 0.52 {
|
||||||
|
t.Error("expected uptime.LastSevenDays to not be 0.52, got", uptime.LastSevenDays)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ type Store interface {
|
|||||||
|
|
||||||
// Save persists the data if and where it needs to be persisted
|
// Save persists the data if and where it needs to be persisted
|
||||||
Save() error
|
Save() error
|
||||||
|
|
||||||
|
// Close terminates every connections and closes the store, if applicable.
|
||||||
|
// Should only be used before stopping the application.
|
||||||
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add method to check state of store (by keeping track of silent errors)
|
// TODO: add method to check state of store (by keeping track of silent errors)
|
||||||
|
9
storage/type.go
Normal file
9
storage/type.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package storage
|
||||||
|
|
||||||
|
// Type of the store.
|
||||||
|
type Type string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeInMemory Type = "inmemory" // In-memory store
|
||||||
|
TypeSQLite Type = "sqlite" // SQLite store
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user