ducky/subscriptions
2015-10-04
Parent:aab6ba5ae392
ducky/subscriptions/subscription_store_test.go
Make api subpackage golint-passing. Add comments to all the exported functions, methods, and variables in the api subpackage, to make golint happy. Also, make the individual endpoints in the api subpackage unexported, as there's no real use case for exporting them. The handlers depend on the placeholders in the endpoint, so we need them to be controlled in unison, which means it's probably a bad idea to declare the route outside of the API package. And the only reason to expose the Handler is so people can declare custom endpoints.
| paddy@0 | 1 package subscriptions |
| paddy@0 | 2 |
| paddy@0 | 3 import ( |
| paddy@1 | 4 "os" |
| paddy@0 | 5 "strconv" |
| paddy@0 | 6 "testing" |
| paddy@0 | 7 "time" |
| paddy@0 | 8 |
| paddy@0 | 9 "code.secondbit.org/uuid.hg" |
| paddy@0 | 10 ) |
| paddy@0 | 11 |
| paddy@0 | 12 const ( |
| paddy@15 | 13 subscriptionChangeStripeSubscription = 1 << iota |
| paddy@2 | 14 subscriptionChangePlan |
| paddy@2 | 15 subscriptionChangeStatus |
| paddy@2 | 16 subscriptionChangeCanceling |
| paddy@2 | 17 subscriptionChangeTrialStart |
| paddy@2 | 18 subscriptionChangeTrialEnd |
| paddy@2 | 19 subscriptionChangePeriodStart |
| paddy@2 | 20 subscriptionChangePeriodEnd |
| paddy@2 | 21 subscriptionChangeCanceledAt |
| paddy@2 | 22 subscriptionChangeFailedChargeAttempts |
| paddy@2 | 23 subscriptionChangeLastFailedCharge |
| paddy@0 | 24 subscriptionChangeLastNotified |
| paddy@0 | 25 ) |
| paddy@0 | 26 |
| paddy@1 | 27 func init() { |
| paddy@1 | 28 if os.Getenv("PG_TEST_DB") != "" { |
| paddy@1 | 29 p, err := NewPostgres(os.Getenv("PG_TEST_DB")) |
| paddy@1 | 30 if err != nil { |
| paddy@1 | 31 panic(err) |
| paddy@1 | 32 } |
| paddy@1 | 33 testSubscriptionStores = append(testSubscriptionStores, p) |
| paddy@1 | 34 } |
| paddy@1 | 35 } |
| paddy@1 | 36 |
| paddy@3 | 37 var testSubscriptionStores = []SubscriptionStore{ |
| paddy@0 | 38 NewMemstore(), |
| paddy@0 | 39 } |
| paddy@0 | 40 |
| paddy@0 | 41 func compareSubscriptions(sub1, sub2 Subscription) (bool, string, interface{}, interface{}) { |
| paddy@0 | 42 if !sub1.UserID.Equal(sub2.UserID) { |
| paddy@0 | 43 return false, "UserID", sub1.UserID, sub2.UserID |
| paddy@0 | 44 } |
| paddy@2 | 45 if sub1.StripeSubscription != sub2.StripeSubscription { |
| paddy@2 | 46 return false, "StripeSubscription", sub1.StripeSubscription, sub2.StripeSubscription |
| paddy@0 | 47 } |
| paddy@2 | 48 if sub1.Plan != sub2.Plan { |
| paddy@2 | 49 return false, "Plan", sub1.Plan, sub2.Plan |
| paddy@0 | 50 } |
| paddy@2 | 51 if sub1.Status != sub2.Status { |
| paddy@2 | 52 return false, "Status", sub1.Status, sub2.Status |
| paddy@2 | 53 } |
| paddy@2 | 54 if sub1.Canceling != sub2.Canceling { |
| paddy@2 | 55 return false, "Canceling", sub1.Canceling, sub2.Canceling |
| paddy@0 | 56 } |
| paddy@0 | 57 if !sub1.Created.Equal(sub2.Created) { |
| paddy@0 | 58 return false, "Created", sub1.Created, sub2.Created |
| paddy@0 | 59 } |
| paddy@2 | 60 if !sub1.TrialStart.Equal(sub2.TrialStart) { |
| paddy@2 | 61 return false, "TrialStart", sub1.TrialStart, sub2.TrialStart |
| paddy@0 | 62 } |
| paddy@2 | 63 if !sub1.TrialEnd.Equal(sub2.TrialEnd) { |
| paddy@2 | 64 return false, "TrialEnd", sub1.TrialEnd, sub2.TrialEnd |
| paddy@2 | 65 } |
| paddy@2 | 66 if !sub1.PeriodStart.Equal(sub2.PeriodStart) { |
| paddy@2 | 67 return false, "PeriodStart", sub1.PeriodStart, sub2.PeriodStart |
| paddy@2 | 68 } |
| paddy@2 | 69 if !sub1.PeriodEnd.Equal(sub2.PeriodEnd) { |
| paddy@2 | 70 return false, "PeriodEnd", sub1.PeriodEnd, sub2.PeriodEnd |
| paddy@2 | 71 } |
| paddy@2 | 72 if !sub1.CanceledAt.Equal(sub2.CanceledAt) { |
| paddy@2 | 73 return false, "CanceledAt", sub1.CanceledAt, sub2.CanceledAt |
| paddy@2 | 74 } |
| paddy@2 | 75 if sub1.FailedChargeAttempts != sub2.FailedChargeAttempts { |
| paddy@2 | 76 return false, "FailedChargeAttempts", sub1.FailedChargeAttempts, sub2.FailedChargeAttempts |
| paddy@2 | 77 } |
| paddy@2 | 78 if !sub1.LastFailedCharge.Equal(sub2.LastFailedCharge) { |
| paddy@2 | 79 return false, "LastFailedCharge", sub1.LastFailedCharge, sub2.LastFailedCharge |
| paddy@0 | 80 } |
| paddy@0 | 81 if !sub1.LastNotified.Equal(sub2.LastNotified) { |
| paddy@0 | 82 return false, "LastNotified", sub1.LastNotified, sub2.LastNotified |
| paddy@0 | 83 } |
| paddy@0 | 84 return true, "", nil, nil |
| paddy@0 | 85 } |
| paddy@0 | 86 |
| paddy@0 | 87 func subscriptionMapContains(subscriptionMap map[string]Subscription, subscriptions ...Subscription) (bool, []Subscription) { |
| paddy@0 | 88 var missing []Subscription |
| paddy@0 | 89 for _, sub := range subscriptions { |
| paddy@1 | 90 if _, ok := subscriptionMap[sub.UserID.String()]; !ok { |
| paddy@0 | 91 missing = append(missing, sub) |
| paddy@0 | 92 } |
| paddy@0 | 93 } |
| paddy@0 | 94 if len(missing) > 0 { |
| paddy@0 | 95 return false, missing |
| paddy@0 | 96 } |
| paddy@0 | 97 return true, missing |
| paddy@0 | 98 } |
| paddy@0 | 99 |
| paddy@2 | 100 func compareSubscriptionStats(stat1, stat2 SubscriptionStats) (bool, string, interface{}, interface{}) { |
| paddy@2 | 101 if stat1.Number != stat2.Number { |
| paddy@2 | 102 return false, "Number", stat1.Number, stat2.Number |
| paddy@2 | 103 } |
| paddy@2 | 104 if stat1.Canceling != stat2.Canceling { |
| paddy@2 | 105 return false, "Canceling", stat1.Canceling, stat2.Canceling |
| paddy@2 | 106 } |
| paddy@2 | 107 if stat1.Failing != stat2.Failing { |
| paddy@2 | 108 return false, "Failing", stat1.Failing, stat2.Failing |
| paddy@2 | 109 } |
| paddy@2 | 110 if len(stat1.Plans) != len(stat2.Plans) { |
| paddy@2 | 111 return false, "Plans", stat1.Plans, stat2.Plans |
| paddy@2 | 112 } |
| paddy@2 | 113 for key, count := range stat1.Plans { |
| paddy@2 | 114 count2, ok := stat2.Plans[key] |
| paddy@2 | 115 if !ok { |
| paddy@2 | 116 return false, "Plans", stat1.Plans, stat2.Plans |
| paddy@2 | 117 } |
| paddy@2 | 118 if count != count2 { |
| paddy@2 | 119 return false, "Plans", stat1.Plans, stat2.Plans |
| paddy@2 | 120 } |
| paddy@2 | 121 } |
| paddy@2 | 122 return true, "", nil, nil |
| paddy@2 | 123 } |
| paddy@2 | 124 |
| paddy@0 | 125 func TestCreateSubscription(t *testing.T) { |
| paddy@0 | 126 for _, store := range testSubscriptionStores { |
| paddy@3 | 127 err := store.Reset() |
| paddy@0 | 128 if err != nil { |
| paddy@0 | 129 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 130 } |
| paddy@0 | 131 customerID := uuid.NewID() |
| paddy@0 | 132 sub := Subscription{ |
| paddy@2 | 133 UserID: customerID, |
| paddy@2 | 134 StripeSubscription: "stripeSubscription1", |
| paddy@2 | 135 Created: time.Now().Round(time.Millisecond), |
| paddy@2 | 136 TrialStart: time.Now().Round(time.Millisecond), |
| paddy@2 | 137 TrialEnd: time.Now().Round(time.Millisecond).Add(time.Hour * 24 * 31), |
| paddy@0 | 138 } |
| paddy@3 | 139 err = store.CreateSubscription(sub) |
| paddy@0 | 140 if err != nil { |
| paddy@0 | 141 t.Errorf("Error creating subscription in %T: %+v\n", store, err) |
| paddy@0 | 142 } |
| paddy@3 | 143 retrieved, err := store.GetSubscriptions([]uuid.ID{sub.UserID}) |
| paddy@0 | 144 if err != nil { |
| paddy@0 | 145 t.Errorf("Error retrieving subscription from %T: %+v\n", store, err) |
| paddy@0 | 146 } |
| paddy@1 | 147 if _, returned := retrieved[sub.UserID.String()]; !returned { |
| paddy@1 | 148 t.Errorf("Error retrieving subscription from %T: %s wasn't in the results.", store, sub.UserID) |
| paddy@0 | 149 } |
| paddy@1 | 150 ok, field, expected, result := compareSubscriptions(sub, retrieved[sub.UserID.String()]) |
| paddy@0 | 151 if !ok { |
| paddy@0 | 152 t.Errorf("Expected %s to be %v, got %v from %T\n", field, expected, result, store) |
| paddy@0 | 153 } |
| paddy@3 | 154 err = store.CreateSubscription(sub) |
| paddy@0 | 155 if err != ErrSubscriptionAlreadyExists { |
| paddy@0 | 156 t.Errorf("Unexpected error creating subscription in %T (wanted %+v): %+v\n", store, ErrSubscriptionAlreadyExists, err) |
| paddy@0 | 157 } |
| paddy@1 | 158 sub.UserID = uuid.NewID() |
| paddy@3 | 159 err = store.CreateSubscription(sub) |
| paddy@2 | 160 if err != ErrStripeSubscriptionAlreadyExists { |
| paddy@2 | 161 t.Errorf("Unexpected error creating subscription in %T (wanted %+v): %#+v\n", store, ErrStripeSubscriptionAlreadyExists, err) |
| paddy@0 | 162 } |
| paddy@2 | 163 sub.StripeSubscription = "stripeSubscription2" |
| paddy@3 | 164 err = store.CreateSubscription(sub) |
| paddy@0 | 165 if err != nil { |
| paddy@0 | 166 t.Errorf("Error creating subscription in %T: %+v\n", store, err) |
| paddy@0 | 167 } |
| paddy@0 | 168 } |
| paddy@0 | 169 } |
| paddy@0 | 170 |
| paddy@0 | 171 func TestUpdateSubscription(t *testing.T) { |
| paddy@15 | 172 variations := 1 << 12 |
| paddy@0 | 173 sub := Subscription{ |
| paddy@2 | 174 UserID: uuid.NewID(), |
| paddy@2 | 175 StripeSubscription: "default", |
| paddy@2 | 176 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -24 * -32), |
| paddy@2 | 177 TrialStart: time.Now().Round(time.Millisecond).Add(time.Hour * -24 * -32), |
| paddy@2 | 178 TrialEnd: time.Now().Round(time.Millisecond).Add(time.Hour * -24), |
| paddy@2 | 179 LastNotified: time.Now().Round(time.Millisecond).Add(time.Hour * -24), |
| paddy@0 | 180 } |
| paddy@0 | 181 sub2 := Subscription{ |
| paddy@2 | 182 UserID: uuid.NewID(), |
| paddy@2 | 183 StripeSubscription: "stripeSubscription2", |
| paddy@2 | 184 Created: time.Now().Round(time.Millisecond), |
| paddy@2 | 185 TrialStart: time.Now().Round(time.Millisecond), |
| paddy@2 | 186 TrialEnd: time.Now().Round(time.Millisecond), |
| paddy@2 | 187 LastNotified: time.Now().Round(time.Millisecond), |
| paddy@0 | 188 } |
| paddy@0 | 189 |
| paddy@2 | 190 for _, store := range testSubscriptionStores { |
| paddy@3 | 191 err := store.Reset() |
| paddy@2 | 192 if err != nil { |
| paddy@2 | 193 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@2 | 194 } |
| paddy@3 | 195 err = store.CreateSubscription(sub) |
| paddy@2 | 196 if err != nil { |
| paddy@2 | 197 t.Fatalf("Error saving subscription in %T: %s\n", store, err) |
| paddy@2 | 198 } |
| paddy@2 | 199 for i := 1; i < variations; i++ { |
| paddy@15 | 200 var stripeSubscription, plan, status string |
| paddy@2 | 201 var canceling bool |
| paddy@2 | 202 var failedChargeAttempts int |
| paddy@2 | 203 var trialStart, trialEnd, periodStart, periodEnd, canceledAt, lastFailedCharge, lastNotified time.Time |
| paddy@0 | 204 |
| paddy@2 | 205 change := SubscriptionChange{} |
| paddy@2 | 206 empty := change.IsEmpty() |
| paddy@2 | 207 if !empty { |
| paddy@2 | 208 t.Errorf("Expected empty to be %t, was %t\n", true, empty) |
| paddy@2 | 209 } |
| paddy@2 | 210 result := sub |
| paddy@2 | 211 strI := strconv.Itoa(i) |
| paddy@0 | 212 |
| paddy@2 | 213 if i&subscriptionChangeStripeSubscription != 0 { |
| paddy@2 | 214 stripeSubscription = "stripeSubscription-" + strI |
| paddy@2 | 215 change.StripeSubscription = &stripeSubscription |
| paddy@2 | 216 sub.StripeSubscription = stripeSubscription |
| paddy@2 | 217 } |
| paddy@0 | 218 |
| paddy@2 | 219 if i&subscriptionChangePlan != 0 { |
| paddy@2 | 220 plan = "plan-" + strI |
| paddy@2 | 221 change.Plan = &plan |
| paddy@2 | 222 sub.Plan = plan |
| paddy@2 | 223 } |
| paddy@0 | 224 |
| paddy@2 | 225 if i&subscriptionChangeStatus != 0 { |
| paddy@2 | 226 status = "status-" + strI |
| paddy@2 | 227 change.Status = &status |
| paddy@2 | 228 sub.Status = status |
| paddy@2 | 229 } |
| paddy@0 | 230 |
| paddy@2 | 231 if i&subscriptionChangeCanceling != 0 { |
| paddy@2 | 232 canceling = i%2 == 0 |
| paddy@2 | 233 change.Canceling = &canceling |
| paddy@2 | 234 sub.Canceling = canceling |
| paddy@2 | 235 } |
| paddy@0 | 236 |
| paddy@2 | 237 if i&subscriptionChangeTrialStart != 0 { |
| paddy@2 | 238 trialStart = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@2 | 239 change.TrialStart = &trialStart |
| paddy@2 | 240 sub.TrialStart = trialStart |
| paddy@2 | 241 } |
| paddy@0 | 242 |
| paddy@2 | 243 if i&subscriptionChangeTrialEnd != 0 { |
| paddy@2 | 244 trialEnd = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@2 | 245 change.TrialEnd = &trialEnd |
| paddy@2 | 246 sub.TrialEnd = trialEnd |
| paddy@2 | 247 } |
| paddy@0 | 248 |
| paddy@2 | 249 if i&subscriptionChangePeriodStart != 0 { |
| paddy@2 | 250 periodStart = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@2 | 251 change.PeriodStart = &periodStart |
| paddy@2 | 252 sub.PeriodStart = periodStart |
| paddy@2 | 253 } |
| paddy@0 | 254 |
| paddy@2 | 255 if i&subscriptionChangePeriodEnd != 0 { |
| paddy@2 | 256 periodEnd = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@2 | 257 change.PeriodEnd = &periodEnd |
| paddy@2 | 258 sub.PeriodEnd = periodEnd |
| paddy@2 | 259 } |
| paddy@0 | 260 |
| paddy@2 | 261 if i&subscriptionChangeCanceledAt != 0 { |
| paddy@2 | 262 canceledAt = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@2 | 263 change.CanceledAt = &canceledAt |
| paddy@2 | 264 sub.CanceledAt = canceledAt |
| paddy@0 | 265 } |
| paddy@2 | 266 |
| paddy@2 | 267 if i&subscriptionChangeFailedChargeAttempts != 0 { |
| paddy@2 | 268 failedChargeAttempts = i |
| paddy@2 | 269 change.FailedChargeAttempts = &failedChargeAttempts |
| paddy@2 | 270 sub.FailedChargeAttempts = failedChargeAttempts |
| paddy@2 | 271 } |
| paddy@2 | 272 |
| paddy@2 | 273 if i&subscriptionChangeLastFailedCharge != 0 { |
| paddy@2 | 274 lastFailedCharge = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@2 | 275 change.LastFailedCharge = &lastFailedCharge |
| paddy@2 | 276 sub.LastFailedCharge = lastFailedCharge |
| paddy@2 | 277 } |
| paddy@2 | 278 |
| paddy@2 | 279 if i&subscriptionChangeLastNotified != 0 { |
| paddy@2 | 280 lastNotified = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@2 | 281 change.LastNotified = &lastNotified |
| paddy@2 | 282 sub.LastNotified = lastNotified |
| paddy@2 | 283 } |
| paddy@2 | 284 |
| paddy@2 | 285 empty = change.IsEmpty() |
| paddy@2 | 286 if empty { |
| paddy@2 | 287 t.Errorf("Expected empty to be %t, was %t\n", false, empty) |
| paddy@2 | 288 } |
| paddy@2 | 289 |
| paddy@2 | 290 result.ApplyChange(change) |
| paddy@2 | 291 match, field, expected, got := compareSubscriptions(sub, result) |
| paddy@2 | 292 if !match { |
| paddy@2 | 293 t.Errorf("Expected field `%s` to be `%v`, got `%v`\n", field, expected, got) |
| paddy@0 | 294 } |
| paddy@3 | 295 err = store.UpdateSubscription(sub.UserID, change) |
| paddy@0 | 296 if err != nil { |
| paddy@15 | 297 t.Logf("Change %d: %+v\n", i, change) |
| paddy@15 | 298 if p, ok := store.(Postgres); ok { |
| paddy@15 | 299 query := p.updateSubscriptionSQL(sub.UserID, change) |
| paddy@15 | 300 t.Log(query.String()) |
| paddy@15 | 301 t.Log(query.Args...) |
| paddy@15 | 302 } |
| paddy@0 | 303 t.Errorf("Error updating subscription in %T: %s\n", store, err) |
| paddy@0 | 304 } |
| paddy@3 | 305 retrieved, err := store.GetSubscriptions([]uuid.ID{sub.UserID}) |
| paddy@0 | 306 if err != nil { |
| paddy@0 | 307 t.Errorf("Error getting subscription from %T: %s\n", store, err) |
| paddy@0 | 308 } |
| paddy@0 | 309 ok, missing := subscriptionMapContains(retrieved, sub) |
| paddy@0 | 310 if !ok { |
| paddy@1 | 311 t.Errorf("Expected to retrieve %s from %T, but missing was %+v\n", sub.UserID.String(), store, missing) |
| paddy@0 | 312 } |
| paddy@2 | 313 match, field, expected, got = compareSubscriptions(sub, retrieved[sub.UserID.String()]) |
| paddy@0 | 314 if !match { |
| paddy@0 | 315 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T\n", field, expected, got, store) |
| paddy@0 | 316 } |
| paddy@2 | 317 sub = result |
| paddy@0 | 318 } |
| paddy@2 | 319 |
| paddy@3 | 320 err = store.CreateSubscription(sub2) |
| paddy@0 | 321 if err != nil { |
| paddy@0 | 322 t.Fatalf("Error saving subscription in %T: %+v\n", store, err) |
| paddy@0 | 323 } |
| paddy@0 | 324 change := SubscriptionChange{} |
| paddy@3 | 325 err = store.UpdateSubscription(sub.UserID, change) |
| paddy@0 | 326 if err != ErrSubscriptionChangeEmpty { |
| paddy@0 | 327 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionChangeEmpty, err, store) |
| paddy@0 | 328 } |
| paddy@2 | 329 stripeSubscription := sub2.StripeSubscription |
| paddy@2 | 330 change.StripeSubscription = &stripeSubscription |
| paddy@3 | 331 err = store.UpdateSubscription(uuid.NewID(), change) |
| paddy@0 | 332 if err != ErrSubscriptionNotFound { |
| paddy@0 | 333 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionNotFound, err, store) |
| paddy@0 | 334 } |
| paddy@3 | 335 err = store.UpdateSubscription(sub.UserID, change) |
| paddy@2 | 336 if err != ErrStripeSubscriptionAlreadyExists { |
| paddy@2 | 337 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrStripeSubscriptionAlreadyExists, err, store) |
| paddy@0 | 338 } |
| paddy@0 | 339 } |
| paddy@0 | 340 } |
| paddy@0 | 341 |
| paddy@0 | 342 func TestDeleteSubscription(t *testing.T) { |
| paddy@0 | 343 for _, store := range testSubscriptionStores { |
| paddy@3 | 344 err := store.Reset() |
| paddy@0 | 345 if err != nil { |
| paddy@0 | 346 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 347 } |
| paddy@0 | 348 sub1 := Subscription{ |
| paddy@2 | 349 UserID: uuid.NewID(), |
| paddy@2 | 350 StripeSubscription: "stripeSubscription1", |
| paddy@0 | 351 } |
| paddy@0 | 352 sub2 := Subscription{ |
| paddy@2 | 353 UserID: uuid.NewID(), |
| paddy@2 | 354 StripeSubscription: "stripeSubscription2", |
| paddy@0 | 355 } |
| paddy@3 | 356 err = store.CreateSubscription(sub1) |
| paddy@0 | 357 if err != nil { |
| paddy@0 | 358 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 359 } |
| paddy@3 | 360 err = store.CreateSubscription(sub2) |
| paddy@0 | 361 if err != nil { |
| paddy@2 | 362 t.Fatalf("Error creating %+v in %T: %+v\n", sub2, store, err) |
| paddy@0 | 363 } |
| paddy@3 | 364 err = store.DeleteSubscription(sub1.UserID) |
| paddy@0 | 365 if err != nil { |
| paddy@0 | 366 t.Fatalf("Error deleting %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 367 } |
| paddy@3 | 368 retrieved, err := store.GetSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID}) |
| paddy@0 | 369 if err != nil { |
| paddy@0 | 370 t.Errorf("Error retrieving subscriptions from %T: %+v\n", store, err) |
| paddy@0 | 371 } |
| paddy@0 | 372 ok, missing := subscriptionMapContains(retrieved, sub1) |
| paddy@0 | 373 if ok { |
| paddy@1 | 374 t.Errorf("Expected not to retrieve %s from %T, but missing was %+v\n", sub1.UserID.String(), store, missing) |
| paddy@0 | 375 } |
| paddy@0 | 376 ok, missing = subscriptionMapContains(retrieved, sub2) |
| paddy@0 | 377 if !ok { |
| paddy@1 | 378 t.Errorf("Expected to retrieve %s from %T, but missing was %+v\n", sub2.UserID.String(), store, missing) |
| paddy@0 | 379 } |
| paddy@3 | 380 err = store.DeleteSubscription(sub1.UserID) |
| paddy@0 | 381 if err != ErrSubscriptionNotFound { |
| paddy@0 | 382 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionNotFound, err, store) |
| paddy@0 | 383 } |
| paddy@0 | 384 } |
| paddy@0 | 385 } |
| paddy@0 | 386 |
| paddy@0 | 387 func TestGetSubscriptions(t *testing.T) { |
| paddy@0 | 388 for _, store := range testSubscriptionStores { |
| paddy@3 | 389 err := store.Reset() |
| paddy@0 | 390 if err != nil { |
| paddy@0 | 391 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 392 } |
| paddy@0 | 393 sub1 := Subscription{ |
| paddy@2 | 394 UserID: uuid.NewID(), |
| paddy@2 | 395 StripeSubscription: "stripeSubscription1", |
| paddy@2 | 396 Plan: "plan1", |
| paddy@2 | 397 Created: time.Now().Round(time.Millisecond), |
| paddy@2 | 398 TrialStart: time.Now().Round(time.Millisecond), |
| paddy@2 | 399 TrialEnd: time.Now().Round(time.Millisecond).Add(time.Hour * 24 * 32), |
| paddy@0 | 400 } |
| paddy@0 | 401 sub2 := Subscription{ |
| paddy@2 | 402 UserID: uuid.NewID(), |
| paddy@2 | 403 StripeSubscription: "stripeSubscription2", |
| paddy@2 | 404 Plan: "plan2", |
| paddy@2 | 405 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -720), |
| paddy@2 | 406 TrialStart: time.Now().Round(time.Millisecond).Add(time.Hour * -720), |
| paddy@2 | 407 TrialEnd: time.Now().Round(time.Millisecond), |
| paddy@0 | 408 } |
| paddy@0 | 409 sub3 := Subscription{ |
| paddy@2 | 410 UserID: uuid.NewID(), |
| paddy@2 | 411 StripeSubscription: "stripeSubscription3", |
| paddy@2 | 412 Plan: "plan3", |
| paddy@2 | 413 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -1440), |
| paddy@2 | 414 TrialStart: time.Now().Round(time.Millisecond).Add(time.Hour * -1440), |
| paddy@2 | 415 TrialEnd: time.Now().Round(time.Millisecond).Add(time.Hour * -720), |
| paddy@2 | 416 PeriodStart: time.Now().Round(time.Millisecond).Add(time.Hour * -720), |
| paddy@2 | 417 PeriodEnd: time.Now().Round(time.Millisecond), |
| paddy@2 | 418 Status: "unpaid", |
| paddy@0 | 419 } |
| paddy@3 | 420 err = store.CreateSubscription(sub1) |
| paddy@0 | 421 if err != nil { |
| paddy@0 | 422 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 423 } |
| paddy@3 | 424 err = store.CreateSubscription(sub2) |
| paddy@0 | 425 if err != nil { |
| paddy@0 | 426 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 427 } |
| paddy@3 | 428 err = store.CreateSubscription(sub3) |
| paddy@0 | 429 if err != nil { |
| paddy@0 | 430 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 431 } |
| paddy@3 | 432 retrieved, err := store.GetSubscriptions([]uuid.ID{}) |
| paddy@0 | 433 if err != ErrNoSubscriptionID { |
| paddy@0 | 434 t.Errorf("Error retrieving no subscriptions from %T. Expected %+v, got %+v\n", store, ErrNoSubscriptionID, err) |
| paddy@0 | 435 } |
| paddy@3 | 436 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID}) |
| paddy@0 | 437 if err != nil { |
| paddy@1 | 438 t.Errorf("Error retrieving %s from %T: %+v\n", sub1.UserID, store, err) |
| paddy@0 | 439 } |
| paddy@0 | 440 ok, missing := subscriptionMapContains(retrieved, sub1) |
| paddy@0 | 441 if !ok { |
| paddy@0 | 442 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 443 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 444 } |
| paddy@3 | 445 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID}) |
| paddy@0 | 446 if err != nil { |
| paddy@1 | 447 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub1.UserID, sub2.UserID, store, err) |
| paddy@0 | 448 } |
| paddy@0 | 449 ok, missing = subscriptionMapContains(retrieved, sub1, sub2) |
| paddy@0 | 450 if !ok { |
| paddy@0 | 451 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 452 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 453 } |
| paddy@3 | 454 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID, sub3.UserID}) |
| paddy@0 | 455 if err != nil { |
| paddy@1 | 456 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub1.UserID, sub3.UserID, store, err) |
| paddy@0 | 457 } |
| paddy@0 | 458 ok, missing = subscriptionMapContains(retrieved, sub1, sub3) |
| paddy@0 | 459 if !ok { |
| paddy@0 | 460 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 461 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 462 } |
| paddy@3 | 463 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID, sub3.UserID}) |
| paddy@0 | 464 if err != nil { |
| paddy@1 | 465 t.Errorf("Error retrieving %s, %s, and %s from %T: %+v\n", sub1.UserID, sub2.UserID, sub3.UserID, store, err) |
| paddy@0 | 466 } |
| paddy@0 | 467 ok, missing = subscriptionMapContains(retrieved, sub1, sub2, sub3) |
| paddy@0 | 468 if !ok { |
| paddy@0 | 469 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 470 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 471 } |
| paddy@3 | 472 retrieved, err = store.GetSubscriptions([]uuid.ID{sub2.UserID}) |
| paddy@0 | 473 if err != nil { |
| paddy@1 | 474 t.Errorf("Error retrieving %s from %T: %+v\n", sub2.UserID, store, err) |
| paddy@0 | 475 } |
| paddy@0 | 476 ok, missing = subscriptionMapContains(retrieved, sub2) |
| paddy@0 | 477 if !ok { |
| paddy@0 | 478 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 479 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 480 } |
| paddy@3 | 481 retrieved, err = store.GetSubscriptions([]uuid.ID{sub2.UserID, sub3.UserID}) |
| paddy@0 | 482 if err != nil { |
| paddy@1 | 483 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub2.UserID, sub3.UserID, store, err) |
| paddy@0 | 484 } |
| paddy@0 | 485 ok, missing = subscriptionMapContains(retrieved, sub2, sub3) |
| paddy@0 | 486 if !ok { |
| paddy@0 | 487 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 488 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 489 } |
| paddy@3 | 490 retrieved, err = store.GetSubscriptions([]uuid.ID{sub3.UserID}) |
| paddy@0 | 491 if err != nil { |
| paddy@1 | 492 t.Errorf("Error retrieving %s from %T: %+v\n", sub3.UserID, store, err) |
| paddy@0 | 493 } |
| paddy@0 | 494 ok, missing = subscriptionMapContains(retrieved, sub3) |
| paddy@0 | 495 if !ok { |
| paddy@0 | 496 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 497 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 498 } |
| paddy@3 | 499 retrieved, err = store.GetSubscriptions([]uuid.ID{uuid.NewID()}) |
| paddy@0 | 500 if err != nil { |
| paddy@0 | 501 t.Errorf("Error retrieving non-existent ID from %T: %+v\n", store, err) |
| paddy@0 | 502 } |
| paddy@0 | 503 if len(retrieved) != 0 { |
| paddy@0 | 504 t.Errorf("Expected no results, %T returned %+v\n", store, retrieved) |
| paddy@0 | 505 } |
| paddy@3 | 506 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID, uuid.NewID(), sub3.UserID}) |
| paddy@0 | 507 if err != nil { |
| paddy@0 | 508 t.Errorf("Error retrieving non-existent ID from %T: %+v\n", store, err) |
| paddy@0 | 509 } |
| paddy@0 | 510 if len(retrieved) != 3 { |
| paddy@0 | 511 t.Errorf("Expected 3 results, %T returned %+v\n", store, retrieved) |
| paddy@0 | 512 } |
| paddy@0 | 513 ok, missing = subscriptionMapContains(retrieved, sub1, sub2, sub3) |
| paddy@0 | 514 if !ok { |
| paddy@0 | 515 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 516 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 517 } |
| paddy@0 | 518 } |
| paddy@0 | 519 } |
| paddy@2 | 520 |
| paddy@2 | 521 func TestGetSubscriptionStats(t *testing.T) { |
| paddy@2 | 522 for _, store := range testSubscriptionStores { |
| paddy@3 | 523 err := store.Reset() |
| paddy@2 | 524 if err != nil { |
| paddy@2 | 525 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@2 | 526 } |
| paddy@2 | 527 sub1 := Subscription{ |
| paddy@2 | 528 UserID: uuid.NewID(), |
| paddy@2 | 529 StripeSubscription: "stripeSubscription1", |
| paddy@2 | 530 Plan: "plan1", |
| paddy@2 | 531 Canceling: true, |
| paddy@2 | 532 } |
| paddy@2 | 533 sub2 := Subscription{ |
| paddy@2 | 534 UserID: uuid.NewID(), |
| paddy@2 | 535 StripeSubscription: "stripeSubscription2", |
| paddy@2 | 536 Plan: "plan2", |
| paddy@2 | 537 Status: "past_due", |
| paddy@2 | 538 } |
| paddy@3 | 539 err = store.CreateSubscription(sub1) |
| paddy@2 | 540 if err != nil { |
| paddy@2 | 541 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@2 | 542 } |
| paddy@3 | 543 stats, err := store.GetSubscriptionStats() |
| paddy@2 | 544 if err != nil { |
| paddy@2 | 545 t.Errorf("Error getting stats from %T: %+v\n", store, err) |
| paddy@2 | 546 } |
| paddy@2 | 547 ok, field, expected, results := compareSubscriptionStats(SubscriptionStats{ |
| paddy@2 | 548 Number: 1, |
| paddy@2 | 549 Canceling: 1, |
| paddy@2 | 550 Failing: 0, |
| paddy@2 | 551 Plans: map[string]int64{ |
| paddy@2 | 552 "plan1": 1, |
| paddy@2 | 553 }, |
| paddy@2 | 554 }, stats) |
| paddy@2 | 555 if !ok { |
| paddy@2 | 556 t.Errorf("Expected %s to be %+v, got %+v from %T\n", field, expected, results, store) |
| paddy@2 | 557 } |
| paddy@3 | 558 err = store.CreateSubscription(sub2) |
| paddy@2 | 559 if err != nil { |
| paddy@2 | 560 t.Fatalf("Error creating %+v in %T: %+v\n", sub2, store, err) |
| paddy@2 | 561 } |
| paddy@3 | 562 stats, err = store.GetSubscriptionStats() |
| paddy@2 | 563 if err != nil { |
| paddy@2 | 564 t.Errorf("Error getting status from %T: %+v\n", store, err) |
| paddy@2 | 565 } |
| paddy@2 | 566 ok, field, expected, results = compareSubscriptionStats(SubscriptionStats{ |
| paddy@2 | 567 Number: 2, |
| paddy@2 | 568 Canceling: 1, |
| paddy@2 | 569 Failing: 1, |
| paddy@2 | 570 Plans: map[string]int64{ |
| paddy@2 | 571 "plan1": 1, |
| paddy@2 | 572 "plan2": 1, |
| paddy@2 | 573 }, |
| paddy@2 | 574 }, stats) |
| paddy@2 | 575 if !ok { |
| paddy@2 | 576 t.Errorf("Expected %s to be %+v, got %+v from %T\n", field, expected, results, store) |
| paddy@2 | 577 } |
| paddy@3 | 578 err = store.DeleteSubscription(sub1.UserID) |
| paddy@2 | 579 if err != nil { |
| paddy@2 | 580 t.Errorf("Error deleting subscription from %T: %+v\n", store, err) |
| paddy@2 | 581 } |
| paddy@3 | 582 stats, err = store.GetSubscriptionStats() |
| paddy@2 | 583 if err != nil { |
| paddy@2 | 584 t.Errorf("Error getting status from %T: %+v\n", store, err) |
| paddy@2 | 585 } |
| paddy@2 | 586 ok, field, expected, results = compareSubscriptionStats(SubscriptionStats{ |
| paddy@2 | 587 Number: 1, |
| paddy@2 | 588 Canceling: 0, |
| paddy@2 | 589 Failing: 1, |
| paddy@2 | 590 Plans: map[string]int64{ |
| paddy@2 | 591 "plan2": 1, |
| paddy@2 | 592 }, |
| paddy@2 | 593 }, stats) |
| paddy@2 | 594 if !ok { |
| paddy@2 | 595 t.Errorf("Expected %s to be %+v, got %+v from %T\n", field, expected, results, store) |
| paddy@2 | 596 } |
| paddy@2 | 597 } |
| paddy@2 | 598 } |