From f90a645594ff456d1cecef0cbc2e5293934ac5a9 Mon Sep 17 00:00:00 2001 From: Ekaterina Lebedeva Date: Mon, 10 Jun 2024 19:26:55 +0300 Subject: [PATCH] [#144] registry: Add tests for obj registry exporter Signed-off-by: Ekaterina Lebedeva --- internal/registry/obj_exporter.go | 9 +- internal/registry/obj_exporter_test.go | 156 +++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 internal/registry/obj_exporter_test.go diff --git a/internal/registry/obj_exporter.go b/internal/registry/obj_exporter.go index 57e6d0d..e1e81e5 100644 --- a/internal/registry/obj_exporter.go +++ b/internal/registry/obj_exporter.go @@ -10,14 +10,17 @@ type ObjExporter struct { } type PreGenerateInfo struct { - Buckets []string `json:"buckets"` - Objects []ObjInfo `json:"objects"` - ObjSize string `json:"obj_size"` + Buckets []string `json:"buckets"` + Containers []string `json:"containers"` + Objects []ObjInfo `json:"objects"` + ObjSize string `json:"obj_size"` } type ObjInfo struct { Bucket string `json:"bucket"` Object string `json:"object"` + CID string `json:"cid"` + OID string `json:"oid"` } func NewObjExporter(selector *ObjSelector) *ObjExporter { diff --git a/internal/registry/obj_exporter_test.go b/internal/registry/obj_exporter_test.go new file mode 100644 index 0000000..87e8984 --- /dev/null +++ b/internal/registry/obj_exporter_test.go @@ -0,0 +1,156 @@ +package registry + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + "os" + "path/filepath" + "slices" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +type expectedResult struct { + mode string + objects []ObjectInfo + dir string + dbName string + jsonName string +} + +func TestObjectExporter(t *testing.T) { + names := []string{"s3", "grpc"} + for _, name := range names { + t.Run(name, runExportTest) + t.Run(name+"-changed", runExportChangedTest) + t.Run(name+"-empty", runExportEmptyTest) + } +} + +func runExportTest(t *testing.T) { + expected := getExpectedResult(t) + objReg := getFilledRegistry(t, expected) + objExp := NewObjExporter(NewObjSelector(objReg, 0, SelectorOneshot, &ObjFilter{Status: statusCreated})) + + require.NoError(t, objExp.ExportJSONPreGen(expected.jsonName)) + require.NoError(t, checkExported(expected.objects, expected.jsonName)) +} + +func runExportChangedTest(t *testing.T) { + expected := getExpectedResult(t) + objReg := getFilledRegistry(t, expected) + + newStatus := randString(10) + num := randPositiveInt(1, len(expected.objects)) + changedObjects := make([]ObjectInfo, num) + require.Equal(t, num, copy(changedObjects[:], expected.objects[:])) + + sel := NewObjSelector(objReg, 0, SelectorOneshot, &ObjFilter{Status: statusCreated}) + for i := range changedObjects { + changedObjects[i].Status = newStatus + require.NoError(t, objReg.SetObjectStatus(sel.NextObject().Id, statusCreated, newStatus)) + } + + objExp := NewObjExporter(NewObjSelector(objReg, 0, SelectorOneshot, &ObjFilter{Status: newStatus})) + require.NoError(t, objExp.ExportJSONPreGen(expected.jsonName)) + require.NoError(t, checkExported(changedObjects, expected.jsonName)) +} + +func runExportEmptyTest(t *testing.T) { + expected := getExpectedResult(t) + expected.objects = make([]ObjectInfo, 0) + objReg := getFilledRegistry(t, expected) + objExp := NewObjExporter(NewObjSelector(objReg, 0, SelectorOneshot, &ObjFilter{Status: statusCreated})) + + require.NoError(t, objExp.ExportJSONPreGen(expected.jsonName)) + require.NoError(t, checkExported(expected.objects, expected.jsonName)) +} + +func getExpectedResult(t *testing.T) expectedResult { + num := randPositiveInt(2, 100) + mode := getMode(t.Name()) + require.NotEqual(t, "", mode, "test mode should contain either \"s3\" or\"grpc\"") + dir := t.TempDir() + res := expectedResult{ + mode: mode, + objects: generateObjectInfo(num, t.Name()), + dir: dir, + dbName: filepath.Join(dir, "registry-"+mode+".db"), + jsonName: filepath.Join(dir, "registry-"+mode+".json"), + } + return res +} + +func randPositiveInt(min, max int) int { + return rand.Intn(max-min) + min +} + +func getMode(name string) (res string) { + if strings.Contains(name, "s3") { + res = filepath.Base(name) + } + if strings.Contains(name, "grpc") { + res = filepath.Base(name) + } + return res +} + +func generateObjectInfo(num int, mode string) []ObjectInfo { + res := make([]ObjectInfo, num) + for i := range res { + res[i] = randomObjectInfo() + if !strings.Contains(mode, "s3") { + res[i].S3Bucket = "" + res[i].S3Key = "" + } + if !strings.Contains(mode, "grpc") { + res[i].CID = "" + res[i].OID = "" + } + } + return res +} + +func getFilledRegistry(t *testing.T, expected expectedResult) *ObjRegistry { + objReg := NewObjRegistry(context.Background(), expected.dbName) + for i := range expected.objects { + require.NoError(t, objReg.AddObject(expected.objects[i].CID, expected.objects[i].OID, expected.objects[i].S3Bucket, expected.objects[i].S3Key, expected.objects[i].PayloadHash)) + } + return objReg +} + +func checkExported(expected []ObjectInfo, fileName string) error { + file, err := os.ReadFile(fileName) + if err != nil { + return err + } + + if !json.Valid(file) { + return fmt.Errorf("exported json file %s is invalid", fileName) + } + + var actual PreGenerateInfo + if json.Unmarshal(file, &actual) != nil { + return err + } + + if len(expected) != len(actual.Objects) { + return fmt.Errorf("expected len(): %v, got len(): %v", len(expected), len(actual.Objects)) + } + + for i := range expected { + if !slices.ContainsFunc(actual.Objects, func(oi ObjInfo) bool { + compareS3 := oi.Bucket == expected[i].S3Bucket && oi.Object == expected[i].S3Key + comparegRPC := oi.CID == expected[i].CID && oi.OID == expected[i].OID + return compareS3 && comparegRPC + }) { + return fmt.Errorf("object %v not found in exported json file %s", expected[i], fileName) + } + } + + return nil +}