ducky/subscriptions

Paddy 2015-06-22 Parent:61c4ce5850da Child:c4cfceb2f2fb

3:b240b6123548 Go to Latest

ducky/subscriptions/subscription_store_test.go

Export all subscriptionStore methods. We're not going to wrap all our subscriptionStore interactions in a Context type, so we need to expose all the functions so other packages can call them. Also, it's now SubscriptionStore. Also creates a SubscriptionRequest type that is used to create a new Subscription instance, along with a Validate method on it, to detect errors when creating a SubscriptionRequest. Update our CreateSubscription function to be New, and have it take a SubscriptionRequest, a Stripe instance, and a SubscriptionStore as arguments. It'll create the Subscription in the SubscriptionStore, create a customer in Stripe, and create the subscription in Stripe, then associate the Stripe subscription with the created Subscription. Also, fix our StripeSubscriptionChange function to correctly equate a missing/zero Unix timestamp from Stripe with a missing/zero time.Time.

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@2 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@2 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@2 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@0 297 t.Errorf("Error updating subscription in %T: %s\n", store, err)
paddy@0 298 }
paddy@3 299 retrieved, err := store.GetSubscriptions([]uuid.ID{sub.UserID})
paddy@0 300 if err != nil {
paddy@0 301 t.Errorf("Error getting subscription from %T: %s\n", store, err)
paddy@0 302 }
paddy@0 303 ok, missing := subscriptionMapContains(retrieved, sub)
paddy@0 304 if !ok {
paddy@1 305 t.Errorf("Expected to retrieve %s from %T, but missing was %+v\n", sub.UserID.String(), store, missing)
paddy@0 306 }
paddy@2 307 match, field, expected, got = compareSubscriptions(sub, retrieved[sub.UserID.String()])
paddy@0 308 if !match {
paddy@0 309 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T\n", field, expected, got, store)
paddy@0 310 }
paddy@2 311 sub = result
paddy@0 312 }
paddy@2 313
paddy@3 314 err = store.CreateSubscription(sub2)
paddy@0 315 if err != nil {
paddy@0 316 t.Fatalf("Error saving subscription in %T: %+v\n", store, err)
paddy@0 317 }
paddy@0 318 change := SubscriptionChange{}
paddy@3 319 err = store.UpdateSubscription(sub.UserID, change)
paddy@0 320 if err != ErrSubscriptionChangeEmpty {
paddy@0 321 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionChangeEmpty, err, store)
paddy@0 322 }
paddy@2 323 stripeSubscription := sub2.StripeSubscription
paddy@2 324 change.StripeSubscription = &stripeSubscription
paddy@3 325 err = store.UpdateSubscription(uuid.NewID(), change)
paddy@0 326 if err != ErrSubscriptionNotFound {
paddy@0 327 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionNotFound, err, store)
paddy@0 328 }
paddy@3 329 err = store.UpdateSubscription(sub.UserID, change)
paddy@2 330 if err != ErrStripeSubscriptionAlreadyExists {
paddy@2 331 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrStripeSubscriptionAlreadyExists, err, store)
paddy@0 332 }
paddy@0 333 }
paddy@0 334 }
paddy@0 335
paddy@0 336 func TestDeleteSubscription(t *testing.T) {
paddy@0 337 for _, store := range testSubscriptionStores {
paddy@3 338 err := store.Reset()
paddy@0 339 if err != nil {
paddy@0 340 t.Fatalf("Error resetting %T: %+v\n", store, err)
paddy@0 341 }
paddy@0 342 sub1 := Subscription{
paddy@2 343 UserID: uuid.NewID(),
paddy@2 344 StripeSubscription: "stripeSubscription1",
paddy@0 345 }
paddy@0 346 sub2 := Subscription{
paddy@2 347 UserID: uuid.NewID(),
paddy@2 348 StripeSubscription: "stripeSubscription2",
paddy@0 349 }
paddy@3 350 err = store.CreateSubscription(sub1)
paddy@0 351 if err != nil {
paddy@0 352 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err)
paddy@0 353 }
paddy@3 354 err = store.CreateSubscription(sub2)
paddy@0 355 if err != nil {
paddy@2 356 t.Fatalf("Error creating %+v in %T: %+v\n", sub2, store, err)
paddy@0 357 }
paddy@3 358 err = store.DeleteSubscription(sub1.UserID)
paddy@0 359 if err != nil {
paddy@0 360 t.Fatalf("Error deleting %+v in %T: %+v\n", sub1, store, err)
paddy@0 361 }
paddy@3 362 retrieved, err := store.GetSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID})
paddy@0 363 if err != nil {
paddy@0 364 t.Errorf("Error retrieving subscriptions from %T: %+v\n", store, err)
paddy@0 365 }
paddy@0 366 ok, missing := subscriptionMapContains(retrieved, sub1)
paddy@0 367 if ok {
paddy@1 368 t.Errorf("Expected not to retrieve %s from %T, but missing was %+v\n", sub1.UserID.String(), store, missing)
paddy@0 369 }
paddy@0 370 ok, missing = subscriptionMapContains(retrieved, sub2)
paddy@0 371 if !ok {
paddy@1 372 t.Errorf("Expected to retrieve %s from %T, but missing was %+v\n", sub2.UserID.String(), store, missing)
paddy@0 373 }
paddy@3 374 err = store.DeleteSubscription(sub1.UserID)
paddy@0 375 if err != ErrSubscriptionNotFound {
paddy@0 376 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionNotFound, err, store)
paddy@0 377 }
paddy@0 378 }
paddy@0 379 }
paddy@0 380
paddy@0 381 func TestGetSubscriptions(t *testing.T) {
paddy@0 382 for _, store := range testSubscriptionStores {
paddy@3 383 err := store.Reset()
paddy@0 384 if err != nil {
paddy@0 385 t.Fatalf("Error resetting %T: %+v\n", store, err)
paddy@0 386 }
paddy@0 387 sub1 := Subscription{
paddy@2 388 UserID: uuid.NewID(),
paddy@2 389 StripeSubscription: "stripeSubscription1",
paddy@2 390 Plan: "plan1",
paddy@2 391 Created: time.Now().Round(time.Millisecond),
paddy@2 392 TrialStart: time.Now().Round(time.Millisecond),
paddy@2 393 TrialEnd: time.Now().Round(time.Millisecond).Add(time.Hour * 24 * 32),
paddy@0 394 }
paddy@0 395 sub2 := Subscription{
paddy@2 396 UserID: uuid.NewID(),
paddy@2 397 StripeSubscription: "stripeSubscription2",
paddy@2 398 Plan: "plan2",
paddy@2 399 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -720),
paddy@2 400 TrialStart: time.Now().Round(time.Millisecond).Add(time.Hour * -720),
paddy@2 401 TrialEnd: time.Now().Round(time.Millisecond),
paddy@0 402 }
paddy@0 403 sub3 := Subscription{
paddy@2 404 UserID: uuid.NewID(),
paddy@2 405 StripeSubscription: "stripeSubscription3",
paddy@2 406 Plan: "plan3",
paddy@2 407 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -1440),
paddy@2 408 TrialStart: time.Now().Round(time.Millisecond).Add(time.Hour * -1440),
paddy@2 409 TrialEnd: time.Now().Round(time.Millisecond).Add(time.Hour * -720),
paddy@2 410 PeriodStart: time.Now().Round(time.Millisecond).Add(time.Hour * -720),
paddy@2 411 PeriodEnd: time.Now().Round(time.Millisecond),
paddy@2 412 Status: "unpaid",
paddy@0 413 }
paddy@3 414 err = store.CreateSubscription(sub1)
paddy@0 415 if err != nil {
paddy@0 416 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err)
paddy@0 417 }
paddy@3 418 err = store.CreateSubscription(sub2)
paddy@0 419 if err != nil {
paddy@0 420 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err)
paddy@0 421 }
paddy@3 422 err = store.CreateSubscription(sub3)
paddy@0 423 if err != nil {
paddy@0 424 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err)
paddy@0 425 }
paddy@3 426 retrieved, err := store.GetSubscriptions([]uuid.ID{})
paddy@0 427 if err != ErrNoSubscriptionID {
paddy@0 428 t.Errorf("Error retrieving no subscriptions from %T. Expected %+v, got %+v\n", store, ErrNoSubscriptionID, err)
paddy@0 429 }
paddy@3 430 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID})
paddy@0 431 if err != nil {
paddy@1 432 t.Errorf("Error retrieving %s from %T: %+v\n", sub1.UserID, store, err)
paddy@0 433 }
paddy@0 434 ok, missing := subscriptionMapContains(retrieved, sub1)
paddy@0 435 if !ok {
paddy@0 436 t.Logf("Results: %+v\n", retrieved)
paddy@0 437 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store)
paddy@0 438 }
paddy@3 439 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID})
paddy@0 440 if err != nil {
paddy@1 441 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub1.UserID, sub2.UserID, store, err)
paddy@0 442 }
paddy@0 443 ok, missing = subscriptionMapContains(retrieved, sub1, sub2)
paddy@0 444 if !ok {
paddy@0 445 t.Logf("Results: %+v\n", retrieved)
paddy@0 446 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store)
paddy@0 447 }
paddy@3 448 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID, sub3.UserID})
paddy@0 449 if err != nil {
paddy@1 450 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub1.UserID, sub3.UserID, store, err)
paddy@0 451 }
paddy@0 452 ok, missing = subscriptionMapContains(retrieved, sub1, sub3)
paddy@0 453 if !ok {
paddy@0 454 t.Logf("Results: %+v\n", retrieved)
paddy@0 455 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store)
paddy@0 456 }
paddy@3 457 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID, sub3.UserID})
paddy@0 458 if err != nil {
paddy@1 459 t.Errorf("Error retrieving %s, %s, and %s from %T: %+v\n", sub1.UserID, sub2.UserID, sub3.UserID, store, err)
paddy@0 460 }
paddy@0 461 ok, missing = subscriptionMapContains(retrieved, sub1, sub2, sub3)
paddy@0 462 if !ok {
paddy@0 463 t.Logf("Results: %+v\n", retrieved)
paddy@0 464 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store)
paddy@0 465 }
paddy@3 466 retrieved, err = store.GetSubscriptions([]uuid.ID{sub2.UserID})
paddy@0 467 if err != nil {
paddy@1 468 t.Errorf("Error retrieving %s from %T: %+v\n", sub2.UserID, store, err)
paddy@0 469 }
paddy@0 470 ok, missing = subscriptionMapContains(retrieved, sub2)
paddy@0 471 if !ok {
paddy@0 472 t.Logf("Results: %+v\n", retrieved)
paddy@0 473 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store)
paddy@0 474 }
paddy@3 475 retrieved, err = store.GetSubscriptions([]uuid.ID{sub2.UserID, sub3.UserID})
paddy@0 476 if err != nil {
paddy@1 477 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub2.UserID, sub3.UserID, store, err)
paddy@0 478 }
paddy@0 479 ok, missing = subscriptionMapContains(retrieved, sub2, sub3)
paddy@0 480 if !ok {
paddy@0 481 t.Logf("Results: %+v\n", retrieved)
paddy@0 482 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store)
paddy@0 483 }
paddy@3 484 retrieved, err = store.GetSubscriptions([]uuid.ID{sub3.UserID})
paddy@0 485 if err != nil {
paddy@1 486 t.Errorf("Error retrieving %s from %T: %+v\n", sub3.UserID, store, err)
paddy@0 487 }
paddy@0 488 ok, missing = subscriptionMapContains(retrieved, sub3)
paddy@0 489 if !ok {
paddy@0 490 t.Logf("Results: %+v\n", retrieved)
paddy@0 491 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store)
paddy@0 492 }
paddy@3 493 retrieved, err = store.GetSubscriptions([]uuid.ID{uuid.NewID()})
paddy@0 494 if err != nil {
paddy@0 495 t.Errorf("Error retrieving non-existent ID from %T: %+v\n", store, err)
paddy@0 496 }
paddy@0 497 if len(retrieved) != 0 {
paddy@0 498 t.Errorf("Expected no results, %T returned %+v\n", store, retrieved)
paddy@0 499 }
paddy@3 500 retrieved, err = store.GetSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID, uuid.NewID(), sub3.UserID})
paddy@0 501 if err != nil {
paddy@0 502 t.Errorf("Error retrieving non-existent ID from %T: %+v\n", store, err)
paddy@0 503 }
paddy@0 504 if len(retrieved) != 3 {
paddy@0 505 t.Errorf("Expected 3 results, %T returned %+v\n", store, retrieved)
paddy@0 506 }
paddy@0 507 ok, missing = subscriptionMapContains(retrieved, sub1, sub2, sub3)
paddy@0 508 if !ok {
paddy@0 509 t.Logf("Results: %+v\n", retrieved)
paddy@0 510 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store)
paddy@0 511 }
paddy@0 512 }
paddy@0 513 }
paddy@2 514
paddy@2 515 func TestGetSubscriptionStats(t *testing.T) {
paddy@2 516 for _, store := range testSubscriptionStores {
paddy@3 517 err := store.Reset()
paddy@2 518 if err != nil {
paddy@2 519 t.Fatalf("Error resetting %T: %+v\n", store, err)
paddy@2 520 }
paddy@2 521 sub1 := Subscription{
paddy@2 522 UserID: uuid.NewID(),
paddy@2 523 StripeSubscription: "stripeSubscription1",
paddy@2 524 Plan: "plan1",
paddy@2 525 Canceling: true,
paddy@2 526 }
paddy@2 527 sub2 := Subscription{
paddy@2 528 UserID: uuid.NewID(),
paddy@2 529 StripeSubscription: "stripeSubscription2",
paddy@2 530 Plan: "plan2",
paddy@2 531 Status: "past_due",
paddy@2 532 }
paddy@3 533 err = store.CreateSubscription(sub1)
paddy@2 534 if err != nil {
paddy@2 535 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err)
paddy@2 536 }
paddy@3 537 stats, err := store.GetSubscriptionStats()
paddy@2 538 if err != nil {
paddy@2 539 t.Errorf("Error getting stats from %T: %+v\n", store, err)
paddy@2 540 }
paddy@2 541 ok, field, expected, results := compareSubscriptionStats(SubscriptionStats{
paddy@2 542 Number: 1,
paddy@2 543 Canceling: 1,
paddy@2 544 Failing: 0,
paddy@2 545 Plans: map[string]int64{
paddy@2 546 "plan1": 1,
paddy@2 547 },
paddy@2 548 }, stats)
paddy@2 549 if !ok {
paddy@2 550 t.Errorf("Expected %s to be %+v, got %+v from %T\n", field, expected, results, store)
paddy@2 551 }
paddy@3 552 err = store.CreateSubscription(sub2)
paddy@2 553 if err != nil {
paddy@2 554 t.Fatalf("Error creating %+v in %T: %+v\n", sub2, store, err)
paddy@2 555 }
paddy@3 556 stats, err = store.GetSubscriptionStats()
paddy@2 557 if err != nil {
paddy@2 558 t.Errorf("Error getting status from %T: %+v\n", store, err)
paddy@2 559 }
paddy@2 560 ok, field, expected, results = compareSubscriptionStats(SubscriptionStats{
paddy@2 561 Number: 2,
paddy@2 562 Canceling: 1,
paddy@2 563 Failing: 1,
paddy@2 564 Plans: map[string]int64{
paddy@2 565 "plan1": 1,
paddy@2 566 "plan2": 1,
paddy@2 567 },
paddy@2 568 }, stats)
paddy@2 569 if !ok {
paddy@2 570 t.Errorf("Expected %s to be %+v, got %+v from %T\n", field, expected, results, store)
paddy@2 571 }
paddy@3 572 err = store.DeleteSubscription(sub1.UserID)
paddy@2 573 if err != nil {
paddy@2 574 t.Errorf("Error deleting subscription from %T: %+v\n", store, err)
paddy@2 575 }
paddy@3 576 stats, err = store.GetSubscriptionStats()
paddy@2 577 if err != nil {
paddy@2 578 t.Errorf("Error getting status from %T: %+v\n", store, err)
paddy@2 579 }
paddy@2 580 ok, field, expected, results = compareSubscriptionStats(SubscriptionStats{
paddy@2 581 Number: 1,
paddy@2 582 Canceling: 0,
paddy@2 583 Failing: 1,
paddy@2 584 Plans: map[string]int64{
paddy@2 585 "plan2": 1,
paddy@2 586 },
paddy@2 587 }, stats)
paddy@2 588 if !ok {
paddy@2 589 t.Errorf("Expected %s to be %+v, got %+v from %T\n", field, expected, results, store)
paddy@2 590 }
paddy@2 591 }
paddy@2 592 }