From 7730b39b0f0e2d4b4d72d937cbcea0352c87791280bc0208c8ac18aa6ad5685c Mon Sep 17 00:00:00 2001 From: Nitesh Date: Tue, 27 Jan 2026 19:20:00 +0530 Subject: [PATCH] obs-status-service: add --test-run using interface-based Redis mock (fixes #113) --- obs-status-service/main.go | 10 +++++-- obs-status-service/redis.go | 7 ++++- obs-status-service/redismock.go | 53 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 obs-status-service/redismock.go diff --git a/obs-status-service/main.go b/obs-status-service/main.go index 80446fe..67fe8f1 100644 --- a/obs-status-service/main.go +++ b/obs-status-service/main.go @@ -243,16 +243,20 @@ func main() { disableTls := flag.Bool("no-tls", false, "Disable TLS") ObsUrl = flag.String("obs-url", obsUrlDef, "OBS API endpoint for package buildlog information") debug := flag.Bool("debug", false, "Enable debug logging") + testRun := flag.Bool("test-run", false, "Run service in test mode without Redis") flag.Parse() if *debug { common.SetLoggingLevel(common.LogLevelDebug) } - if redisUrl := os.Getenv("REDIS"); len(redisUrl) > 0 { - RedisConnect(redisUrl) + if *testRun { + redisClient = &MockRedisClient{} + common.LogInfo("Running in TEST MODE (mock Redis)") + } else if redisURL := os.Getenv("REDIS"); redisURL != "" { + RedisConnect(redisURL) } else { - common.LogError("REDIS needs to contains URL of the OBS Redis instance with login information") + common.LogError("REDIS environment variable is required unless --test-run is used") return } diff --git a/obs-status-service/redis.go b/obs-status-service/redis.go index 89daf0c..45b55fa 100644 --- a/obs-status-service/redis.go +++ b/obs-status-service/redis.go @@ -11,10 +11,15 @@ import ( "src.opensuse.org/autogits/common" ) +type RedisClient interface { + HGetAll(ctx context.Context, key string) *redis.MapStringStringCmd + ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *redis.ScanCmd +} + var RepoStatus []*common.BuildResult = []*common.BuildResult{} var RepoStatusLock *sync.RWMutex = &sync.RWMutex{} -var redisClient *redis.Client +var redisClient RedisClient func RedisConnect(RedisUrl string) { opts, err := redis.ParseURL(RedisUrl) diff --git a/obs-status-service/redismock.go b/obs-status-service/redismock.go new file mode 100644 index 0000000..ce510db --- /dev/null +++ b/obs-status-service/redismock.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + + "github.com/redis/go-redis/v9" +) + +// MockRedisClient implements RedisClient interface +// and provides static data for local development (--test-run). +type MockRedisClient struct{} + +// ScanType mocks redisClient.ScanType +func (m *MockRedisClient) ScanType( + ctx context.Context, + cursor uint64, + match string, + count int64, + keyType string, +) *redis.ScanCmd { + + keys := []string{ + "result.devel:languages:python:Factory/openSUSE_Tumbleweed/x86_64", + "result.devel:Factory:git-workflow/openSUSE_Tumbleweed/x86_64", + } + + // cmdable is nil because this is a mock + cmd := redis.NewScanCmd(ctx, nil, "SCAN") + cmd.SetVal(keys, 0) + return cmd +} + +// HGetAll mocks redisClient.HGetAll +func (m *MockRedisClient) HGetAll( + ctx context.Context, + key string, +) *redis.MapStringStringCmd { + + data := map[string]map[string]string{ + "result.devel:languages:python:Factory/openSUSE_Tumbleweed/x86_64": { + "python313": "succeeded", + "python314": "failed", + }, + "result.devel:Factory:git-workflow/openSUSE_Tumbleweed/x86_64": { + "autogits": "succeeded", + }, + } + + // cmdable is nil because this is a mock + cmd := redis.NewMapStringStringCmd(ctx, nil, "HGETALL") + cmd.SetVal(data[key]) + return cmd +} -- 2.51.1