diff --git a/internal/config/config_test.go b/internal/config/config_test.go new file mode 100644 index 0000000..34b3ba9 --- /dev/null +++ b/internal/config/config_test.go @@ -0,0 +1,52 @@ +package config + +import ( + "testing" +) + +func TestLoad_defaults(t *testing.T) { + t.Setenv("APP_ENV", "") + t.Setenv("ADDR", "") + t.Setenv("KEYCLOAK_ISSUER", "") + t.Setenv("DATABASE_URL", "") + + cfg, err := Load() + if err != nil { + t.Fatal(err) + } + if cfg.Env != "dev" { + t.Errorf("Env = %q, want dev", cfg.Env) + } + if cfg.Addr != ":8080" { + t.Errorf("Addr = %q, want :8080", cfg.Addr) + } + if cfg.KeycloakIssuer == "" { + t.Error("KeycloakIssuer is empty; expected a default") + } + if cfg.DatabaseURL != "" { + t.Errorf("DatabaseURL = %q, want empty default", cfg.DatabaseURL) + } +} + +func TestLoad_overrides(t *testing.T) { + t.Setenv("APP_ENV", "stage") + t.Setenv("ADDR", ":9000") + t.Setenv("KEYCLOAK_ISSUER", "https://auth.example/realms/r") + t.Setenv("DATABASE_URL", "postgres://x") + + cfg, err := Load() + if err != nil { + t.Fatal(err) + } + if cfg.Env != "stage" || cfg.Addr != ":9000" || cfg.KeycloakIssuer != "https://auth.example/realms/r" || cfg.DatabaseURL != "postgres://x" { + t.Errorf("overrides not applied: %+v", cfg) + } +} + +func TestLoad_invalidEnv(t *testing.T) { + t.Setenv("APP_ENV", "bogus") + _, err := Load() + if err == nil { + t.Fatal("expected error for invalid APP_ENV") + } +} diff --git a/internal/store/memory_test.go b/internal/store/memory_test.go new file mode 100644 index 0000000..afc3325 --- /dev/null +++ b/internal/store/memory_test.go @@ -0,0 +1,64 @@ +package store + +import ( + "context" + "errors" + "testing" +) + +func TestMemory_seededAcme(t *testing.T) { + m := NewMemory() + ctx := context.Background() + + t.Run("by slug returns seed", func(t *testing.T) { + got, err := m.BySlug(ctx, "acme") + if err != nil { + t.Fatal(err) + } + if got.Slug != "acme" { + t.Errorf("slug = %q, want acme", got.Slug) + } + if got.Status != "active" { + t.Errorf("status = %q, want active", got.Status) + } + if len(got.Products) != 2 { + t.Errorf("products = %v, want [certifai compliance]", got.Products) + } + }) + + t.Run("by id returns seed", func(t *testing.T) { + got, err := m.ByID(ctx, "00000000-0000-0000-0000-000000000001") + if err != nil { + t.Fatal(err) + } + if got.Slug != "acme" { + t.Errorf("slug = %q, want acme", got.Slug) + } + }) + + t.Run("missing slug returns ErrNotFound", func(t *testing.T) { + _, err := m.BySlug(ctx, "nope") + if !errors.Is(err, ErrNotFound) { + t.Errorf("err = %v, want ErrNotFound", err) + } + }) + + t.Run("missing id returns ErrNotFound", func(t *testing.T) { + _, err := m.ByID(ctx, "deadbeef") + if !errors.Is(err, ErrNotFound) { + t.Errorf("err = %v, want ErrNotFound", err) + } + }) + + t.Run("returned tenant is a copy, not the stored pointer", func(t *testing.T) { + got, err := m.BySlug(ctx, "acme") + if err != nil { + t.Fatal(err) + } + got.Name = "mutated" + got2, _ := m.BySlug(ctx, "acme") + if got2.Name == "mutated" { + t.Error("store leaked internal pointer; caller could mutate seeded state") + } + }) +}