ducky/subscriptions

Paddy 2015-09-30 Parent:c4cfceb2f2fb

15:aab6ba5ae392 Go to Latest

ducky/subscriptions/subscription_store_test.go

Log Postgres test failures more verbosely, fix SubscriptionChange.IsEmpty. SubscriptionChange.IsEmpty() would return false even if no actual database operations are going to be performed. This is because we allow information we _don't_ store in the database (Stripe source, Stripe email) to be specified in a SubscriptionChange object, just so we can easily access them. Then we use the Stripe API to store them in Stripe's databases, and turn them into data _we_ store in our database. Think of them as pre-processed values that are never stored raw. The problem is, we were treating these properties the same as the properties we actually stored in the database, and (worse) were running database tests for combinations of these properties, which was causing test failures because we were trying to update no columns in the database. Whoops. I removed these properties from the IsEmpty helper, and removed them from the code that generates the SubscriptionChange permutations for testing. This allows tests to pass, but also stays closer to what the system was designed to do. In tracking down this bug, I discovered that the logging we had for errors when running Postgres tests was inadequate, so I updated the logs when that failure occurs while testing Postgres to help surface future failures faster.

History
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 }