Remove Uptime.Last* parameters

This commit is contained in:
TwinProduction 2021-08-13 00:38:39 -04:00 committed by Chris
parent 0b6fc6b520
commit d65cebb1fb
15 changed files with 48 additions and 173 deletions

View File

@ -138,20 +138,28 @@ func serviceStatusesHandler(writer http.ResponseWriter, r *http.Request) {
func serviceStatusHandler(writer http.ResponseWriter, r *http.Request) { func serviceStatusHandler(writer http.ResponseWriter, r *http.Request) {
page, pageSize := extractPageAndPageSizeFromRequest(r) page, pageSize := extractPageAndPageSizeFromRequest(r)
vars := mux.Vars(r) vars := mux.Vars(r)
serviceStatus := storage.Get().GetServiceStatusByKey(vars["key"], paging.NewServiceStatusParams().WithResults(page, pageSize).WithEvents(1, common.MaximumNumberOfEvents).WithUptime()) serviceStatus := storage.Get().GetServiceStatusByKey(vars["key"], paging.NewServiceStatusParams().WithResults(page, pageSize).WithEvents(1, common.MaximumNumberOfEvents))
if serviceStatus == nil { if serviceStatus == nil {
log.Printf("[controller][serviceStatusHandler] Service with key=%s not found", vars["key"]) log.Printf("[controller][serviceStatusHandler] Service with key=%s not found", vars["key"])
writer.WriteHeader(http.StatusNotFound) writer.WriteHeader(http.StatusNotFound)
_, _ = writer.Write([]byte("not found")) _, _ = writer.Write([]byte("not found"))
return return
} }
uptime7Days, _ := storage.Get().GetUptimeByKey(vars["key"], time.Now().Add(-time.Hour*24*7), time.Now())
uptime24Hours, _ := storage.Get().GetUptimeByKey(vars["key"], time.Now().Add(-time.Hour*24), time.Now())
uptime1Hour, _ := storage.Get().GetUptimeByKey(vars["key"], time.Now().Add(-time.Hour), time.Now())
data := map[string]interface{}{ data := map[string]interface{}{
"serviceStatus": serviceStatus, "serviceStatus": serviceStatus,
// The following fields, while present on core.ServiceStatus, are annotated to remain hidden so that we can // The following fields, while present on core.ServiceStatus, are annotated to remain hidden so that we can
// expose only the necessary data on /api/v1/statuses. // expose only the necessary data on /api/v1/statuses.
// Since the /api/v1/statuses/{key} endpoint does need this data, however, we explicitly expose it here // Since the /api/v1/statuses/{key} endpoint does need this data, however, we explicitly expose it here
"events": serviceStatus.Events, "events": serviceStatus.Events,
"uptime": serviceStatus.Uptime, // TODO: remove this in v3.0.0. Not used by front-end, only used for API. Left here for v2.x.x backward compatibility
"uptime": map[string]float64{
"7d": uptime7Days,
"24h": uptime24Hours,
"1h": uptime1Hour,
},
} }
output, err := json.Marshal(data) output, err := json.Marshal(data)
if err != nil { if err != nil {

View File

@ -3,10 +3,6 @@ package core
// Uptime is the struct that contains the relevant data for calculating the uptime as well as the uptime itself // Uptime is the struct that contains the relevant data for calculating the uptime as well as the uptime itself
// and some other statistics // and some other statistics
type Uptime struct { type Uptime struct {
LastSevenDays float64 `json:"7d"` // Uptime percentage over the past 7 days
LastTwentyFourHours float64 `json:"24h"` // Uptime percentage over the past 24 hours
LastHour float64 `json:"1h"` // Uptime percentage over the past hour
// SuccessfulExecutionsPerHour is a map containing the number of successes (value) // SuccessfulExecutionsPerHour is a map containing the number of successes (value)
// for every hourly unix timestamps (key) // for every hourly unix timestamps (key)
// Deprecated // Deprecated

View File

@ -2,11 +2,10 @@ package paging
// ServiceStatusParams represents all parameters that can be used for paging purposes // ServiceStatusParams represents all parameters that can be used for paging purposes
type ServiceStatusParams struct { type ServiceStatusParams struct {
EventsPage int // Number of the event page EventsPage int // Number of the event page
EventsPageSize int // Size of the event page EventsPageSize int // Size of the event page
ResultsPage int // Number of the result page ResultsPage int // Number of the result page
ResultsPageSize int // Size of the result page ResultsPageSize int // Size of the result page
IncludeUptime bool // Whether to include uptime data
} }
// NewServiceStatusParams creates a new ServiceStatusParams // NewServiceStatusParams creates a new ServiceStatusParams
@ -27,9 +26,3 @@ func (params *ServiceStatusParams) WithResults(page, pageSize int) *ServiceStatu
params.ResultsPageSize = pageSize params.ResultsPageSize = pageSize
return params return params
} }
// WithUptime sets the value IncludeUptime to true
func (params *ServiceStatusParams) WithUptime() *ServiceStatusParams {
params.IncludeUptime = true
return params
}

View File

@ -10,7 +10,6 @@ func TestNewServiceStatusParams(t *testing.T) {
ExpectedEventsPageSize int ExpectedEventsPageSize int
ExpectedResultsPage int ExpectedResultsPage int
ExpectedResultsPageSize int ExpectedResultsPageSize int
ExpectedIncludeUptime bool
} }
scenarios := []Scenario{ scenarios := []Scenario{
{ {
@ -20,7 +19,6 @@ func TestNewServiceStatusParams(t *testing.T) {
ExpectedEventsPageSize: 0, ExpectedEventsPageSize: 0,
ExpectedResultsPage: 0, ExpectedResultsPage: 0,
ExpectedResultsPageSize: 0, ExpectedResultsPageSize: 0,
ExpectedIncludeUptime: false,
}, },
{ {
Name: "with-events-page-2-size-7", Name: "with-events-page-2-size-7",
@ -29,25 +27,22 @@ func TestNewServiceStatusParams(t *testing.T) {
ExpectedEventsPageSize: 7, ExpectedEventsPageSize: 7,
ExpectedResultsPage: 0, ExpectedResultsPage: 0,
ExpectedResultsPageSize: 0, ExpectedResultsPageSize: 0,
ExpectedIncludeUptime: false,
}, },
{ {
Name: "with-events-page-4-size-3-uptime", Name: "with-events-page-4-size-3-uptime",
Params: NewServiceStatusParams().WithEvents(4, 3).WithUptime(), Params: NewServiceStatusParams().WithEvents(4, 3),
ExpectedEventsPage: 4, ExpectedEventsPage: 4,
ExpectedEventsPageSize: 3, ExpectedEventsPageSize: 3,
ExpectedResultsPage: 0, ExpectedResultsPage: 0,
ExpectedResultsPageSize: 0, ExpectedResultsPageSize: 0,
ExpectedIncludeUptime: true,
}, },
{ {
Name: "with-results-page-1-size-20-uptime", Name: "with-results-page-1-size-20-uptime",
Params: NewServiceStatusParams().WithResults(1, 20).WithUptime(), Params: NewServiceStatusParams().WithResults(1, 20),
ExpectedEventsPage: 0, ExpectedEventsPage: 0,
ExpectedEventsPageSize: 0, ExpectedEventsPageSize: 0,
ExpectedResultsPage: 1, ExpectedResultsPage: 1,
ExpectedResultsPageSize: 20, ExpectedResultsPageSize: 20,
ExpectedIncludeUptime: true,
}, },
{ {
Name: "with-results-page-2-size-10-events-page-3-size-50", Name: "with-results-page-2-size-10-events-page-3-size-50",
@ -56,7 +51,6 @@ func TestNewServiceStatusParams(t *testing.T) {
ExpectedEventsPageSize: 50, ExpectedEventsPageSize: 50,
ExpectedResultsPage: 2, ExpectedResultsPage: 2,
ExpectedResultsPageSize: 10, ExpectedResultsPageSize: 10,
ExpectedIncludeUptime: false,
}, },
} }
for _, scenario := range scenarios { for _, scenario := range scenarios {
@ -73,9 +67,6 @@ func TestNewServiceStatusParams(t *testing.T) {
if scenario.Params.ResultsPageSize != scenario.ExpectedResultsPageSize { if scenario.Params.ResultsPageSize != scenario.ExpectedResultsPageSize {
t.Errorf("expected ResultsPageSize to be %d, was %d", scenario.ExpectedResultsPageSize, scenario.Params.ResultsPageSize) t.Errorf("expected ResultsPageSize to be %d, was %d", scenario.ExpectedResultsPageSize, scenario.Params.ResultsPageSize)
} }
if scenario.Params.IncludeUptime != scenario.ExpectedIncludeUptime {
t.Errorf("expected IncludeUptime to be %v, was %v", scenario.ExpectedIncludeUptime, scenario.Params.IncludeUptime)
}
}) })
} }
} }

View File

@ -45,57 +45,6 @@ func processUptimeAfterResult(uptime *core.Uptime, result *core.Result) {
} }
} }
} }
if result.Success {
// Recalculate uptime if at least one of the 1h, 24h or 7d uptime are not 100%
// If they're all 100%, then recalculating the uptime would be useless unless
// the result added was a failure (!result.Success)
if uptime.LastSevenDays != 1 || uptime.LastTwentyFourHours != 1 || uptime.LastHour != 1 {
recalculateUptime(uptime)
}
} else {
// Recalculate uptime if at least one of the 1h, 24h or 7d uptime are not 0%
// If they're all 0%, then recalculating the uptime would be useless unless
// the result added was a success (result.Success)
if uptime.LastSevenDays != 0 || uptime.LastTwentyFourHours != 0 || uptime.LastHour != 0 {
recalculateUptime(uptime)
}
}
}
// recalculateUptime calculates the uptime over the past 7 days, 24 hours and 1 hour.
func recalculateUptime(uptime *core.Uptime) {
uptimeBrackets := make(map[string]uint64)
now := time.Now()
// The oldest uptime bracket starts 7 days ago, so we'll start from there
timestamp := now.Add(-sevenDays)
for now.Sub(timestamp) >= 0 {
hourlyUnixTimestamp := timestamp.Truncate(time.Hour).Unix()
hourlyStats := uptime.HourlyStatistics[hourlyUnixTimestamp]
if hourlyStats == nil || hourlyStats.TotalExecutions == 0 {
timestamp = timestamp.Add(time.Hour)
continue
}
uptimeBrackets["7d_success"] += hourlyStats.SuccessfulExecutions
uptimeBrackets["7d_total"] += hourlyStats.TotalExecutions
if now.Sub(timestamp) <= 24*time.Hour {
uptimeBrackets["24h_success"] += hourlyStats.SuccessfulExecutions
uptimeBrackets["24h_total"] += hourlyStats.TotalExecutions
}
if now.Sub(timestamp) <= time.Hour {
uptimeBrackets["1h_success"] += hourlyStats.SuccessfulExecutions
uptimeBrackets["1h_total"] += hourlyStats.TotalExecutions
}
timestamp = timestamp.Add(time.Hour)
}
if uptimeBrackets["7d_total"] > 0 {
uptime.LastSevenDays = float64(uptimeBrackets["7d_success"]) / float64(uptimeBrackets["7d_total"])
}
if uptimeBrackets["24h_total"] > 0 {
uptime.LastTwentyFourHours = float64(uptimeBrackets["24h_success"]) / float64(uptimeBrackets["24h_total"])
}
if uptimeBrackets["1h_total"] > 0 {
uptime.LastHour = float64(uptimeBrackets["1h_success"]) / float64(uptimeBrackets["1h_total"])
}
} }
// XXX: Remove this on v3.0.0 // XXX: Remove this on v3.0.0

View File

@ -12,22 +12,16 @@ func TestProcessUptimeAfterResult(t *testing.T) {
serviceStatus := core.NewServiceStatus(service.Key(), service.Group, service.Name) serviceStatus := core.NewServiceStatus(service.Key(), service.Group, service.Name)
uptime := serviceStatus.Uptime uptime := serviceStatus.Uptime
checkUptimes(t, serviceStatus, 0.00, 0.00, 0.00)
now := time.Now() now := time.Now()
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())
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-7 * 24 * time.Hour), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-7 * 24 * time.Hour), Success: true})
checkUptimes(t, serviceStatus, 1.00, 0.00, 0.00)
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-6 * 24 * time.Hour), Success: false}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-6 * 24 * time.Hour), Success: false})
checkUptimes(t, serviceStatus, 0.50, 0.00, 0.00)
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-8 * 24 * time.Hour), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-8 * 24 * time.Hour), Success: true})
checkUptimes(t, serviceStatus, 0.50, 0.00, 0.00)
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-24 * time.Hour), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-24 * time.Hour), Success: true})
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-12 * time.Hour), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-12 * time.Hour), Success: true})
checkUptimes(t, serviceStatus, 0.75, 1.00, 0.00)
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-1 * time.Hour), Success: true, Duration: 10 * time.Millisecond}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-1 * time.Hour), Success: true, Duration: 10 * time.Millisecond})
checkHourlyStatistics(t, uptime.HourlyStatistics[now.Unix()-now.Unix()%3600-3600], 10, 1, 1) checkHourlyStatistics(t, uptime.HourlyStatistics[now.Unix()-now.Unix()%3600-3600], 10, 1, 1)
@ -37,7 +31,6 @@ func TestProcessUptimeAfterResult(t *testing.T) {
checkHourlyStatistics(t, uptime.HourlyStatistics[now.Unix()-now.Unix()%3600-3600], 535, 3, 1) checkHourlyStatistics(t, uptime.HourlyStatistics[now.Unix()-now.Unix()%3600-3600], 535, 3, 1)
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-10 * time.Minute), Success: false}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-10 * time.Minute), Success: false})
checkUptimes(t, serviceStatus, 0.50, 0.50, 0.25)
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-120 * time.Hour), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-120 * time.Hour), Success: true})
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-119 * time.Hour), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-119 * time.Hour), Success: true})
@ -47,7 +40,6 @@ func TestProcessUptimeAfterResult(t *testing.T) {
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-8 * time.Hour), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-8 * time.Hour), Success: true})
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-30 * time.Minute), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-30 * time.Minute), Success: true})
processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-25 * time.Minute), Success: true}) processUptimeAfterResult(uptime, &core.Result{Timestamp: now.Add(-25 * time.Minute), Success: true})
checkUptimes(t, serviceStatus, 0.75, 0.70, 0.50)
} }
func TestAddResultUptimeIsCleaningUpAfterItself(t *testing.T) { func TestAddResultUptimeIsCleaningUpAfterItself(t *testing.T) {
@ -62,29 +54,11 @@ func TestAddResultUptimeIsCleaningUpAfterItself(t *testing.T) {
if len(serviceStatus.Uptime.HourlyStatistics) > numberOfHoursInTenDays { if len(serviceStatus.Uptime.HourlyStatistics) > numberOfHoursInTenDays {
t.Errorf("At no point in time should there be more than %d entries in serviceStatus.SuccessfulExecutionsPerHour, but there are %d", numberOfHoursInTenDays, len(serviceStatus.Uptime.HourlyStatistics)) t.Errorf("At no point in time should there be more than %d entries in serviceStatus.SuccessfulExecutionsPerHour, but there are %d", numberOfHoursInTenDays, len(serviceStatus.Uptime.HourlyStatistics))
} }
if now.Sub(timestamp) > time.Hour && serviceStatus.Uptime.LastHour != 0 {
t.Error("most recent timestamp > 1h ago, expected serviceStatus.Uptime.LastHour to be 0, got", serviceStatus.Uptime.LastHour)
}
if now.Sub(timestamp) < time.Hour && serviceStatus.Uptime.LastHour == 0 {
t.Error("most recent timestamp < 1h ago, expected serviceStatus.Uptime.LastHour to NOT be 0, got", serviceStatus.Uptime.LastHour)
}
// Simulate service with an interval of 3 minutes // Simulate service with an interval of 3 minutes
timestamp = timestamp.Add(3 * time.Minute) timestamp = timestamp.Add(3 * time.Minute)
} }
} }
func checkUptimes(t *testing.T, status *core.ServiceStatus, expectedUptimeDuringLastSevenDays, expectedUptimeDuringLastTwentyFourHours, expectedUptimeDuringLastHour float64) {
if status.Uptime.LastSevenDays != expectedUptimeDuringLastSevenDays {
t.Errorf("expected status.Uptime.LastSevenDays to be %f, got %f", expectedUptimeDuringLastHour, status.Uptime.LastSevenDays)
}
if status.Uptime.LastTwentyFourHours != expectedUptimeDuringLastTwentyFourHours {
t.Errorf("expected status.Uptime.LastTwentyFourHours to be %f, got %f", expectedUptimeDuringLastTwentyFourHours, status.Uptime.LastTwentyFourHours)
}
if status.Uptime.LastHour != expectedUptimeDuringLastHour {
t.Errorf("expected status.Uptime.LastHour to be %f, got %f", expectedUptimeDuringLastHour, status.Uptime.LastHour)
}
}
func checkHourlyStatistics(t *testing.T, hourlyUptimeStatistics *core.HourlyUptimeStatistics, expectedTotalExecutionsResponseTime uint64, expectedTotalExecutions uint64, expectedSuccessfulExecutions uint64) { func checkHourlyStatistics(t *testing.T, hourlyUptimeStatistics *core.HourlyUptimeStatistics, expectedTotalExecutionsResponseTime uint64, expectedTotalExecutions uint64, expectedSuccessfulExecutions uint64) {
if hourlyUptimeStatistics.TotalExecutionsResponseTime != expectedTotalExecutionsResponseTime { if hourlyUptimeStatistics.TotalExecutionsResponseTime != expectedTotalExecutionsResponseTime {
t.Error("TotalExecutionsResponseTime should've been", expectedTotalExecutionsResponseTime, "got", hourlyUptimeStatistics.TotalExecutionsResponseTime) t.Error("TotalExecutionsResponseTime should've been", expectedTotalExecutionsResponseTime, "got", hourlyUptimeStatistics.TotalExecutionsResponseTime)

View File

@ -29,11 +29,6 @@ func ShallowCopyServiceStatus(ss *core.ServiceStatus, params *paging.ServiceStat
} else { } else {
shallowCopy.Events = ss.Events[eventsStart:eventsEnd] shallowCopy.Events = ss.Events[eventsStart:eventsEnd]
} }
if params.IncludeUptime {
shallowCopy.Uptime.LastHour = ss.Uptime.LastHour
shallowCopy.Uptime.LastTwentyFourHours = ss.Uptime.LastTwentyFourHours
shallowCopy.Uptime.LastSevenDays = ss.Uptime.LastSevenDays
}
return shallowCopy return shallowCopy
} }

View File

@ -63,18 +63,4 @@ func TestShallowCopyServiceStatus(t *testing.T) {
if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, 50)).Results) != 25 { if len(ShallowCopyServiceStatus(serviceStatus, paging.NewServiceStatusParams().WithResults(1, 50)).Results) != 25 {
t.Error("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)
}
}
} }

View File

@ -501,12 +501,12 @@ func (s *Store) getServiceStatusByKey(tx *sql.Tx, key string, parameters *paging
log.Printf("[sqlite][getServiceStatusByKey] Failed to retrieve results for key=%s: %s", key, err.Error()) log.Printf("[sqlite][getServiceStatusByKey] Failed to retrieve results for key=%s: %s", key, err.Error())
} }
} }
if parameters.IncludeUptime { //if parameters.IncludeUptime {
now := time.Now() // now := time.Now()
serviceStatus.Uptime.LastHour, _, err = s.getServiceUptime(tx, serviceID, now.Add(-time.Hour), now) // serviceStatus.Uptime.LastHour, _, err = s.getServiceUptime(tx, serviceID, now.Add(-time.Hour), now)
serviceStatus.Uptime.LastTwentyFourHours, _, err = s.getServiceUptime(tx, serviceID, now.Add(-24*time.Hour), now) // serviceStatus.Uptime.LastTwentyFourHours, _, err = s.getServiceUptime(tx, serviceID, now.Add(-24*time.Hour), now)
serviceStatus.Uptime.LastSevenDays, _, err = s.getServiceUptime(tx, serviceID, now.Add(-7*24*time.Hour), now) // serviceStatus.Uptime.LastSevenDays, _, err = s.getServiceUptime(tx, serviceID, now.Add(-7*24*time.Hour), now)
} //}
return serviceStatus, nil return serviceStatus, nil
} }

View File

@ -174,16 +174,25 @@ func TestStore_Persistence(t *testing.T) {
store, _ := NewStore("sqlite", file) store, _ := NewStore("sqlite", file)
store.Insert(&testService, &testSuccessfulResult) store.Insert(&testService, &testSuccessfulResult)
store.Insert(&testService, &testUnsuccessfulResult) store.Insert(&testService, &testUnsuccessfulResult)
ssFromOldStore := store.GetServiceStatus(testService.Group, testService.Name, paging.NewServiceStatusParams().WithResults(1, common.MaximumNumberOfResults).WithEvents(1, common.MaximumNumberOfEvents).WithUptime()) if uptime, _ := store.GetUptimeByKey(testService.Key(), time.Now().Add(-time.Hour), time.Now()); uptime != 0.5 {
if ssFromOldStore == nil || ssFromOldStore.Group != "group" || ssFromOldStore.Name != "name" || len(ssFromOldStore.Events) != 3 || len(ssFromOldStore.Results) != 2 || ssFromOldStore.Uptime.LastHour != 0.5 || ssFromOldStore.Uptime.LastTwentyFourHours != 0.5 || ssFromOldStore.Uptime.LastSevenDays != 0.5 { t.Errorf("the uptime over the past 1h should've been 0.5, got %f", uptime)
}
if uptime, _ := store.GetUptimeByKey(testService.Key(), time.Now().Add(-time.Hour*24), time.Now()); uptime != 0.5 {
t.Errorf("the uptime over the past 24h should've been 0.5, got %f", uptime)
}
if uptime, _ := store.GetUptimeByKey(testService.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.GetServiceStatus(testService.Group, testService.Name, paging.NewServiceStatusParams().WithResults(1, common.MaximumNumberOfResults).WithEvents(1, common.MaximumNumberOfEvents))
if ssFromOldStore == nil || ssFromOldStore.Group != "group" || ssFromOldStore.Name != "name" || len(ssFromOldStore.Events) != 3 || len(ssFromOldStore.Results) != 2 {
store.Close() store.Close()
t.Fatal("sanity check failed") t.Fatal("sanity check failed")
} }
store.Close() store.Close()
store, _ = NewStore("sqlite", file) store, _ = NewStore("sqlite", file)
defer store.Close() defer store.Close()
ssFromNewStore := store.GetServiceStatus(testService.Group, testService.Name, paging.NewServiceStatusParams().WithResults(1, common.MaximumNumberOfResults).WithEvents(1, common.MaximumNumberOfEvents).WithUptime()) ssFromNewStore := store.GetServiceStatus(testService.Group, testService.Name, paging.NewServiceStatusParams().WithResults(1, common.MaximumNumberOfResults).WithEvents(1, common.MaximumNumberOfEvents))
if ssFromNewStore == nil || ssFromNewStore.Group != "group" || ssFromNewStore.Name != "name" || len(ssFromNewStore.Events) != 3 || len(ssFromNewStore.Results) != 2 || ssFromNewStore.Uptime.LastHour != 0.5 || ssFromNewStore.Uptime.LastTwentyFourHours != 0.5 || ssFromNewStore.Uptime.LastSevenDays != 0.5 { if ssFromNewStore == nil || ssFromNewStore.Group != "group" || ssFromNewStore.Name != "name" || len(ssFromNewStore.Events) != 3 || len(ssFromNewStore.Results) != 2 {
t.Fatal("failed sanity check") t.Fatal("failed sanity check")
} }
if ssFromNewStore == ssFromOldStore { if ssFromNewStore == ssFromOldStore {

View File

@ -127,7 +127,7 @@ func TestStore_GetServiceStatusByKey(t *testing.T) {
scenario.Store.Insert(&testService, &firstResult) scenario.Store.Insert(&testService, &firstResult)
scenario.Store.Insert(&testService, &secondResult) scenario.Store.Insert(&testService, &secondResult)
serviceStatus := scenario.Store.GetServiceStatusByKey(testService.Key(), paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults).WithUptime()) serviceStatus := scenario.Store.GetServiceStatusByKey(testService.Key(), paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults))
if serviceStatus == nil { if serviceStatus == nil {
t.Fatalf("serviceStatus shouldn't have been nil") t.Fatalf("serviceStatus shouldn't have been nil")
} }
@ -143,18 +143,6 @@ func TestStore_GetServiceStatusByKey(t *testing.T) {
if serviceStatus.Results[0].Timestamp.After(serviceStatus.Results[1].Timestamp) { if serviceStatus.Results[0].Timestamp.After(serviceStatus.Results[1].Timestamp) {
t.Error("The result at index 0 should've been older than the result at index 1") t.Error("The result at index 0 should've been older than the result at index 1")
} }
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, got %f", serviceStatus.Uptime.LastHour)
}
if serviceStatus.Uptime.LastTwentyFourHours != 0.5 {
t.Errorf("serviceStatus.Uptime.LastTwentyFourHours should've been 0.5, got %f", serviceStatus.Uptime.LastTwentyFourHours)
}
if serviceStatus.Uptime.LastSevenDays != 0.5 {
t.Errorf("serviceStatus.Uptime.LastSevenDays should've been 0.5, got %f", serviceStatus.Uptime.LastSevenDays)
}
scenario.Store.Clear() scenario.Store.Clear()
}) })
} }
@ -166,15 +154,15 @@ func TestStore_GetServiceStatusForMissingStatusReturnsNil(t *testing.T) {
for _, scenario := range scenarios { for _, scenario := range scenarios {
t.Run(scenario.Name, func(t *testing.T) { t.Run(scenario.Name, func(t *testing.T) {
scenario.Store.Insert(&testService, &testSuccessfulResult) scenario.Store.Insert(&testService, &testSuccessfulResult)
serviceStatus := scenario.Store.GetServiceStatus("nonexistantgroup", "nonexistantname", paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults).WithUptime()) serviceStatus := scenario.Store.GetServiceStatus("nonexistantgroup", "nonexistantname", paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults))
if serviceStatus != nil { 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) 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 = scenario.Store.GetServiceStatus(testService.Group, "nonexistantname", paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults).WithUptime()) serviceStatus = scenario.Store.GetServiceStatus(testService.Group, "nonexistantname", paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults))
if serviceStatus != nil { 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") t.Errorf("Returned service status for group '%s' and name '%s' not nil after inserting the service into the store", testService.Group, "nonexistantname")
} }
serviceStatus = scenario.Store.GetServiceStatus("nonexistantgroup", testService.Name, paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults).WithUptime()) serviceStatus = scenario.Store.GetServiceStatus("nonexistantgroup", testService.Name, paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults))
if serviceStatus != nil { 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) t.Errorf("Returned service status for group '%s' and name '%s' not nil after inserting the service into the store", "nonexistantgroup", testService.Name)
} }
@ -316,7 +304,7 @@ func TestStore_Insert(t *testing.T) {
scenario.Store.Insert(&testService, &testSuccessfulResult) scenario.Store.Insert(&testService, &testSuccessfulResult)
scenario.Store.Insert(&testService, &testUnsuccessfulResult) scenario.Store.Insert(&testService, &testUnsuccessfulResult)
ss := scenario.Store.GetServiceStatusByKey(testService.Key(), paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults).WithUptime()) ss := scenario.Store.GetServiceStatusByKey(testService.Key(), paging.NewServiceStatusParams().WithEvents(1, common.MaximumNumberOfEvents).WithResults(1, common.MaximumNumberOfResults))
if ss == nil { if ss == nil {
t.Fatalf("Store should've had key '%s', but didn't", testService.Key()) t.Fatalf("Store should've had key '%s', but didn't", testService.Key())
} }

View File

@ -14,33 +14,20 @@
/> />
<Pagination @page="changePage"/> <Pagination @page="changePage"/>
</slot> </slot>
<div v-if="uptime" class="mt-12"> <div class="mt-12">
<h1 class="text-xl xl:text-3xl font-mono text-gray-400">UPTIME</h1> <h1 class="text-xl xl:text-3xl font-mono text-gray-400">UPTIME</h1>
<hr /> <hr />
<div class="flex space-x-4 text-center text-xl xl:text-2xl mt-3"> <div v-if="serviceStatus && serviceStatus.key" class="flex space-x-4 text-center text-2xl mt-6 relative bottom-2 mb-10">
<div class="flex-1">
{{ prettifyUptime(uptime['7d']) }}
<h2 class="text-sm text-gray-400">Last 7 days</h2>
</div>
<div class="flex-1">
{{ prettifyUptime(uptime['24h']) }}
<h2 class="text-sm text-gray-400">Last 24 hours</h2>
</div>
<div class="flex-1">
{{ prettifyUptime(uptime['1h']) }}
<h2 class="text-sm text-gray-400">Last hour</h2>
</div>
</div>
<hr class="mt-1"/>
<h3 class="text-xl font-mono text-gray-400 mt-1 text-right">BADGES</h3>
<div v-if="serviceStatus && serviceStatus.key" class="flex space-x-4 text-center text-2xl mt-6 relative bottom-12">
<div class="flex-1"> <div class="flex-1">
<h2 class="text-sm text-gray-400 mb-1">Last 7 days</h2>
<img :src="generateBadgeImageURL('7d')" alt="7d uptime badge" class="mx-auto" /> <img :src="generateBadgeImageURL('7d')" alt="7d uptime badge" class="mx-auto" />
</div> </div>
<div class="flex-1"> <div class="flex-1">
<h2 class="text-sm text-gray-400 mb-1">Last 24 hours</h2>
<img :src="generateBadgeImageURL('24h')" alt="24h uptime badge" class="mx-auto" /> <img :src="generateBadgeImageURL('24h')" alt="24h uptime badge" class="mx-auto" />
</div> </div>
<div class="flex-1"> <div class="flex-1">
<h2 class="text-sm text-gray-400 mb-1">Last hour</h2>
<img :src="generateBadgeImageURL('1h')" alt="1h uptime badge" class="mx-auto" /> <img :src="generateBadgeImageURL('1h')" alt="1h uptime badge" class="mx-auto" />
</div> </div>
</div> </div>
@ -159,7 +146,6 @@ export default {
return { return {
serviceStatus: {}, serviceStatus: {},
events: [], events: [],
uptime: {"7d": 0, "24h": 0, "1h": 0},
// Since this page isn't at the root, we need to modify the server URL a bit // Since this page isn't at the root, we need to modify the server URL a bit
serverUrl: SERVER_URL === '.' ? '..' : SERVER_URL, serverUrl: SERVER_URL === '.' ? '..' : SERVER_URL,
currentPage: 1, currentPage: 1,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long