diff --git a/alerting/provider/incidentio/incidentio.go b/alerting/provider/incidentio/incidentio.go index 6783f571..ee1bc86a 100644 --- a/alerting/provider/incidentio/incidentio.go +++ b/alerting/provider/incidentio/incidentio.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "maps" "net/http" "strconv" "strings" @@ -170,9 +171,7 @@ func (provider *AlertProvider) buildRequestBody(cfg *Config, ep *endpoint.Endpoi // Merge metadata: cfg.Metadata + ep.ExtraLabels (if present) mergedMetadata := map[string]interface{}{} // Copy cfg.Metadata - for k, v := range cfg.Metadata { - mergedMetadata[k] = v - } + maps.Copy(mergedMetadata, cfg.Metadata) // Add extra labels from endpoint (if present) if ep.ExtraLabels != nil && len(ep.ExtraLabels) > 0 { for k, v := range ep.ExtraLabels { diff --git a/api/badge.go b/api/badge.go index 8fa95696..7600366e 100644 --- a/api/badge.go +++ b/api/badge.go @@ -299,7 +299,7 @@ func getBadgeColorFromResponseTime(responseTime int, key string, cfg *config.Con thresholds = endpoint.UIConfig.Badge.ResponseTime.Thresholds } // the threshold config requires 5 values, so we can be sure it's set here - for i := 0; i < 5; i++ { + for i := range 5 { if responseTime <= thresholds[i] { return badgeColors[i] } diff --git a/config/config.go b/config/config.go index 1597e9ce..6f0b5a18 100644 --- a/config/config.go +++ b/config/config.go @@ -6,6 +6,7 @@ import ( "io/fs" "os" "path/filepath" + "slices" "sort" "strings" "time" @@ -136,7 +137,7 @@ func (config *Config) GetUniqueExtraMetricLabels() []string { continue } for label := range ep.ExtraLabels { - if contains(labels, label) { + if slices.Contains(labels, label) { continue } labels = append(labels, label) diff --git a/config/config_test.go b/config/config_test.go index 216cd4ec..5abfe8e7 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "slices" "testing" "time" @@ -2052,7 +2053,7 @@ func TestConfig_GetUniqueExtraMetricLabels(t *testing.T) { t.Errorf("expected %d labels, got %d", len(tt.expected), len(labels)) } for _, label := range tt.expected { - if !contains(labels, label) { + if !slices.Contains(labels, label) { t.Errorf("expected label %s to be present", label) } } diff --git a/config/endpoint/condition.go b/config/endpoint/condition.go index 6929fd55..88b36c32 100644 --- a/config/endpoint/condition.go +++ b/config/endpoint/condition.go @@ -216,7 +216,7 @@ func sanitizeAndResolveNumericalWithContext(list []string, result *Result, conte func prettifyNumericalParameters(parameters []string, resolvedParameters []int64, operator string) string { resolvedStrings := make([]string, 2) - for i := 0; i < 2; i++ { + for i := range 2 { // Check if the parameter is a certificate or domain expiration placeholder if parameters[i] == CertificateExpirationPlaceholder || parameters[i] == DomainExpirationPlaceholder { // Format as duration string (convert milliseconds back to duration) diff --git a/config/endpoint/endpoint.go b/config/endpoint/endpoint.go index 91fc712e..0e8c77b7 100644 --- a/config/endpoint/endpoint.go +++ b/config/endpoint/endpoint.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "maps" "math/rand" "net" "net/http" @@ -489,9 +490,7 @@ func (e *Endpoint) call(result *Result) { } else if endpointType == TypeWS { wsHeaders := map[string]string{} if e.Headers != nil { - for k, v := range e.Headers { - wsHeaders[k] = v - } + maps.Copy(wsHeaders, e.Headers) } if !hasHeader(wsHeaders, UserAgentHeader) { wsHeaders[UserAgentHeader] = GatusUserAgent diff --git a/config/endpoint/result.go b/config/endpoint/result.go index e2561f0e..ca3fbdfb 100644 --- a/config/endpoint/result.go +++ b/config/endpoint/result.go @@ -1,6 +1,7 @@ package endpoint import ( + "slices" "time" ) @@ -66,11 +67,7 @@ type Result struct { // AddError adds an error to the result's list of errors. // It also ensures that there are no duplicates. func (r *Result) AddError(error string) { - for _, resultError := range r.Errors { - if resultError == error { - // If the error already exists, don't add it - return - } + if !slices.Contains(r.Errors, error) { + r.Errors = append(r.Errors, error+"") } - r.Errors = append(r.Errors, error+"") } diff --git a/config/gontext/gontext_test.go b/config/gontext/gontext_test.go index a29bbe4d..39628166 100644 --- a/config/gontext/gontext_test.go +++ b/config/gontext/gontext_test.go @@ -340,9 +340,9 @@ func TestGontext_ConcurrentAccess(t *testing.T) { done := make(chan bool, 10) // Start 5 goroutines that read values - for i := 0; i < 5; i++ { + for i := range 5 { go func(id int) { - for j := 0; j < 100; j++ { + for range 100 { _, err := ctx.Get("counter") if err != nil { t.Errorf("Reader %d error: %v", id, err) @@ -353,9 +353,9 @@ func TestGontext_ConcurrentAccess(t *testing.T) { } // Start 5 goroutines that write values - for i := 0; i < 5; i++ { + for i := range 5 { go func(id int) { - for j := 0; j < 100; j++ { + for j := range 100 { err := ctx.Set("counter", id*1000+j) if err != nil { t.Errorf("Writer %d error: %v", id, err) @@ -366,7 +366,7 @@ func TestGontext_ConcurrentAccess(t *testing.T) { } // Wait for all goroutines to complete - for i := 0; i < 10; i++ { + for range 10 { <-done } } diff --git a/config/maintenance/maintenance.go b/config/maintenance/maintenance.go index 5483d607..0e0c50f4 100644 --- a/config/maintenance/maintenance.go +++ b/config/maintenance/maintenance.go @@ -3,6 +3,7 @@ package maintenance import ( "errors" "fmt" + "slices" "strconv" "strings" "time" @@ -70,13 +71,7 @@ func (c *Config) ValidateAndSetDefaults() error { return nil } for _, day := range c.Every { - isDayValid := false - for _, longDayName := range longDayNames { - if day == longDayName { - isDayValid = true - break - } - } + isDayValid := slices.Contains(longDayNames, day) if !isDayValid { return errInvalidDayName } @@ -118,7 +113,7 @@ func (c *Config) IsUnderMaintenance() bool { // Set to midnight prior to adding duration dayWhereMaintenancePeriodWouldStart := time.Date(now.Year(), now.Month(), adjustedDate, 0, 0, 0, 0, now.Location()) hasMaintenanceEveryDay := len(c.Every) == 0 - hasMaintenancePeriodScheduledToStartOnThatWeekday := c.hasDay(dayWhereMaintenancePeriodWouldStart.Weekday().String()) + hasMaintenancePeriodScheduledToStartOnThatWeekday := slices.Contains(c.Every, dayWhereMaintenancePeriodWouldStart.Weekday().String()) if !hasMaintenanceEveryDay && !hasMaintenancePeriodScheduledToStartOnThatWeekday { // The day when the maintenance period would start is not scheduled // to have any maintenance, so we can just return false. @@ -129,15 +124,6 @@ func (c *Config) IsUnderMaintenance() bool { return now.After(startOfMaintenancePeriod) && now.Before(endOfMaintenancePeriod) } -func (c *Config) hasDay(day string) bool { - for _, d := range c.Every { - if d == day { - return true - } - } - return false -} - func hhmmToDuration(s string) (time.Duration, error) { if len(s) != 5 { return 0, errInvalidMaintenanceStartFormat diff --git a/config/tunneling/sshtunnel/sshtunnel.go b/config/tunneling/sshtunnel/sshtunnel.go index 964d5089..1d6f4e5f 100644 --- a/config/tunneling/sshtunnel/sshtunnel.go +++ b/config/tunneling/sshtunnel/sshtunnel.go @@ -133,7 +133,7 @@ func (t *SSHTunnel) Dial(network, addr string) (net.Conn, error) { const maxRetries = 3 const baseDelay = 500 * time.Millisecond var lastErr error - for attempt := 0; attempt < maxRetries; attempt++ { + for attempt := range maxRetries { if attempt > 0 { // Exponential backoff: 500ms, 1s, 2s delay := baseDelay << (attempt - 1) diff --git a/config/util.go b/config/util.go index cffeaf0f..280212a9 100644 --- a/config/util.go +++ b/config/util.go @@ -4,13 +4,3 @@ package config func toPtr[T any](value T) *T { return &value } - -// contains checks if a key exists in the slice -func contains[T comparable](slice []T, key T) bool { - for _, item := range slice { - if item == key { - return true - } - } - return false -} diff --git a/storage/store/memory/memory.go b/storage/store/memory/memory.go index 79f4e505..edf5d7c3 100644 --- a/storage/store/memory/memory.go +++ b/storage/store/memory/memory.go @@ -1,6 +1,7 @@ package memory import ( + "slices" "sort" "sync" "time" @@ -237,13 +238,7 @@ func (s *Store) InsertSuiteResult(su *suite.Suite, result *suite.Result) error { func (s *Store) DeleteAllEndpointStatusesNotInKeys(keys []string) int { var keysToDelete []string for _, existingKey := range s.endpointCache.GetKeysByPattern("*", 0) { - shouldDelete := true - for _, k := range keys { - if existingKey == k { - shouldDelete = false - break - } - } + shouldDelete := !slices.Contains(keys, existingKey) if shouldDelete { keysToDelete = append(keysToDelete, existingKey) } diff --git a/storage/store/memory/memory_test.go b/storage/store/memory/memory_test.go index 7a1176c1..e5353e9d 100644 --- a/storage/store/memory/memory_test.go +++ b/storage/store/memory/memory_test.go @@ -797,7 +797,7 @@ func TestSuiteResultOrdering(t *testing.T) { baseTime := time.Now().Add(-5 * time.Hour) timestamps := make([]time.Time, 5) - for i := 0; i < 5; i++ { + for i := range 5 { timestamp := baseTime.Add(time.Duration(i) * time.Hour) timestamps[i] = timestamp result := &suite.Result{ @@ -878,7 +878,7 @@ func TestSuiteResultOrdering(t *testing.T) { smallSuite := &suite.Suite{Name: "small-suite", Group: "test"} // Insert 6 results, should keep only the newest 3 - for i := 0; i < 6; i++ { + for i := range 6 { result := &suite.Result{ Name: smallSuite.Name, Group: smallSuite.Group, @@ -925,7 +925,7 @@ func TestStore_ConcurrentAccess(t *testing.T) { // Create endpoints for concurrent testing endpoints := make([]*endpoint.Endpoint, numGoroutines) - for i := 0; i < numGoroutines; i++ { + for i := range numGoroutines { endpoints[i] = &endpoint.Endpoint{ Name: "endpoint-" + string(rune('A'+i)), Group: "concurrent", @@ -934,12 +934,12 @@ func TestStore_ConcurrentAccess(t *testing.T) { } // Concurrently insert results for different endpoints - for i := 0; i < numGoroutines; i++ { + for i := range numGoroutines { wg.Add(1) go func(endpointIndex int) { defer wg.Done() ep := endpoints[endpointIndex] - for j := 0; j < resultsPerGoroutine; j++ { + for j := range resultsPerGoroutine { result := &endpoint.Result{ Success: j%2 == 0, Timestamp: time.Now().Add(time.Duration(j) * time.Minute), @@ -978,7 +978,7 @@ func TestStore_ConcurrentAccess(t *testing.T) { // Create suites for concurrent testing suites := make([]*suite.Suite, numGoroutines) - for i := 0; i < numGoroutines; i++ { + for i := range numGoroutines { suites[i] = &suite.Suite{ Name: "suite-" + string(rune('A'+i)), Group: "concurrent", @@ -986,12 +986,12 @@ func TestStore_ConcurrentAccess(t *testing.T) { } // Concurrently insert results for different suites - for i := 0; i < numGoroutines; i++ { + for i := range numGoroutines { wg.Add(1) go func(suiteIndex int) { defer wg.Done() su := suites[suiteIndex] - for j := 0; j < resultsPerGoroutine; j++ { + for j := range resultsPerGoroutine { result := &suite.Result{ Name: su.Name, Group: su.Group, @@ -1036,7 +1036,7 @@ func TestStore_ConcurrentAccess(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - for i := 0; i < 5; i++ { + for i := range 5 { result := &endpoint.Result{ Success: true, Timestamp: time.Now(), @@ -1050,7 +1050,7 @@ func TestStore_ConcurrentAccess(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - for i := 0; i < 5; i++ { + for i := range 5 { result := &suite.Result{ Name: testSuite.Name, Group: testSuite.Group, @@ -1066,7 +1066,7 @@ func TestStore_ConcurrentAccess(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - for i := 0; i < 10; i++ { + for range 10 { store.GetAllEndpointStatuses(&paging.EndpointStatusParams{}) store.GetAllSuiteStatuses(&paging.SuiteStatusParams{}) time.Sleep(1 * time.Millisecond) diff --git a/storage/store/memory/util_bench_test.go b/storage/store/memory/util_bench_test.go index d8f1d26a..2a81f4e6 100644 --- a/storage/store/memory/util_bench_test.go +++ b/storage/store/memory/util_bench_test.go @@ -11,10 +11,10 @@ import ( func BenchmarkShallowCopyEndpointStatus(b *testing.B) { ep := &testEndpoint status := endpoint.NewStatus(ep.Group, ep.Name) - for i := 0; i < storage.DefaultMaximumNumberOfResults; i++ { + for range storage.DefaultMaximumNumberOfResults { AddResult(status, &testSuccessfulResult, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) } - for n := 0; n < b.N; n++ { + for b.Loop() { ShallowCopyEndpointStatus(status, paging.NewEndpointStatusParams().WithResults(1, 20)) } b.ReportAllocs() diff --git a/storage/store/memory/util_test.go b/storage/store/memory/util_test.go index 927ca937..dd09d5b4 100644 --- a/storage/store/memory/util_test.go +++ b/storage/store/memory/util_test.go @@ -13,7 +13,7 @@ import ( func TestAddResult(t *testing.T) { ep := &endpoint.Endpoint{Name: "name", Group: "group"} endpointStatus := endpoint.NewStatus(ep.Group, ep.Name) - for i := 0; i < (storage.DefaultMaximumNumberOfResults+storage.DefaultMaximumNumberOfEvents)*2; i++ { + for i := range (storage.DefaultMaximumNumberOfResults + storage.DefaultMaximumNumberOfEvents) * 2 { AddResult(endpointStatus, &endpoint.Result{Success: i%2 == 0, Timestamp: time.Now()}, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) } if len(endpointStatus.Results) != storage.DefaultMaximumNumberOfResults { @@ -30,7 +30,7 @@ func TestShallowCopyEndpointStatus(t *testing.T) { ep := &endpoint.Endpoint{Name: "name", Group: "group"} endpointStatus := endpoint.NewStatus(ep.Group, ep.Name) ts := time.Now().Add(-25 * time.Hour) - for i := 0; i < 25; i++ { + for i := range 25 { AddResult(endpointStatus, &endpoint.Result{Success: i%2 == 0, Timestamp: ts}, storage.DefaultMaximumNumberOfResults, storage.DefaultMaximumNumberOfEvents) ts = ts.Add(time.Hour) } @@ -74,9 +74,9 @@ func TestShallowCopySuiteStatus(t *testing.T) { Key: testSuite.Key(), Results: []*suite.Result{}, } - + ts := time.Now().Add(-25 * time.Hour) - for i := 0; i < 25; i++ { + for i := range 25 { result := &suite.Result{ Name: testSuite.Name, Group: testSuite.Group, @@ -169,4 +169,3 @@ func TestShallowCopySuiteStatus(t *testing.T) { } }) } - diff --git a/storage/store/sql/sql_test.go b/storage/store/sql/sql_test.go index 9cbaf492..b776f7a5 100644 --- a/storage/store/sql/sql_test.go +++ b/storage/store/sql/sql_test.go @@ -900,7 +900,7 @@ func TestEventOrderingFix(t *testing.T) { } // Create many events over time baseTime := time.Now().Add(-100 * time.Hour) // Start 100 hours ago - for i := 0; i < 50; i++ { + for i := range 50 { result := &endpoint.Result{ Success: i%2 == 0, // Alternate between true/false to create events Timestamp: baseTime.Add(time.Duration(i) * time.Hour), diff --git a/storage/store/store_bench_test.go b/storage/store/store_bench_test.go index c3f53f75..d02f715e 100644 --- a/storage/store/store_bench_test.go +++ b/storage/store/store_bench_test.go @@ -53,11 +53,11 @@ func BenchmarkStore_GetAllEndpointStatuses(b *testing.B) { numberOfEndpoints := []int{10, 25, 50, 100} for _, numberOfEndpointsToCreate := range numberOfEndpoints { // Create endpoints and insert results - for i := 0; i < numberOfEndpointsToCreate; i++ { + for i := range numberOfEndpointsToCreate { ep := testEndpoint ep.Name = "endpoint" + strconv.Itoa(i) // InsertEndpointResult 20 results for each endpoint - for j := 0; j < 20; j++ { + for range 20 { scenario.Store.InsertEndpointResult(&ep, &testSuccessfulResult) } } @@ -191,7 +191,7 @@ func BenchmarkStore_GetEndpointStatusByKey(b *testing.B) { }, } for _, scenario := range scenarios { - for i := 0; i < 50; i++ { + for range 50 { scenario.Store.InsertEndpointResult(&testEndpoint, &testSuccessfulResult) scenario.Store.InsertEndpointResult(&testEndpoint, &testUnsuccessfulResult) }