package product import ( "context" "encoding/json" "errors" "net/http" "net/http/httptest" "testing" "time" ) // The whole point of this port: the product must be created with the // REGISTRY's uuid, so both systems anchor to the same tenant identity. func TestProvisionTenant_sendsTheRegistryUUID(t *testing.T) { var got Tenant srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _ = json.NewDecoder(r.Body).Decode(&got) w.WriteHeader(http.StatusCreated) })) defer srv.Close() p := NewHTTPProvisioner(srv.URL, "/sdk/v1/tenants", nil, 5*time.Second) err := p.ProvisionTenant(context.Background(), Tenant{ ID: "2f875d6a-1d94-433a-b2ec-8529451a2d89", Name: "Acme", Slug: "acme", }) if err != nil { t.Fatalf("provision: %v", err) } if got.ID != "2f875d6a-1d94-433a-b2ec-8529451a2d89" { t.Errorf("registry uuid not sent: %+v", got) } if got.Slug != "acme" || got.Name != "Acme" { t.Errorf("payload wrong: %+v", got) } } // Re-provisioning must be safe: onboarding may retry, and the product's // insert is idempotent on the primary key. func TestProvisionTenant_conflictIsSuccess(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusConflict) })) defer srv.Close() p := NewHTTPProvisioner(srv.URL, "", nil, 5*time.Second) if err := p.ProvisionTenant(context.Background(), Tenant{ID: "x"}); err != nil { t.Fatalf("409 should be treated as already-provisioned, got %v", err) } } func TestProvisionTenant_serverErrorIsUnavailable(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusInternalServerError) })) defer srv.Close() p := NewHTTPProvisioner(srv.URL, "", nil, 5*time.Second) err := p.ProvisionTenant(context.Background(), Tenant{ID: "x"}) if !errors.Is(err, ErrUnavailable) { t.Fatalf("want ErrUnavailable, got %v", err) } } func TestProvisionTenant_attachesAuthHeaderWhenSupplied(t *testing.T) { var seen string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { seen = r.Header.Get("Authorization") w.WriteHeader(http.StatusCreated) })) defer srv.Close() p := NewHTTPProvisioner(srv.URL, "", func(context.Context) (string, error) { return "Bearer tok-123", nil }, 5*time.Second) if err := p.ProvisionTenant(context.Background(), Tenant{ID: "x"}); err != nil { t.Fatal(err) } if seen != "Bearer tok-123" { t.Errorf("auth header = %q", seen) } } func TestNoopProvisioner(t *testing.T) { if err := (NoopProvisioner{}).ProvisionTenant(context.Background(), Tenant{}); err != nil { t.Fatal(err) } }