Files

143 lines
3.3 KiB
Go
Raw Permalink Normal View History

package billing
import (
"context"
"errors"
"os"
"testing"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
)
func TestPlanIDByNameRequiresName(t *testing.T) {
t.Parallel()
svc := &Service{}
_, err := svc.PlanIDByName(context.Background(), " ")
if !errors.Is(err, ErrPlanNameRequired) {
t.Fatalf("got %v, want ErrPlanNameRequired", err)
}
}
func TestAssignPlanIfMissingSkipsExisting(t *testing.T) {
dsn := os.Getenv("DATABASE_URL")
if dsn == "" {
t.Skip("DATABASE_URL not set")
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
pg, err := pgxpool.New(ctx, dsn)
if err != nil {
t.Fatal(err)
}
defer pg.Close()
svc := &Service{Pool: pg}
if err := svc.EnsureDefaultPlans(ctx); err != nil {
t.Fatal(err)
}
freeID, err := svc.PlanIDByName(ctx, "Free")
if err != nil {
t.Fatal(err)
}
starterID, err := svc.PlanIDByName(ctx, "Starter")
if err != nil {
t.Fatal(err)
}
companyID := uuid.New()
_, err = pg.Exec(ctx, `INSERT INTO companies (id, name) VALUES ($1, $2)`, companyID, "missing-plans-"+companyID.String()[:8])
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cleanupCancel()
_, _ = pg.Exec(cleanupCtx, `DELETE FROM companies WHERE id = $1`, companyID)
})
assigned, err := svc.AssignPlanIfMissing(ctx, companyID, freeID)
if err != nil {
t.Fatal(err)
}
if !assigned {
t.Fatal("expected first assign to succeed")
}
assigned, err = svc.AssignPlanIfMissing(ctx, companyID, starterID)
if err != nil {
t.Fatal(err)
}
if assigned {
t.Fatal("must not overwrite an existing active plan")
}
has, err := svc.HasActivePlan(ctx, companyID)
if err != nil || !has {
t.Fatalf("has active plan: has=%v err=%v", has, err)
}
var planID int64
err = pg.QueryRow(ctx, `SELECT plan_id FROM company_plans WHERE company_id = $1 AND is_active = true`, companyID).Scan(&planID)
if err != nil {
t.Fatal(err)
}
if planID != freeID {
t.Fatalf("active plan_id=%d, want Free id=%d", planID, freeID)
}
missing, err := svc.ListCompaniesWithoutActivePlan(ctx, 500, 0)
if err != nil {
t.Fatal(err)
}
for _, c := range missing {
if c.ID == companyID {
t.Fatal("company with active plan must not appear in without-plan list")
}
}
}
func TestListCompaniesWithoutActivePlanIncludesBareCompany(t *testing.T) {
dsn := os.Getenv("DATABASE_URL")
if dsn == "" {
t.Skip("DATABASE_URL not set")
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
pg, err := pgxpool.New(ctx, dsn)
if err != nil {
t.Fatal(err)
}
defer pg.Close()
svc := &Service{Pool: pg}
companyID := uuid.New()
_, err = pg.Exec(ctx, `INSERT INTO companies (id, name) VALUES ($1, $2)`, companyID, "no-plan-"+companyID.String()[:8])
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cleanupCancel()
_, _ = pg.Exec(cleanupCtx, `DELETE FROM companies WHERE id = $1`, companyID)
})
found := false
rows, err := svc.ListCompaniesWithoutActivePlan(ctx, 500, 0)
if err != nil {
t.Fatal(err)
}
for _, c := range rows {
if c.ID == companyID {
found = true
break
}
}
if !found {
t.Fatal("bare company must appear in without-plan list")
}
}