obs-status-service: add --test-run using interface-based Redis mock (fixes #113) #123
@@ -244,16 +244,24 @@ 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 {
|
||||
mockClient, err := NewMockRedisClient("factory.results.json.bz2")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
redisClient = mockClient
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
100
obs-status-service/redismock.go
Normal file
100
obs-status-service/redismock.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"compress/bzip2"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
"src.opensuse.org/autogits/common"
|
||||
)
|
||||
|
||||
// MockRedisClient implements RedisClient interface
|
||||
// and builds mock responses from existing test JSON data.
|
||||
type MockRedisClient struct {
|
||||
results []*common.BuildResult
|
||||
}
|
||||
|
||||
// NewMockRedisClient creates a mock client and loads test data.
|
||||
func NewMockRedisClient(path string) (*MockRedisClient, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
bzReader := bzip2.NewReader(file)
|
||||
|
||||
var results []*common.BuildResult
|
||||
if err := json.NewDecoder(bzReader).Decode(&results); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &MockRedisClient{
|
||||
results: results,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ScanType mocks redisClient.ScanType
|
||||
// It returns redis keys in the format: result.<Project>/<Repository>/<Arch>
|
||||
func (m *MockRedisClient) ScanType(
|
||||
ctx context.Context,
|
||||
cursor uint64,
|
||||
match string,
|
||||
count int64,
|
||||
keyType string,
|
||||
) *redis.ScanCmd {
|
||||
|
||||
var keys []string
|
||||
|
||||
for _, r := range m.results {
|
||||
key := "result." + r.Project + "/" + r.Repository + "/" + r.Arch
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
cmd := redis.NewScanCmd(ctx, nil, "SCAN")
|
||||
cmd.SetVal(keys, 0)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// HGetAll mocks redisClient.HGetAll
|
||||
// It returns a map[package]status for a given redis key.
|
||||
func (m *MockRedisClient) HGetAll(
|
||||
ctx context.Context,
|
||||
key string,
|
||||
) *redis.MapStringStringCmd {
|
||||
|
||||
resultMap := make(map[string]string)
|
||||
|
||||
// key format: result.<Project>/<Repository>/<Arch>
|
||||
if !strings.HasPrefix(key, "result.") {
|
||||
cmd := redis.NewMapStringStringCmd(ctx, nil, "HGETALL")
|
||||
cmd.SetVal(resultMap)
|
||||
return cmd
|
||||
}
|
||||
|
||||
key = strings.TrimPrefix(key, "result.")
|
||||
parts := strings.Split(key, "/")
|
||||
if len(parts) != 3 {
|
||||
cmd := redis.NewMapStringStringCmd(ctx, nil, "HGETALL")
|
||||
cmd.SetVal(resultMap)
|
||||
return cmd
|
||||
}
|
||||
|
||||
project, repository, arch := parts[0], parts[1], parts[2]
|
||||
|
||||
for _, r := range m.results {
|
||||
if r.Project == project && r.Repository == repository && r.Arch == arch {
|
||||
for _, pkg := range r.Status {
|
||||
resultMap[pkg.Package] = pkg.Code
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
cmd := redis.NewMapStringStringCmd(ctx, nil, "HGETALL")
|
||||
cmd.SetVal(resultMap)
|
||||
return cmd
|
||||
}
|
||||
Reference in New Issue
Block a user