Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/descrybe/descrybe-v2/apps/api/internal/billing"
|
||||
"github.com/descrybe/descrybe-v2/apps/api/internal/campaigns"
|
||||
"github.com/descrybe/descrybe-v2/apps/api/internal/config"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func TestRequireFeatureBillingNilFailsClosedInProduction(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := &Server{Config: config.Config{AppEnv: "production"}}
|
||||
h := s.RequireFeature("capability.api_access")(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/gated", nil))
|
||||
if rec.Code != http.StatusServiceUnavailable {
|
||||
t.Fatalf("status=%d want 503 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequireFeatureBillingNilPassThroughOutsideProduction(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := &Server{Config: config.Config{AppEnv: "development"}}
|
||||
called := false
|
||||
h := s.RequireFeature("capability.api_access")(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
called = true
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/gated", nil))
|
||||
if rec.Code != http.StatusNoContent || !called {
|
||||
t.Fatalf("status=%d called=%v want 204 pass-through", rec.Code, called)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequireFeaturesPlanGateViaHook(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
s := &Server{
|
||||
testAssertFeatures: func(_ context.Context, keys ...string) error {
|
||||
return fmt.Errorf("%w: %s", billing.ErrFeatureDisabled, keys[0])
|
||||
},
|
||||
}
|
||||
ctx := context.WithValue(context.Background(), ctxCompanyID, cid)
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil).WithContext(ctx)
|
||||
rec := httptest.NewRecorder()
|
||||
if s.requireFeatures(rec, req, "marketing.campaigns") {
|
||||
t.Fatal("requireFeatures should reject disabled feature")
|
||||
}
|
||||
if rec.Code != http.StatusPaymentRequired {
|
||||
t.Fatalf("status=%d want 402 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if !strings.Contains(rec.Body.String(), "feature_disabled") {
|
||||
t.Fatalf("body=%s want feature_disabled", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateCampaignPlanGate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
uid := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
s := &Server{
|
||||
Campaigns: &campaigns.Service{},
|
||||
testAssertFeatures: func(_ context.Context, keys ...string) error {
|
||||
return fmt.Errorf("%w: %s", billing.ErrFeatureDisabled, keys[0])
|
||||
},
|
||||
}
|
||||
ctx := context.WithValue(context.Background(), ctxUserID, uid)
|
||||
ctx = context.WithValue(ctx, ctxCompanyID, cid)
|
||||
ctx = context.WithValue(ctx, ctxRole, "admin")
|
||||
|
||||
t.Run("list", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/campaigns", nil).WithContext(ctx)
|
||||
rec := httptest.NewRecorder()
|
||||
s.handleListCampaigns(rec, req)
|
||||
if rec.Code != http.StatusPaymentRequired {
|
||||
t.Fatalf("status=%d want 402 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("create", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/campaigns", bytes.NewBufferString(`{"name":"x"}`)).WithContext(ctx)
|
||||
rec := httptest.NewRecorder()
|
||||
s.handleCreateCampaign(rec, req)
|
||||
if rec.Code != http.StatusPaymentRequired {
|
||||
t.Fatalf("status=%d want 402 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateAPIKeyPlanGate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
uid := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
s := &Server{
|
||||
testAssertFeatures: func(_ context.Context, keys ...string) error {
|
||||
return fmt.Errorf("%w: settings.api_keys", billing.ErrFeatureDisabled)
|
||||
},
|
||||
}
|
||||
ctx := context.WithValue(context.Background(), ctxUserID, uid)
|
||||
ctx = context.WithValue(ctx, ctxCompanyID, cid)
|
||||
ctx = context.WithValue(ctx, ctxRole, "admin")
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/api-keys", bytes.NewBufferString(`{"name":"x"}`)).WithContext(ctx)
|
||||
rec := httptest.NewRecorder()
|
||||
s.handleCreateAPIKey(rec, req)
|
||||
if rec.Code != http.StatusPaymentRequired {
|
||||
t.Fatalf("status=%d want 402 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateAPIKeyBillingNilFailsClosedInProduction(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
uid := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
s := &Server{Config: config.Config{AppEnv: "production"}}
|
||||
ctx := context.WithValue(context.Background(), ctxUserID, uid)
|
||||
ctx = context.WithValue(ctx, ctxCompanyID, cid)
|
||||
ctx = context.WithValue(ctx, ctxRole, "admin")
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/api-keys", bytes.NewBufferString(`{"name":"x"}`)).WithContext(ctx)
|
||||
rec := httptest.NewRecorder()
|
||||
s.handleCreateAPIKey(rec, req)
|
||||
if rec.Code != http.StatusServiceUnavailable {
|
||||
t.Fatalf("status=%d want 503 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateShopifyConfigPlanGate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
uid := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
|
||||
s := &Server{
|
||||
testAssertFeatures: func(_ context.Context, keys ...string) error {
|
||||
return fmt.Errorf("%w: stores.shopify", billing.ErrFeatureDisabled)
|
||||
},
|
||||
}
|
||||
ctx := context.WithValue(context.Background(), ctxUserID, uid)
|
||||
ctx = context.WithValue(ctx, ctxCompanyID, cid)
|
||||
ctx = context.WithValue(ctx, ctxRole, "admin")
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/shopify", bytes.NewBufferString(`{}`)).WithContext(ctx)
|
||||
rec := httptest.NewRecorder()
|
||||
s.handleUpdateShopifyConfig(rec, req)
|
||||
if rec.Code != http.StatusPaymentRequired {
|
||||
t.Fatalf("status=%d want 402 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListPublicPlansBillingNilReturnsEmpty(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := &Server{Config: config.Config{WebOrigin: "http://localhost:5173"}}
|
||||
rec := httptest.NewRecorder()
|
||||
s.handleListPublicPlans(rec, httptest.NewRequest(http.MethodGet, "/api/public/plans", nil))
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("nil billing status=%d want 200 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
s.Billing = &billing.Service{} // non-nil service without pool must not 500
|
||||
rec2 := httptest.NewRecorder()
|
||||
s.handleListPublicPlans(rec2, httptest.NewRequest(http.MethodGet, "/api/public/plans", nil))
|
||||
if rec2.Code != http.StatusOK {
|
||||
t.Fatalf("empty billing status=%d want 200 body=%s", rec2.Code, rec2.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListPlansBillingNilServiceUnavailable(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := &Server{}
|
||||
rec := httptest.NewRecorder()
|
||||
s.handleListPlans(rec, httptest.NewRequest(http.MethodGet, "/api/admin/plans", nil))
|
||||
if rec.Code != http.StatusServiceUnavailable {
|
||||
t.Fatalf("status=%d want 503 body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user