feat: add idempotent calendar bootstrap
Bootstrap independently reviewed catalogs through audited import, approval, and initial activation transitions, then resume insight scheduling safely.
This commit is contained in:
87
internal/eventcatalog/bootstrap_integration_test.go
Normal file
87
internal/eventcatalog/bootstrap_integration_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package eventcatalog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func TestRepositoryBootstrapStateAndInitialActivation(t *testing.T) {
|
||||
pool := eventCatalogTestPool(t)
|
||||
repository := NewRepository(pool)
|
||||
ctx := t.Context()
|
||||
prefix := fmt.Sprintf("bootstrap-%d", time.Now().UnixNano())
|
||||
first := catalogImportForIntegration(prefix + "-first")
|
||||
second := catalogImportForIntegration(prefix + "-second")
|
||||
t.Cleanup(func() {
|
||||
_, _ = pool.Exec(context.Background(), `DELETE FROM calendar_catalog_versions WHERE version IN ($1,$2)`, first.Version, second.Version)
|
||||
})
|
||||
|
||||
if err := repository.ImportDraft(ctx, first); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state, err := repository.CatalogState(ctx, first.Version)
|
||||
if err != nil || state.Status != CatalogStatusDraft || !state.matches(first) {
|
||||
t.Fatalf("draft state=%+v error=%v", state, err)
|
||||
}
|
||||
if err := repository.Approve(ctx, first.Version, "reviewer"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := repository.ActivateInitial(ctx, first.Version, "operator"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
active, err := repository.ActiveCatalogState(ctx)
|
||||
if err != nil || active.Version != first.Version || active.Status != CatalogStatusActive {
|
||||
t.Fatalf("active state=%+v error=%v", active, err)
|
||||
}
|
||||
var auditCount int
|
||||
if err := pool.QueryRow(ctx, `SELECT count(*) FROM calendar_catalog_audit a JOIN calendar_catalog_versions v ON v.id=a.catalog_version_id WHERE v.version=$1`, first.Version).Scan(&auditCount); err != nil || auditCount != 3 {
|
||||
t.Fatalf("first audit count=%d error=%v", auditCount, err)
|
||||
}
|
||||
|
||||
if err := repository.ImportDraft(ctx, second); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := repository.Approve(ctx, second.Version, "reviewer"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := repository.ActivateInitial(ctx, second.Version, "operator"); !errors.Is(err, ErrCatalogConflict) {
|
||||
t.Fatalf("activation error=%v, want ErrCatalogConflict", err)
|
||||
}
|
||||
state, err = repository.CatalogState(ctx, second.Version)
|
||||
if err != nil || state.Status != CatalogStatusApproved {
|
||||
t.Fatalf("conflicting state=%+v error=%v", state, err)
|
||||
}
|
||||
if err := pool.QueryRow(ctx, `SELECT count(*) FROM calendar_catalog_audit a JOIN calendar_catalog_versions v ON v.id=a.catalog_version_id WHERE v.version=$1`, second.Version).Scan(&auditCount); err != nil || auditCount != 2 {
|
||||
t.Fatalf("second audit count=%d error=%v", auditCount, err)
|
||||
}
|
||||
}
|
||||
|
||||
func eventCatalogTestPool(t *testing.T) *pgxpool.Pool {
|
||||
t.Helper()
|
||||
databaseURL := os.Getenv("TEST_DATABASE_URL")
|
||||
if databaseURL == "" {
|
||||
t.Skip("TEST_DATABASE_URL is not configured")
|
||||
}
|
||||
pool, err := pgxpool.New(context.Background(), databaseURL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(pool.Close)
|
||||
return pool
|
||||
}
|
||||
|
||||
func catalogImportForIntegration(version string) Import {
|
||||
input := validCoveredImport()
|
||||
input.Version = version
|
||||
input.SourceChecksum = "sha256:" + fmt.Sprintf("%064x", len(version))
|
||||
for index := range input.Events {
|
||||
input.Events[index].ID = fmt.Sprintf("%s-event-%d", version, index)
|
||||
}
|
||||
return input
|
||||
}
|
||||
Reference in New Issue
Block a user