| 1 | package abono_test |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "testing" |
| 6 | "time" |
| 7 | |
| 8 | "amadan.net/rastrillo/abono" |
| 9 | ) |
| 10 | |
| 11 | // TestMembersListsEveryHolding: the owner's members screen sees every |
| 12 | // subject's holdings, subscriptions and comps, ended ones included, by |
| 13 | // subject and then newest first, and never an unclaimed or unrecognised |
| 14 | // row (neither has anyone to show, and neither grants). |
| 15 | func TestMembersListsEveryHolding(t *testing.T) { |
| 16 | now := t0 |
| 17 | d := newStripeDouble(t) |
| 18 | s, _ := d.service(t, &now, abono.Config{}) |
| 19 | seedPlans(t, s) |
| 20 | ctx := context.Background() |
| 21 | |
| 22 | end := t0.AddDate(1, 0, 0) |
| 23 | for _, sp := range []subSpec{ |
| 24 | {ID: "sub_b", Status: "active", Price: "price_A", Customer: "cus_b", Email: "b@example.com", Start: t0, End: end, Metadata: map[string]string{"abono_subject": "b"}}, |
| 25 | {ID: "sub_x", Status: "active", Price: "price_unknown", Customer: "cus_x", Email: "x@example.com", Start: t0, End: end, Metadata: map[string]string{"abono_subject": "x"}}, |
| 26 | {ID: "sub_u", Status: "active", Price: "price_A", Customer: "cus_u", Email: "u@example.com", Start: t0, End: end}, |
| 27 | } { |
| 28 | if err := s.Sync(ctx, d.put(t, sp), abono.Hint{Subject: sp.Metadata["abono_subject"], Email: sp.Email}); err != nil { |
| 29 | t.Fatalf("Sync %s: %v", sp.ID, err) |
| 30 | } |
| 31 | } |
| 32 | // The unclaimed one: no Holder, so sub_u has an address and nobody. |
| 33 | id, err := s.Comp(ctx, "a", "monthly", nil, "") |
| 34 | if err != nil { |
| 35 | t.Fatal(err) |
| 36 | } |
| 37 | now = t0.Add(time.Minute) |
| 38 | ended, err := s.Comp(ctx, "b", "monthly", nil, "") |
| 39 | if err != nil { |
| 40 | t.Fatal(err) |
| 41 | } |
| 42 | if err := s.EndComp(ctx, ended); err != nil { |
| 43 | t.Fatal(err) |
| 44 | } |
| 45 | |
| 46 | ms, err := s.Members(ctx) |
| 47 | if err != nil { |
| 48 | t.Fatalf("Members: %v", err) |
| 49 | } |
| 50 | type row struct { |
| 51 | subject, plan string |
| 52 | source abono.Source |
| 53 | grants bool |
| 54 | comp int64 |
| 55 | } |
| 56 | var got []row |
| 57 | for _, m := range ms { |
| 58 | got = append(got, row{m.Subject, m.Plan, m.Source, m.Grants, m.CompID}) |
| 59 | } |
| 60 | want := []row{ |
| 61 | {"a", "monthly", abono.SourceComp, true, id}, |
| 62 | {"b", "monthly", abono.SourceComp, false, ended}, |
| 63 | {"b", "annual", abono.SourceSubscription, true, 0}, |
| 64 | } |
| 65 | if len(got) != len(want) { |
| 66 | t.Fatalf("Members = %+v, want %+v", got, want) |
| 67 | } |
| 68 | for i := range want { |
| 69 | if got[i] != want[i] { |
| 70 | t.Errorf("Members[%d] = %+v, want %+v", i, got[i], want[i]) |
| 71 | } |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | func TestMembersIsEmptyOnAFreshSite(t *testing.T) { |
| 76 | now := t0 |
| 77 | s, _ := newService(t, &now, abono.Config{}) |
| 78 | ms, err := s.Members(context.Background()) |
| 79 | if err != nil || len(ms) != 0 { |
| 80 | t.Errorf("Members = %v, %v; want none", ms, err) |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | // TestModeAccessors are what the owner's Stripe page reads (ruling R8): |
| 85 | // test or live from the key's prefix, the sandbox, the origin the |
| 86 | // webhook address is built on, and the clock holdings are judged by. |
| 87 | func TestModeAccessors(t *testing.T) { |
| 88 | now := t0 |
| 89 | for _, c := range []struct { |
| 90 | name string |
| 91 | cfg abono.Config |
| 92 | on, test, sandbox bool |
| 93 | }{ |
| 94 | {"off", abono.Config{Origin: "https://site.example"}, false, false, false}, |
| 95 | {"restricted test key", abono.Config{Origin: "https://site.example", Key: "rk_test_x", WebhookSecrets: []string{"whsec_x"}}, true, true, false}, |
| 96 | {"secret test key", abono.Config{Origin: "https://site.example", Key: "sk_test_x", WebhookSecrets: []string{"whsec_x"}}, true, true, false}, |
| 97 | {"live key", abono.Config{Origin: "https://site.example", Key: "rk_live_x", WebhookSecrets: []string{"whsec_x"}}, true, false, false}, |
| 98 | {"sandbox", abono.Config{Origin: "http://localhost:8080", Sandbox: true}, true, false, true}, |
| 99 | } { |
| 100 | t.Run(c.name, func(t *testing.T) { |
| 101 | s, _ := newService(t, &now, c.cfg) |
| 102 | if s.On() != c.on || s.TestMode() != c.test || s.Sandbox() != c.sandbox { |
| 103 | t.Errorf("On, TestMode, Sandbox = %v, %v, %v; want %v, %v, %v", |
| 104 | s.On(), s.TestMode(), s.Sandbox(), c.on, c.test, c.sandbox) |
| 105 | } |
| 106 | if s.Origin() != c.cfg.Origin { |
| 107 | t.Errorf("Origin = %q, want %q", s.Origin(), c.cfg.Origin) |
| 108 | } |
| 109 | if !s.Now().Equal(t0) { |
| 110 | t.Errorf("Now = %v, want the service's clock, %v", s.Now(), t0) |
| 111 | } |
| 112 | }) |
| 113 | } |
| 114 | } |
| 115 | |