ducky/subscriptions

Paddy 2015-06-30 Parent:b240b6123548 Child:c4cfceb2f2fb

5:fe8f092cc149 Go to Latest

ducky/subscriptions/subscription_store_test.go

Make subscriptions Kubernetes-ready. Update our .hgignore file to include the docker-ready subscripionsd binary (which differs from the local subscriptionsd binary only in that it's statically-compiled for linux). Add a replication controller for subscriptionsd that will spin up the appropriate pods for us and make sure our Stripe and Subscriptionsd secret volumes are attached, so the pods may configure themselves with that private info. Create a Stripe secret volume with a placeholder for the stripe secret key. Create a Subscriptionsd secret volume with the DSN sent to the base64 encoding of an empty string right now (which means subscriptionsd will store data in memory, but whatever.) Create a subscriptionsd service that will route traffic to the subscriptionsd pods created by the replication controller. Create a minimal Dockerfile to get the subscriptionsd binary running on kubernetes. Add a build-docker helper script that will compile a Docker-ready subscriptionsd binary (by compiling it in a Docker container). Copy a Ubuntu ca-certificates.crt file that we'll inject into our Dockerfile so the Stripe SSL can be resolved. Busybox doesn't have any certificates, by default. Create a wrapper script that will be run in the Docker container to read the secrets from our secret volumes and inject them as environment variables, which is what subscriptionsd understands.

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 }