mirror of
				https://github.com/redis/go-redis.git
				synced 2025-11-04 02:33:24 +03:00 
			
		
		
		
	* all: Refactor tests for idiomatic Go and minor improvements
Replaced redundant 'for key, _' with 'for key' in map iterations for clarity in doctests/cmds_hash_test.go. Updated time measurement from time.Now().Sub to time.Since in hset_benchmark_test.go for idiomatic Go usage. Simplified variadic argument types from interface{} to any and removed unused min function in maintnotifications/e2e/utils_test.go.
* maintnotifications/e2e/utils_test: Update variadic args type in printLog function
Changed the variadic argument type in printLog from 'any' to 'interface{}' for compatibility and consistency with standard Go practices.
		
	
		
			
				
	
	
		
			246 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			246 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package redis_test
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/redis/go-redis/v9"
 | 
						|
)
 | 
						|
 | 
						|
// HSET Benchmark Tests
 | 
						|
//
 | 
						|
// This file contains benchmark tests for Redis HSET operations with different scales:
 | 
						|
// 1, 10, 100, 1000, 10000, 100000 operations
 | 
						|
//
 | 
						|
// Prerequisites:
 | 
						|
// - Redis server running on localhost:6379
 | 
						|
// - No authentication required
 | 
						|
//
 | 
						|
// Usage:
 | 
						|
//   go test -bench=BenchmarkHSET -v ./hset_benchmark_test.go
 | 
						|
//   go test -bench=BenchmarkHSETPipelined -v ./hset_benchmark_test.go
 | 
						|
//   go test -bench=. -v ./hset_benchmark_test.go  # Run all benchmarks
 | 
						|
//
 | 
						|
// Example output:
 | 
						|
//   BenchmarkHSET/HSET_1_operations-8         	    5000	    250000 ns/op	1000000.00 ops/sec
 | 
						|
//   BenchmarkHSET/HSET_100_operations-8       	     100	  10000000 ns/op	 100000.00 ops/sec
 | 
						|
//
 | 
						|
// The benchmarks test three different approaches:
 | 
						|
// 1. Individual HSET commands (BenchmarkHSET)
 | 
						|
// 2. Pipelined HSET commands (BenchmarkHSETPipelined)
 | 
						|
 | 
						|
// BenchmarkHSET benchmarks HSET operations with different scales
 | 
						|
func BenchmarkHSET(b *testing.B) {
 | 
						|
	ctx := context.Background()
 | 
						|
 | 
						|
	// Setup Redis client
 | 
						|
	rdb := redis.NewClient(&redis.Options{
 | 
						|
		Addr: "localhost:6379",
 | 
						|
		DB:   0,
 | 
						|
	})
 | 
						|
	defer rdb.Close()
 | 
						|
 | 
						|
	// Test connection
 | 
						|
	if err := rdb.Ping(ctx).Err(); err != nil {
 | 
						|
		b.Skipf("Redis server not available: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Clean up before and after tests
 | 
						|
	defer func() {
 | 
						|
		rdb.FlushDB(ctx)
 | 
						|
	}()
 | 
						|
 | 
						|
	scales := []int{1, 10, 100, 1000, 10000, 100000}
 | 
						|
 | 
						|
	for _, scale := range scales {
 | 
						|
		b.Run(fmt.Sprintf("HSET_%d_operations", scale), func(b *testing.B) {
 | 
						|
			benchmarkHSETOperations(b, rdb, ctx, scale)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// benchmarkHSETOperations performs the actual HSET benchmark for a given scale
 | 
						|
func benchmarkHSETOperations(b *testing.B, rdb *redis.Client, ctx context.Context, operations int) {
 | 
						|
	hashKey := fmt.Sprintf("benchmark_hash_%d", operations)
 | 
						|
 | 
						|
	b.ResetTimer()
 | 
						|
	b.StartTimer()
 | 
						|
	totalTimes := []time.Duration{}
 | 
						|
 | 
						|
	for i := 0; i < b.N; i++ {
 | 
						|
		b.StopTimer()
 | 
						|
		// Clean up the hash before each iteration
 | 
						|
		rdb.Del(ctx, hashKey)
 | 
						|
		b.StartTimer()
 | 
						|
 | 
						|
		startTime := time.Now()
 | 
						|
		// Perform the specified number of HSET operations
 | 
						|
		for j := 0; j < operations; j++ {
 | 
						|
			field := fmt.Sprintf("field_%d", j)
 | 
						|
			value := fmt.Sprintf("value_%d", j)
 | 
						|
 | 
						|
			err := rdb.HSet(ctx, hashKey, field, value).Err()
 | 
						|
			if err != nil {
 | 
						|
				b.Fatalf("HSET operation failed: %v", err)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		totalTimes = append(totalTimes, time.Since(startTime))
 | 
						|
	}
 | 
						|
 | 
						|
	// Stop the timer to calculate metrics
 | 
						|
	b.StopTimer()
 | 
						|
 | 
						|
	// Report operations per second
 | 
						|
	opsPerSec := float64(operations*b.N) / b.Elapsed().Seconds()
 | 
						|
	b.ReportMetric(opsPerSec, "ops/sec")
 | 
						|
 | 
						|
	// Report average time per operation
 | 
						|
	avgTimePerOp := b.Elapsed().Nanoseconds() / int64(operations*b.N)
 | 
						|
	b.ReportMetric(float64(avgTimePerOp), "ns/op")
 | 
						|
	// report average time in milliseconds from totalTimes
 | 
						|
	avgTimePerOpMs := totalTimes[0].Milliseconds() / int64(len(totalTimes))
 | 
						|
	b.ReportMetric(float64(avgTimePerOpMs), "ms")
 | 
						|
}
 | 
						|
 | 
						|
// BenchmarkHSETPipelined benchmarks HSET operations using pipelining for better performance
 | 
						|
func BenchmarkHSETPipelined(b *testing.B) {
 | 
						|
	ctx := context.Background()
 | 
						|
 | 
						|
	// Setup Redis client
 | 
						|
	rdb := redis.NewClient(&redis.Options{
 | 
						|
		Addr: "localhost:6379",
 | 
						|
		DB:   0,
 | 
						|
	})
 | 
						|
	defer rdb.Close()
 | 
						|
 | 
						|
	// Test connection
 | 
						|
	if err := rdb.Ping(ctx).Err(); err != nil {
 | 
						|
		b.Skipf("Redis server not available: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Clean up before and after tests
 | 
						|
	defer func() {
 | 
						|
		rdb.FlushDB(ctx)
 | 
						|
	}()
 | 
						|
 | 
						|
	scales := []int{1, 10, 100, 1000, 10000, 100000}
 | 
						|
 | 
						|
	for _, scale := range scales {
 | 
						|
		b.Run(fmt.Sprintf("HSET_Pipelined_%d_operations", scale), func(b *testing.B) {
 | 
						|
			benchmarkHSETPipelined(b, rdb, ctx, scale)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// benchmarkHSETPipelined performs HSET benchmark using pipelining
 | 
						|
func benchmarkHSETPipelined(b *testing.B, rdb *redis.Client, ctx context.Context, operations int) {
 | 
						|
	hashKey := fmt.Sprintf("benchmark_hash_pipelined_%d", operations)
 | 
						|
 | 
						|
	b.ResetTimer()
 | 
						|
	b.StartTimer()
 | 
						|
	totalTimes := []time.Duration{}
 | 
						|
 | 
						|
	for i := 0; i < b.N; i++ {
 | 
						|
		b.StopTimer()
 | 
						|
		// Clean up the hash before each iteration
 | 
						|
		rdb.Del(ctx, hashKey)
 | 
						|
		b.StartTimer()
 | 
						|
 | 
						|
		startTime := time.Now()
 | 
						|
		// Use pipelining for better performance
 | 
						|
		pipe := rdb.Pipeline()
 | 
						|
 | 
						|
		// Add all HSET operations to the pipeline
 | 
						|
		for j := 0; j < operations; j++ {
 | 
						|
			field := fmt.Sprintf("field_%d", j)
 | 
						|
			value := fmt.Sprintf("value_%d", j)
 | 
						|
			pipe.HSet(ctx, hashKey, field, value)
 | 
						|
		}
 | 
						|
 | 
						|
		// Execute all operations at once
 | 
						|
		_, err := pipe.Exec(ctx)
 | 
						|
		if err != nil {
 | 
						|
			b.Fatalf("Pipeline execution failed: %v", err)
 | 
						|
		}
 | 
						|
		totalTimes = append(totalTimes, time.Since(startTime))
 | 
						|
	}
 | 
						|
 | 
						|
	b.StopTimer()
 | 
						|
 | 
						|
	// Report operations per second
 | 
						|
	opsPerSec := float64(operations*b.N) / b.Elapsed().Seconds()
 | 
						|
	b.ReportMetric(opsPerSec, "ops/sec")
 | 
						|
 | 
						|
	// Report average time per operation
 | 
						|
	avgTimePerOp := b.Elapsed().Nanoseconds() / int64(operations*b.N)
 | 
						|
	b.ReportMetric(float64(avgTimePerOp), "ns/op")
 | 
						|
	// report average time in milliseconds from totalTimes
 | 
						|
	avgTimePerOpMs := totalTimes[0].Milliseconds() / int64(len(totalTimes))
 | 
						|
	b.ReportMetric(float64(avgTimePerOpMs), "ms")
 | 
						|
}
 | 
						|
 | 
						|
// add same tests but with RESP2
 | 
						|
func BenchmarkHSET_RESP2(b *testing.B) {
 | 
						|
	ctx := context.Background()
 | 
						|
 | 
						|
	// Setup Redis client
 | 
						|
	rdb := redis.NewClient(&redis.Options{
 | 
						|
		Addr:     "localhost:6379",
 | 
						|
		Password: "", // no password docs
 | 
						|
		DB:       0,  // use default DB
 | 
						|
		Protocol: 2,
 | 
						|
	})
 | 
						|
	defer rdb.Close()
 | 
						|
 | 
						|
	// Test connection
 | 
						|
	if err := rdb.Ping(ctx).Err(); err != nil {
 | 
						|
		b.Skipf("Redis server not available: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Clean up before and after tests
 | 
						|
	defer func() {
 | 
						|
		rdb.FlushDB(ctx)
 | 
						|
	}()
 | 
						|
 | 
						|
	scales := []int{1, 10, 100, 1000, 10000, 100000}
 | 
						|
 | 
						|
	for _, scale := range scales {
 | 
						|
		b.Run(fmt.Sprintf("HSET_RESP2_%d_operations", scale), func(b *testing.B) {
 | 
						|
			benchmarkHSETOperations(b, rdb, ctx, scale)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkHSETPipelined_RESP2(b *testing.B) {
 | 
						|
	ctx := context.Background()
 | 
						|
 | 
						|
	// Setup Redis client
 | 
						|
	rdb := redis.NewClient(&redis.Options{
 | 
						|
		Addr:     "localhost:6379",
 | 
						|
		Password: "", // no password docs
 | 
						|
		DB:       0,  // use default DB
 | 
						|
		Protocol: 2,
 | 
						|
	})
 | 
						|
	defer rdb.Close()
 | 
						|
 | 
						|
	// Test connection
 | 
						|
	if err := rdb.Ping(ctx).Err(); err != nil {
 | 
						|
		b.Skipf("Redis server not available: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Clean up before and after tests
 | 
						|
	defer func() {
 | 
						|
		rdb.FlushDB(ctx)
 | 
						|
	}()
 | 
						|
 | 
						|
	scales := []int{1, 10, 100, 1000, 10000, 100000}
 | 
						|
 | 
						|
	for _, scale := range scales {
 | 
						|
		b.Run(fmt.Sprintf("HSET_Pipelined_RESP2_%d_operations", scale), func(b *testing.B) {
 | 
						|
			benchmarkHSETPipelined(b, rdb, ctx, scale)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |