From 0a2d95652fad311f313b7e63c860544cc5c2fda1 Mon Sep 17 00:00:00 2001 From: atridadl Date: Wed, 17 Jan 2024 00:56:04 -0700 Subject: [PATCH] Tests --- lib/metrics.go | 49 +++++++++++------------------ lib/metrics_test.go | 73 ++++++++++++++++++++++++++++++++++++++++++++ lib/requests.go | 6 +--- lib/requests_test.go | 50 ++++++++++++++++++++++++++++++ lib/types.go | 23 ++++++++++++++ 5 files changed, 165 insertions(+), 36 deletions(-) create mode 100644 lib/metrics_test.go create mode 100644 lib/requests_test.go create mode 100644 lib/types.go diff --git a/lib/metrics.go b/lib/metrics.go index e5ab394..7c7b044 100644 --- a/lib/metrics.go +++ b/lib/metrics.go @@ -6,57 +6,44 @@ import ( "net/http" "os" "path/filepath" - "sync" "time" ) -// PerformanceMetrics holds the metrics for performance evaluation. -type PerformanceMetrics struct { - mu sync.Mutex // Protects the metrics - - totalRequests int32 - totalResponses int32 - totalLatency time.Duration - maxLatency time.Duration - minLatency time.Duration - responseCounters map[int]int32 -} - // Initialize the metrics with default values. var metrics = PerformanceMetrics{ - minLatency: time.Duration(math.MaxInt64), - responseCounters: make(map[int]int32), + MinLatency: time.Duration(math.MaxInt64), + ResponseCounters: make(map[int]int32), } // updateMetrics updates the performance metrics. func UpdateMetrics(duration time.Duration, resp *http.Response, second int) { - metrics.mu.Lock() - defer metrics.mu.Unlock() + metrics.Mu.Lock() + defer metrics.Mu.Unlock() - metrics.totalRequests++ - metrics.totalLatency += duration - if duration > metrics.maxLatency { - metrics.maxLatency = duration + metrics.TotalRequests++ + metrics.TotalLatency += duration + if duration > metrics.MaxLatency { + metrics.MaxLatency = duration } - if duration < metrics.minLatency { - metrics.minLatency = duration + if duration < metrics.MinLatency { + metrics.MinLatency = duration } if resp.StatusCode == http.StatusOK { - metrics.totalResponses++ - metrics.responseCounters[second]++ + metrics.TotalResponses++ + metrics.ResponseCounters[second]++ } } // calculateAndPrintMetrics calculates and prints the performance metrics. func CalculateAndPrintMetrics(startTime time.Time, requestsPerSecond float64, endpoint string, verb string) { averageLatency := time.Duration(0) - if metrics.totalRequests > 0 { - averageLatency = metrics.totalLatency / time.Duration(metrics.totalRequests) + if metrics.TotalRequests > 0 { + averageLatency = metrics.TotalLatency / time.Duration(metrics.TotalRequests) } totalDuration := time.Since(startTime).Seconds() totalResponses := int32(0) - for _, count := range metrics.responseCounters { + for _, count := range metrics.ResponseCounters { totalResponses += count } @@ -65,11 +52,11 @@ func CalculateAndPrintMetrics(startTime time.Time, requestsPerSecond float64, en results += fmt.Sprintf("HTTP Verb: %s\n", verb) results += fmt.Sprintln("--------------------") results += fmt.Sprintln("Performance Metrics:") - results += fmt.Sprintf("Total Requests Sent: %d\n", metrics.totalRequests) + results += fmt.Sprintf("Total Requests Sent: %d\n", metrics.TotalRequests) results += fmt.Sprintf("Total Responses Received: %d\n", totalResponses) results += fmt.Sprintf("Average Latency: %s\n", averageLatency) - results += fmt.Sprintf("Max Latency: %s\n", metrics.maxLatency) - results += fmt.Sprintf("Min Latency: %s\n", metrics.minLatency) + results += fmt.Sprintf("Max Latency: %s\n", metrics.MaxLatency) + results += fmt.Sprintf("Min Latency: %s\n", metrics.MinLatency) results += fmt.Sprintf("Requests Per Second (Sent): %.2f\n", float64(requestsPerSecond)) results += fmt.Sprintf("Responses Per Second (Received): %.2f\n", float64(totalResponses)/totalDuration) diff --git a/lib/metrics_test.go b/lib/metrics_test.go new file mode 100644 index 0000000..0838eef --- /dev/null +++ b/lib/metrics_test.go @@ -0,0 +1,73 @@ +package lib_test + +import ( + "loadr/lib" + "reflect" + "testing" + "time" +) + +func comparePerformanceMetrics(a, b *lib.PerformanceMetrics) bool { + return a.TotalRequests == b.TotalRequests && + a.TotalResponses == b.TotalResponses && + a.TotalLatency == b.TotalLatency && + a.MaxLatency == b.MaxLatency && + a.MinLatency == b.MinLatency && + reflect.DeepEqual(a.ResponseCounters, b.ResponseCounters) +} + +func TestCalculateAndPrintMetrics(t *testing.T) { + // Define test cases. + tests := []struct { + name string + startTime time.Time + requestsPerSecond float64 + endpoint string + verb string + expectedMetrics lib.PerformanceMetrics + }{ + { + name: "Test 1", + startTime: time.Now().Add(-1 * time.Second), // 1 second ago + requestsPerSecond: 1.0, + endpoint: "http://localhost", + verb: "GET", + expectedMetrics: lib.PerformanceMetrics{ + TotalRequests: 1, + TotalResponses: 1, + TotalLatency: 1 * time.Second, + MaxLatency: 1 * time.Second, + MinLatency: 1 * time.Second, + ResponseCounters: map[int]int32{1: 1}, + }, + }, + // Add more test cases as needed. + } + + for i := range tests { + tt := &tests[i] + t.Run(tt.name, func(t *testing.T) { + // Reset the metrics before each test + metrics := lib.PerformanceMetrics{} + + // Mock the system behavior + metrics.TotalRequests++ + metrics.ResponseCounters = make(map[int]int32) + metrics.TotalResponses++ + metrics.TotalLatency += 1 * time.Second + metrics.MaxLatency = 1 * time.Second + metrics.MinLatency = 1 * time.Second + metrics.ResponseCounters[1]++ + + // Call the function + lib.CalculateAndPrintMetrics(tt.startTime, tt.requestsPerSecond, tt.endpoint, tt.verb) + + // Check if the metrics are correct + if !comparePerformanceMetrics(&metrics, &tt.expectedMetrics) { + t.Errorf("CalculateAndPrintMetrics() = TotalRequests: %v, TotalResponses: %v, TotalLatency: %v, MaxLatency: %v, MinLatency: %v, ResponseCounters: %v, want TotalRequests: %v, TotalResponses: %v, TotalLatency: %v, MaxLatency: %v, MinLatency: %v, ResponseCounters: %v", + metrics.TotalRequests, metrics.TotalResponses, metrics.TotalLatency, metrics.MaxLatency, metrics.MinLatency, metrics.ResponseCounters, + tt.expectedMetrics.TotalRequests, tt.expectedMetrics.TotalResponses, tt.expectedMetrics.TotalLatency, tt.expectedMetrics.MaxLatency, tt.expectedMetrics.MinLatency, tt.expectedMetrics.ResponseCounters) + } + }) + } +} diff --git a/lib/requests.go b/lib/requests.go index 7271fef..38c14d5 100644 --- a/lib/requests.go +++ b/lib/requests.go @@ -13,11 +13,7 @@ import ( // Global HTTP client used for making requests. var client = &http.Client{} -type RequestError struct { - Verb string - URL string - Err error -} + func (e *RequestError) Error() string { return fmt.Sprintf("error making %s request to %s: %v", e.Verb, e.URL, e.Err) diff --git a/lib/requests_test.go b/lib/requests_test.go new file mode 100644 index 0000000..333e003 --- /dev/null +++ b/lib/requests_test.go @@ -0,0 +1,50 @@ +package lib_test + +import ( + "loadr/lib" + "net/http" + "net/http/httptest" + "testing" + "time" +) + +func TestSendRequests(t *testing.T) { + // Create a test server that responds with a 200 status. + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + defer ts.Close() + + tests := []struct { + name string + url string + bearerToken string + requestType string + jsonData []byte + maxRequests int + requestsPerSecond float64 + }{ + { + name: "Test 1", + url: ts.URL, + bearerToken: "testToken", + requestType: "GET", + jsonData: []byte(`{"key":"value"}`), + maxRequests: 5, + requestsPerSecond: 1.0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + start := time.Now() + lib.SendRequests(tt.url, tt.bearerToken, tt.requestType, tt.jsonData, tt.maxRequests, tt.requestsPerSecond) + elapsed := time.Since(start) + + // Check if the requests were sent within the expected time frame. + if elapsed > time.Duration(float64(tt.maxRequests)*1.5)*time.Second { + t.Errorf("SendRequests() took too long, got: %v, want: less than %v", elapsed, time.Duration(float64(tt.maxRequests)*1.5)*time.Second) + } + }) + } +} diff --git a/lib/types.go b/lib/types.go new file mode 100644 index 0000000..66f5738 --- /dev/null +++ b/lib/types.go @@ -0,0 +1,23 @@ +package lib + +import ( + "sync" + "time" +) + +// PerformanceMetrics holds the metrics for performance evaluation. +type PerformanceMetrics struct { + Mu sync.Mutex // Protects the metrics + TotalRequests int32 + TotalResponses int32 + TotalLatency time.Duration + MaxLatency time.Duration + MinLatency time.Duration + ResponseCounters map[int]int32 +} + +type RequestError struct { + Verb string + URL string + Err error +}