package query import ( "context" "errors" "queryorchestration/internal/database" "queryorchestration/internal/database/repository" resultprocessor "queryorchestration/internal/query/result/processor" "queryorchestration/internal/serviceconfig" "testing" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/pashagolub/pgxmock/v3" "github.com/stretchr/testify/assert" ) func TestGetUpdator(t *testing.T) { pool, err := pgxmock.NewPool() if err != nil { t.Fatalf("failed to open pgxmock database: %v", err) } cfg := &serviceconfig.BaseConfig{} cfg.DBPool = pool cfg.DBQueries = repository.New(pool) svc := New(cfg, &Services{}) queryType := resultprocessor.Type(resultprocessor.TypeContextFull) updator, err := svc.getUpdator(queryType) assert.NoError(t, err) assert.NotNil(t, updator) queryType = resultprocessor.Type(resultprocessor.TypeJsonExtractor) updator, err = svc.getUpdator(queryType) assert.NoError(t, err) assert.NotNil(t, updator) queryType = resultprocessor.Type(-1) _, err = svc.getUpdator(queryType) assert.Error(t, err) } func TestSubmitUpdate(t *testing.T) { ctx := context.Background() pool, err := pgxmock.NewPool() if err != nil { t.Fatalf("failed to open pgxmock database: %v", err) } cfg := &serviceconfig.BaseConfig{} cfg.DBPool = pool cfg.DBQueries = repository.New(pool) svc := New(cfg, &Services{}) config := "{\"path\":\"example_path\"}" q := Query{ ID: uuid.New(), RequiredQueryIDs: &[]uuid.UUID{ uuid.New(), }, Config: &config, ActiveVersion: int32(1), LatestVersion: int32(2), } aV := int32(10) update := &resultprocessor.Update{ ID: q.ID, RequiredQueryIDs: &[]uuid.UUID{ uuid.New(), }, Config: q.Config, ActiveVersion: &aV, } pool.ExpectBeginTx(pgx.TxOptions{}) pool.ExpectExec("name: AddRequiredQuery :exec").WithArgs(database.MustToDBUUID(update.ID), database.MustToDBUUID((*update.RequiredQueryIDs)[0]), pgxmock.AnyArg()). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectExec("name: RemoveRequiredQuery :exec").WithArgs(pgxmock.AnyArg(), database.MustToDBUUID((*q.RequiredQueryIDs)[0]), database.MustToDBUUID(update.ID)). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectExec("name: RemoveQueryConfig :exec").WithArgs(pgxmock.AnyArg(), database.MustToDBUUID(update.ID)). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectExec("name: AddQueryConfig :exec").WithArgs(database.MustToDBUUID(update.ID), []byte(*update.Config), int32(3)). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectExec("name: UpdateQuery :exec").WithArgs(aV, int32(3), database.MustToDBUUID(update.ID)). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectCommit() err = svc.submitUpdate(ctx, &q, update) assert.NoError(t, err) } func TestSubmitUpdateRollback(t *testing.T) { ctx := context.Background() pool, err := pgxmock.NewPool() if err != nil { t.Fatalf("failed to open pgxmock database: %v", err) } cfg := &serviceconfig.BaseConfig{} cfg.DBPool = pool cfg.DBQueries = repository.New(pool) svc := New(cfg, &Services{}) q := Query{ ID: uuid.New(), ActiveVersion: int32(1), LatestVersion: int32(2), } aV := int32(10) update := &resultprocessor.Update{ ID: q.ID, ActiveVersion: &aV, } pool.ExpectBeginTx(pgx.TxOptions{}) msg := "database failure" pool.ExpectExec("name: UpdateQuery :exec").WithArgs(aV, int32(3), database.MustToDBUUID(update.ID)). WillReturnError(errors.New(msg)) pool.ExpectCommit() err = svc.submitUpdate(ctx, &q, update) assert.EqualError(t, err, msg) } func TestSubmitUpdateRequiredQueries(t *testing.T) { ctx := context.Background() pool, err := pgxmock.NewPool() if err != nil { t.Fatalf("failed to open pgxmock database: %v", err) } cfg := &serviceconfig.BaseConfig{} cfg.DBPool = pool cfg.DBQueries = repository.New(pool) svc := New(cfg, &Services{}) config := "{\"path\":\"example_path\"}" q := Query{ ID: uuid.New(), RequiredQueryIDs: &[]uuid.UUID{ uuid.New(), uuid.New(), uuid.New(), }, Config: &config, ActiveVersion: int32(1), LatestVersion: int32(2), } update := &resultprocessor.Update{ ID: q.ID, RequiredQueryIDs: &[]uuid.UUID{ uuid.New(), uuid.New(), (*q.RequiredQueryIDs)[0], }, } pool.ExpectBeginTx(pgx.TxOptions{}) pool.ExpectExec("name: AddRequiredQuery :exec").WithArgs(database.MustToDBUUID(update.ID), database.MustToDBUUID((*update.RequiredQueryIDs)[0]), pgxmock.AnyArg()). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectExec("name: AddRequiredQuery :exec").WithArgs(database.MustToDBUUID(update.ID), database.MustToDBUUID((*update.RequiredQueryIDs)[1]), pgxmock.AnyArg()). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectExec("name: RemoveRequiredQuery :exec").WithArgs(pgxmock.AnyArg(), database.MustToDBUUID((*q.RequiredQueryIDs)[1]), database.MustToDBUUID(update.ID)). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectExec("name: RemoveRequiredQuery :exec").WithArgs(pgxmock.AnyArg(), database.MustToDBUUID((*q.RequiredQueryIDs)[2]), database.MustToDBUUID(update.ID)). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectExec("name: UpdateQuery :exec").WithArgs(q.ActiveVersion, int32(3), database.MustToDBUUID(update.ID)). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectCommit() err = svc.submitUpdate(ctx, &q, update) assert.NoError(t, err) } func TestSubmitUpdateActiveVersion(t *testing.T) { ctx := context.Background() pool, err := pgxmock.NewPool() if err != nil { t.Fatalf("failed to open pgxmock database: %v", err) } cfg := &serviceconfig.BaseConfig{} cfg.DBPool = pool cfg.DBQueries = repository.New(pool) svc := New(cfg, &Services{}) q := Query{ ID: uuid.New(), ActiveVersion: int32(1), LatestVersion: int32(2), } aV := int32(10) update := &resultprocessor.Update{ ID: q.ID, ActiveVersion: &aV, } pool.ExpectBeginTx(pgx.TxOptions{}) pool.ExpectExec("name: UpdateQuery :exec").WithArgs(aV, int32(3), database.MustToDBUUID(update.ID)). WillReturnResult(pgxmock.NewResult("", 1)) pool.ExpectCommit() err = svc.submitUpdate(ctx, &q, update) assert.NoError(t, err) } func TestGetSetDifference(t *testing.T) { commonUUID := uuid.New() listA := []uuid.UUID{uuid.New(), commonUUID} listB := []uuid.UUID{uuid.New(), commonUUID} assert.ElementsMatch(t, []uuid.UUID{}, getSetDifference(nil, nil)) assert.ElementsMatch(t, listA, getSetDifference(&listA, nil)) assert.ElementsMatch(t, []uuid.UUID{}, getSetDifference(nil, &listB)) assert.ElementsMatch(t, []uuid.UUID{listA[0]}, getSetDifference(&listA, &listB)) assert.ElementsMatch(t, []uuid.UUID{listB[0]}, getSetDifference(&listB, &listA)) assert.ElementsMatch(t, []uuid.UUID{}, getSetDifference(&listA, &listA)) } func TestNormalizeUpdate(t *testing.T) { ctx := context.Background() pool, err := pgxmock.NewPool() if err != nil { t.Fatalf("failed to open pgxmock database: %v", err) } cfg := &serviceconfig.BaseConfig{} cfg.DBPool = pool cfg.DBQueries = repository.New(pool) svc := New(cfg, &Services{}) current := &Query{ ID: uuid.New(), ActiveVersion: int32(1), LatestVersion: int32(2), Type: resultprocessor.TypeJsonExtractor, } qcfg := "{}" aV := int32(2) update := &resultprocessor.Update{ ID: current.ID, Config: &qcfg, ActiveVersion: &aV, RequiredQueryIDs: &[]uuid.UUID{}, } dbids := database.MustToDBUUIDArray(*update.RequiredQueryIDs) pool.ExpectQuery("name: AllQueriesExist :one").WithArgs(dbids).WillReturnRows( pgxmock.NewRows([]string{"all_exist"}). AddRow(true), ) err = svc.normalizeUpdate(ctx, current, update) assert.NoError(t, err) assert.EqualExportedValues(t, resultprocessor.Update{ ID: current.ID, ActiveVersion: &aV, Config: &qcfg, RequiredQueryIDs: nil, }, *update) update.RequiredQueryIDs = &[]uuid.UUID{uuid.New()} dbids = database.MustToDBUUIDArray(*update.RequiredQueryIDs) pool.ExpectQuery("name: IsQueryInDependencyTree :one").WithArgs(dbids).WillReturnRows( pgxmock.NewRows([]string{"all_exist"}). AddRow(true), ) err = svc.normalizeUpdate(ctx, current, update) assert.Error(t, err) update = &resultprocessor.Update{ ID: current.ID, } err = svc.normalizeUpdate(ctx, current, update) assert.Error(t, err) }