Tests
This commit is contained in:
parent
c888c47742
commit
0a2d95652f
5 changed files with 165 additions and 36 deletions
|
@ -6,57 +6,44 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
"time"
|
"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.
|
// Initialize the metrics with default values.
|
||||||
var metrics = PerformanceMetrics{
|
var metrics = PerformanceMetrics{
|
||||||
minLatency: time.Duration(math.MaxInt64),
|
MinLatency: time.Duration(math.MaxInt64),
|
||||||
responseCounters: make(map[int]int32),
|
ResponseCounters: make(map[int]int32),
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateMetrics updates the performance metrics.
|
// updateMetrics updates the performance metrics.
|
||||||
func UpdateMetrics(duration time.Duration, resp *http.Response, second int) {
|
func UpdateMetrics(duration time.Duration, resp *http.Response, second int) {
|
||||||
metrics.mu.Lock()
|
metrics.Mu.Lock()
|
||||||
defer metrics.mu.Unlock()
|
defer metrics.Mu.Unlock()
|
||||||
|
|
||||||
metrics.totalRequests++
|
metrics.TotalRequests++
|
||||||
metrics.totalLatency += duration
|
metrics.TotalLatency += duration
|
||||||
if duration > metrics.maxLatency {
|
if duration > metrics.MaxLatency {
|
||||||
metrics.maxLatency = duration
|
metrics.MaxLatency = duration
|
||||||
}
|
}
|
||||||
if duration < metrics.minLatency {
|
if duration < metrics.MinLatency {
|
||||||
metrics.minLatency = duration
|
metrics.MinLatency = duration
|
||||||
}
|
}
|
||||||
if resp.StatusCode == http.StatusOK {
|
if resp.StatusCode == http.StatusOK {
|
||||||
metrics.totalResponses++
|
metrics.TotalResponses++
|
||||||
metrics.responseCounters[second]++
|
metrics.ResponseCounters[second]++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateAndPrintMetrics calculates and prints the performance metrics.
|
// calculateAndPrintMetrics calculates and prints the performance metrics.
|
||||||
func CalculateAndPrintMetrics(startTime time.Time, requestsPerSecond float64, endpoint string, verb string) {
|
func CalculateAndPrintMetrics(startTime time.Time, requestsPerSecond float64, endpoint string, verb string) {
|
||||||
averageLatency := time.Duration(0)
|
averageLatency := time.Duration(0)
|
||||||
if metrics.totalRequests > 0 {
|
if metrics.TotalRequests > 0 {
|
||||||
averageLatency = metrics.totalLatency / time.Duration(metrics.totalRequests)
|
averageLatency = metrics.TotalLatency / time.Duration(metrics.TotalRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
totalDuration := time.Since(startTime).Seconds()
|
totalDuration := time.Since(startTime).Seconds()
|
||||||
totalResponses := int32(0)
|
totalResponses := int32(0)
|
||||||
for _, count := range metrics.responseCounters {
|
for _, count := range metrics.ResponseCounters {
|
||||||
totalResponses += count
|
totalResponses += count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,11 +52,11 @@ func CalculateAndPrintMetrics(startTime time.Time, requestsPerSecond float64, en
|
||||||
results += fmt.Sprintf("HTTP Verb: %s\n", verb)
|
results += fmt.Sprintf("HTTP Verb: %s\n", verb)
|
||||||
results += fmt.Sprintln("--------------------")
|
results += fmt.Sprintln("--------------------")
|
||||||
results += fmt.Sprintln("Performance Metrics:")
|
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("Total Responses Received: %d\n", totalResponses)
|
||||||
results += fmt.Sprintf("Average Latency: %s\n", averageLatency)
|
results += fmt.Sprintf("Average Latency: %s\n", averageLatency)
|
||||||
results += fmt.Sprintf("Max Latency: %s\n", metrics.maxLatency)
|
results += fmt.Sprintf("Max Latency: %s\n", metrics.MaxLatency)
|
||||||
results += fmt.Sprintf("Min Latency: %s\n", metrics.minLatency)
|
results += fmt.Sprintf("Min Latency: %s\n", metrics.MinLatency)
|
||||||
results += fmt.Sprintf("Requests Per Second (Sent): %.2f\n", float64(requestsPerSecond))
|
results += fmt.Sprintf("Requests Per Second (Sent): %.2f\n", float64(requestsPerSecond))
|
||||||
results += fmt.Sprintf("Responses Per Second (Received): %.2f\n", float64(totalResponses)/totalDuration)
|
results += fmt.Sprintf("Responses Per Second (Received): %.2f\n", float64(totalResponses)/totalDuration)
|
||||||
|
|
||||||
|
|
73
lib/metrics_test.go
Normal file
73
lib/metrics_test.go
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,11 +13,7 @@ import (
|
||||||
// Global HTTP client used for making requests.
|
// Global HTTP client used for making requests.
|
||||||
var client = &http.Client{}
|
var client = &http.Client{}
|
||||||
|
|
||||||
type RequestError struct {
|
|
||||||
Verb string
|
|
||||||
URL string
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *RequestError) Error() string {
|
func (e *RequestError) Error() string {
|
||||||
return fmt.Sprintf("error making %s request to %s: %v", e.Verb, e.URL, e.Err)
|
return fmt.Sprintf("error making %s request to %s: %v", e.Verb, e.URL, e.Err)
|
||||||
|
|
50
lib/requests_test.go
Normal file
50
lib/requests_test.go
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
23
lib/types.go
Normal file
23
lib/types.go
Normal file
|
@ -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
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue