Skip to content
This repository has been archived by the owner on Jan 2, 2024. It is now read-only.

Commit

Permalink
various: tighten up tests (#265)
Browse files Browse the repository at this point in the history
  • Loading branch information
bmizerany committed Feb 27, 2023
1 parent 7322395 commit ef49337
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 133 deletions.
137 changes: 49 additions & 88 deletions api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"
"time"

"github.com/kr/pretty"
"golang.org/x/exp/slices"
"kr.dev/diff"
"tier.run/api/apitypes"
Expand All @@ -24,7 +25,7 @@ var (
mpfs = refs.MustParseFeaturePlans
)

func newTestClient(t *testing.T) (*tier.Client, *control.Client) {
func newTestClient(t *testing.T) *tier.Client {
sc := stroke.Client(t)
sc = stroke.WithAccount(t, sc)
cc := &control.Client{
Expand All @@ -40,18 +41,22 @@ func newTestClient(t *testing.T) (*tier.Client, *control.Client) {
BaseURL: s.URL,
HTTPClient: s.Client(),
}
return tc, cc
return tc
}

func TestAPICheckout(t *testing.T) {
ctx := context.Background()
tc, cc := newTestClient(t)
m := []control.Feature{{
FeaturePlan: mpf("feature:x@plan:test@0"),
Interval: "@monthly",
Currency: "usd",
}}
cc.Push(ctx, m, pushLogger(t))
tc := newTestClient(t)
m := []byte(`
{"plans": {"plan:test@0": {"features": {
"feature:x": {}
}}}}
`)
pr, err := tc.PushJSON(ctx, m)
if err != nil {
t.Fatal(err)
}
t.Logf("pushed: %s", pretty.Formatter(pr))

t.Run("card setup", func(t *testing.T) {
r, err := tc.Checkout(ctx, "org:test", "https://example.com/success", nil)
Expand Down Expand Up @@ -81,32 +86,20 @@ func TestAPISubscribe(t *testing.T) {
t.Parallel()

ctx := context.Background()
tc, cc := newTestClient(t)
tc := newTestClient(t)

m := []control.Feature{
{
FeaturePlan: mpf("feature:x@plan:test@0"),
Interval: "@monthly",
Currency: "usd",
},
{
FeaturePlan: mpf("feature:t@plan:test@0"),
Interval: "@monthly",
Currency: "usd",
Aggregate: "sum",
Mode: "graduated",
Tiers: []control.Tier{
{Upto: control.Inf, Price: 100},
},
},
}
if err := cc.Push(ctx, m, func(f control.Feature, err error) {
if err != nil {
t.Logf("error pushing %q: %v", f.FeaturePlan, err)
}
}); err != nil {
m := []byte(`
{"plans": {"plan:test@0": {"features": {
"feature:x": {},
"feature:t": {"tiers": [{"price": 100}]}
}}}}
`)

pr, err := tc.PushJSON(ctx, m)
if err != nil {
t.Fatal(err)
}
t.Logf("pushed: %s", pretty.Formatter(pr))

whoIs := func(org string, wantErr error) {
t.Helper()
Expand Down Expand Up @@ -230,7 +223,7 @@ func TestAPISubscribe(t *testing.T) {
Message: "feature or plan not found",
})

_, err := tc.Schedule(ctx, "org:test", &tier.ScheduleParams{
_, err = tc.Schedule(ctx, "org:test", &tier.ScheduleParams{
Phases: []apitypes.Phase{
{Trial: true, Features: []string{"plan:test@0"}},
},
Expand All @@ -256,7 +249,7 @@ func TestCancel(t *testing.T) {
t.Parallel()

ctx := context.Background()
tc, _ := newTestClient(t)
tc := newTestClient(t)
_, err := tc.PushJSON(ctx, []byte(`{
"plans": {
"plan:test@0": {
Expand Down Expand Up @@ -298,7 +291,7 @@ func TestPhaseBadOrg(t *testing.T) {
t.Parallel()

ctx := context.Background()
tc, _ := newTestClient(t)
tc := newTestClient(t)
_, err := tc.LookupPhase(ctx, "org:nope")
diff.Test(t, t.Errorf, err, &apitypes.Error{
Status: 400,
Expand All @@ -317,37 +310,22 @@ func TestPhaseFragments(t *testing.T) {
t.Parallel()

ctx := context.Background()
tc, cc := newTestClient(t)
tc := newTestClient(t)

m := []control.Feature{
{
FeaturePlan: mpf("feature:x@plan:test@0"),
Interval: "@monthly",
Currency: "usd",
},
{
FeaturePlan: mpf("feature:t@plan:test@0"),
Interval: "@monthly",
Currency: "usd",
Aggregate: "sum",
Mode: "graduated",
Tiers: []control.Tier{
{Upto: control.Inf, Price: 100},
},
},
}
if err := cc.Push(ctx, m, func(f control.Feature, err error) {
if err != nil {
t.Logf("error pushing %q: %v", f.FeaturePlan, err)
}
}); err != nil {
m := []byte(`
{"plans": {"plan:test@0": {"features": {
"feature:x": {},
"feature:t": {"tiers": [{"price": 100}]}
}}}}
`)

pr, err := tc.PushJSON(ctx, m)
if err != nil {
t.Fatal(err)
}
t.Logf("pushed: %s", pretty.Formatter(pr))

// cheating and using the tier client because ATM the API only supports
// subscribing to plans.
frag := m[1:]
if err := cc.SubscribeTo(ctx, "org:test", control.FeaturePlans(frag)); err != nil {
if err := tc.Subscribe(ctx, "org:test", "feature:x@plan:test@0"); err != nil {
t.Fatal(err)
}

Expand All @@ -357,9 +335,9 @@ func TestPhaseFragments(t *testing.T) {
}

want := apitypes.PhaseResponse{
Features: mpfs("feature:t@plan:test@0"),
Features: mpfs("feature:x@plan:test@0"),
Plans: nil,
Fragments: mpfs("feature:t@plan:test@0"),
Fragments: mpfs("feature:x@plan:test@0"),
}

// actively avoiding a stripe test clock here to keep the test
Expand All @@ -376,7 +354,7 @@ func TestTierPull(t *testing.T) {
t.Parallel()

ctx := context.Background()
tc, _ := newTestClient(t)
tc := newTestClient(t)

want := apitypes.Model{
Plans: map[refs.Plan]apitypes.Plan{
Expand Down Expand Up @@ -415,7 +393,7 @@ func TestPushInvalidPrice(t *testing.T) {
t.Parallel()

ctx := context.Background()
tc, _ := newTestClient(t)
tc := newTestClient(t)

in := apitypes.Model{
Plans: map[refs.Plan]apitypes.Plan{
Expand Down Expand Up @@ -451,7 +429,7 @@ func TestWhoAmI(t *testing.T) {
t.Parallel()

ctx := context.Background()
tc, _ := newTestClient(t)
tc := newTestClient(t)
a, err := tc.WhoAmI(ctx)
if err != nil {
t.Fatal(err)
Expand All @@ -468,7 +446,7 @@ func TestWhoAmI(t *testing.T) {
func TestClock(t *testing.T) {
t.Parallel()

tc, _ := newTestClient(t)
tc := newTestClient(t)

now := time.Now().Truncate(time.Second)
ctx, err := tc.WithClock(context.Background(), t.Name(), now)
Expand Down Expand Up @@ -498,7 +476,7 @@ func TestClock(t *testing.T) {
func TestTierReport(t *testing.T) {
t.Parallel()

tc, _ := newTestClient(t)
tc := newTestClient(t)

now := time.Now()
ctx, err := tc.WithClock(context.Background(), t.Name(), now)
Expand Down Expand Up @@ -563,7 +541,7 @@ func TestTierReport(t *testing.T) {

func TestScheduleWithCustomerInfoNoPhases(t *testing.T) {
ctx := context.Background()
tc, _ := newTestClient(t)
tc := newTestClient(t)

p := &tier.ScheduleParams{
Info: &tier.OrgInfo{
Expand Down Expand Up @@ -628,7 +606,7 @@ func TestScheduleWithCustomerInfoNoPhases(t *testing.T) {

func TestPaymentMethods(t *testing.T) {
ctx := context.Background()
tc, _ := newTestClient(t)
tc := newTestClient(t)

if err := tc.Subscribe(ctx, "org:test"); err != nil {
t.Fatal(err)
Expand All @@ -653,20 +631,3 @@ func maybeFailNow(t *testing.T) {
t.FailNow()
}
}

func pushLogger(t *testing.T) func(f control.Feature, err error) {
t.Helper()
return pushLogWith(t, t.Fatalf)
}

func pushLogWith(t *testing.T, fatalf func(string, ...any)) func(f control.Feature, err error) {
t.Helper()
return func(f control.Feature, err error) {
t.Helper()
if err == nil {
t.Logf("pushed %q", f.FeaturePlan)
} else {
fatalf("error pushing %q: %v", f.FeaturePlan, err)
}
}
}
14 changes: 6 additions & 8 deletions client/tier/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,20 +362,18 @@ func (c *Client) Advance(ctx context.Context, t time.Time) error {
return c.awaitClockReady(ctx, cr.ID)
}

var errForBackoff = errors.New("force backoff")
var errClockNotReady = errors.New("force backoff")

func (c *Client) awaitClockReady(ctx context.Context, id string) error {
bo := backoff.NewBackoff("tier", c.logf, 5*time.Second)
for {
cr, err := c.syncClock(ctx, id)
if err != nil {
return err
if err != nil || cr.Status != "ready" {
c.logf("clock %s not ready: err=%v status=%q; retrying", id, err, cr.Status)
bo.BackOff(ctx, errClockNotReady)
continue
}
if cr.Status == "ready" {
return nil
}
c.logf("clock %s status = %q; waiting", id, cr.Status)
bo.BackOff(ctx, errForBackoff)
return nil
}
}

Expand Down
20 changes: 10 additions & 10 deletions control/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func newTestClient(t *testing.T) *Client {
}

func TestRoundTrip(t *testing.T) {
tc := newTestClient(t)
cc := newTestClient(t)
ctx := context.Background()

want := []Feature{
Expand Down Expand Up @@ -70,11 +70,11 @@ func TestRoundTrip(t *testing.T) {
t.Fatal("want must be sorted")
}

if err := tc.Push(ctx, want, pushLogger(t)); err != nil {
if err := cc.Push(ctx, want, pushLogger(t)); err != nil {
t.Fatal(err)
}

got, err := tc.Pull(ctx, 0)
got, err := cc.Pull(ctx, 0)
if err != nil {
t.Fatal(err)
}
Expand All @@ -91,7 +91,7 @@ func TestRoundTrip(t *testing.T) {
var got struct {
Name string
}
if err := tc.Stripe.Do(ctx, "GET", "/v1/products/tier__feature-test-plan-free-theVersion", stripe.Form{}, &got); err != nil {
if err := cc.Stripe.Do(ctx, "GET", "/v1/products/tier__feature-test-plan-free-theVersion", stripe.Form{}, &got); err != nil {
t.Fatal(err)
}
const want = "PlanTitle - FeatureTitle"
Expand All @@ -102,7 +102,7 @@ func TestRoundTrip(t *testing.T) {
}

func TestPushPlanInvalidDecimal(t *testing.T) {
tc := newTestClient(t) // TODO(bmizerany): use a client without creating an account
cc := newTestClient(t) // TODO(bmizerany): use a client without creating an account
ctx := context.Background()

fs := []Feature{
Expand All @@ -118,14 +118,14 @@ func TestPushPlanInvalidDecimal(t *testing.T) {
},
},
}
got := tc.Push(ctx, fs, pushLogWith(t, t.Logf))
got := cc.Push(ctx, fs, pushLogWith(t, t.Logf))
if !errors.Is(got, ErrInvalidPrice) {
t.Fatalf("got %v, want ErrInvalidDecimal", got)
}
}

func TestPushPlanImmutability(t *testing.T) {
tc := newTestClient(t)
cc := newTestClient(t)
ctx := context.Background()

pushes := []struct {
Expand All @@ -148,7 +148,7 @@ func TestPushPlanImmutability(t *testing.T) {
cb := func(_ Feature, err error) {
errs = append(errs, err)
}
if err := tc.Push(ctx, fs, cb); !errors.Is(err, push.err) {
if err := cc.Push(ctx, fs, cb); !errors.Is(err, push.err) {
t.Errorf("[%d]: got %v, want %v", i, err, push.err)
}
if push.err != nil {
Expand All @@ -163,7 +163,7 @@ func TestPushPlanImmutability(t *testing.T) {
}

func TestPushAllFeaturesLoggedOnFailure(t *testing.T) {
tc := newTestClient(t)
cc := newTestClient(t)
ctx := context.Background()

fs := []Feature{
Expand All @@ -190,7 +190,7 @@ func TestPushAllFeaturesLoggedOnFailure(t *testing.T) {

var mu sync.Mutex
var got []error
if err := tc.Push(ctx, fs, func(_ Feature, err error) {
if err := cc.Push(ctx, fs, func(_ Feature, err error) {
mu.Lock()
defer mu.Unlock()
got = append(got, err)
Expand Down

0 comments on commit ef49337

Please sign in to comment.