diff --git a/storage/store/sql/sql.go b/storage/store/sql/sql.go index 7271652d..66051f09 100644 --- a/storage/store/sql/sql.go +++ b/storage/store/sql/sql.go @@ -242,6 +242,7 @@ func (s *Store) Insert(service *core.Service, result *core.Result) error { // based on result.Success. numberOfEvents, err := s.getNumberOfEventsByServiceID(tx, serviceID) if err != nil { + // Silently fail log.Printf("[sql][Insert] Failed to retrieve total number of events for group=%s; service=%s: %s", service.Group, service.Name, err.Error()) } if numberOfEvents == 0 { diff --git a/storage/store/sql/sql_test.go b/storage/store/sql/sql_test.go index b6858486..f0b38283 100644 --- a/storage/store/sql/sql_test.go +++ b/storage/store/sql/sql_test.go @@ -296,9 +296,12 @@ func TestStore_SanityCheck(t *testing.T) { if len(ss.Results) != 2 { t.Errorf("Service '%s' should've had 2 results, got %d", ss.Name, len(ss.Results)) } - if deleted := store.DeleteAllServiceStatusesNotInKeys([]string{}); deleted != 1 { + if deleted := store.DeleteAllServiceStatusesNotInKeys([]string{"invalid-key-which-means-everything-should-get-deleted"}); deleted != 1 { t.Errorf("%d entries should've been deleted, got %d", 1, deleted) } + if deleted := store.DeleteAllServiceStatusesNotInKeys([]string{}); deleted != 0 { + t.Errorf("There should've been no entries left to delete, got %d", deleted) + } } // TestStore_InvalidTransaction tests what happens if an invalid transaction is passed as parameter @@ -372,3 +375,105 @@ func TestStore_NoRows(t *testing.T) { t.Errorf("should've %v, got %v", errNoRowsReturned, err) } } + +// This tests very unlikely cases where a table is deleted. +func TestStore_BrokenSchema(t *testing.T) { + store, _ := NewStore("sqlite", t.TempDir()+"/TestStore_BrokenSchema.db") + defer store.Close() + if err := store.Insert(&testService, &testSuccessfulResult); err != nil { + t.Fatal("expected no error, got", err.Error()) + } + if _, err := store.GetAverageResponseTimeByKey(testService.Key(), time.Now().Add(-time.Hour), time.Now()); err != nil { + t.Fatal("expected no error, got", err.Error()) + } + if _, err := store.GetAllServiceStatuses(paging.NewServiceStatusParams()); err != nil { + t.Fatal("expected no error, got", err.Error()) + } + // Break + _, _ = store.db.Exec("DROP TABLE service") + if err := store.Insert(&testService, &testSuccessfulResult); err == nil { + t.Fatal("expected an error") + } + if _, err := store.GetAverageResponseTimeByKey(testService.Key(), time.Now().Add(-time.Hour), time.Now()); err == nil { + t.Fatal("expected an error") + } + if _, err := store.GetHourlyAverageResponseTimeByKey(testService.Key(), time.Now().Add(-time.Hour), time.Now()); err == nil { + t.Fatal("expected an error") + } + if _, err := store.GetAllServiceStatuses(paging.NewServiceStatusParams()); err == nil { + t.Fatal("expected an error") + } + if _, err := store.GetUptimeByKey(testService.Key(), time.Now().Add(-time.Hour), time.Now()); err == nil { + t.Fatal("expected an error") + } + if _, err := store.GetServiceStatusByKey(testService.Key(), paging.NewServiceStatusParams()); err == nil { + t.Fatal("expected an error") + } + // Repair + if err := store.createSchema(); err != nil { + t.Fatal("schema should've been repaired") + } + store.Clear() + if err := store.Insert(&testService, &testSuccessfulResult); err != nil { + t.Fatal("expected no error, got", err.Error()) + } + // Break + _, _ = store.db.Exec("DROP TABLE service_event") + if err := store.Insert(&testService, &testSuccessfulResult); err != nil { + t.Fatal("expected no error, because this should silently fails, got", err.Error()) + } + if _, err := store.GetAllServiceStatuses(paging.NewServiceStatusParams().WithResults(1, 1).WithEvents(1, 1)); err != nil { + t.Fatal("expected no error, because this should silently fail, got", err.Error()) + } + // Repair + if err := store.createSchema(); err != nil { + t.Fatal("schema should've been repaired") + } + store.Clear() + if err := store.Insert(&testService, &testSuccessfulResult); err != nil { + t.Fatal("expected no error, got", err.Error()) + } + // Break + _, _ = store.db.Exec("DROP TABLE service_result") + if err := store.Insert(&testService, &testSuccessfulResult); err == nil { + t.Fatal("expected an error") + } + if _, err := store.GetAllServiceStatuses(paging.NewServiceStatusParams().WithResults(1, 1).WithEvents(1, 1)); err != nil { + t.Fatal("expected no error, because this should silently fail, got", err.Error()) + } + // Repair + if err := store.createSchema(); err != nil { + t.Fatal("schema should've been repaired") + } + store.Clear() + if err := store.Insert(&testService, &testSuccessfulResult); err != nil { + t.Fatal("expected no error, got", err.Error()) + } + // Break + _, _ = store.db.Exec("DROP TABLE service_result_condition") + if err := store.Insert(&testService, &testSuccessfulResult); err == nil { + t.Fatal("expected an error") + } + // Repair + if err := store.createSchema(); err != nil { + t.Fatal("schema should've been repaired") + } + store.Clear() + if err := store.Insert(&testService, &testSuccessfulResult); err != nil { + t.Fatal("expected no error, got", err.Error()) + } + // Break + _, _ = store.db.Exec("DROP TABLE service_uptime") + if err := store.Insert(&testService, &testSuccessfulResult); err != nil { + t.Fatal("expected no error, because this should silently fails, got", err.Error()) + } + if _, err := store.GetAverageResponseTimeByKey(testService.Key(), time.Now().Add(-time.Hour), time.Now()); err == nil { + t.Fatal("expected an error") + } + if _, err := store.GetHourlyAverageResponseTimeByKey(testService.Key(), time.Now().Add(-time.Hour), time.Now()); err == nil { + t.Fatal("expected an error") + } + if _, err := store.GetUptimeByKey(testService.Key(), time.Now().Add(-time.Hour), time.Now()); err == nil { + t.Fatal("expected an error") + } +}