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