ducky/subscriptions
ducky/subscriptions/subscription_store_test.go
Implement PostgreSQL support, drop subscription IDs. Create a Postgres object that wraps database/sql, so we can attach methods to it and fulfill interfaces. Create a postgres_init.sql script that will create the subscriptions table in a PostgreSQL database. Make our period type fulfill the driver.Valuer and driver.Scanner types, so it can be stored in and retrieved from SQL databases. Create a SubscriptionStats type, and add a method to our subscriptionStore interface that will allow us to retrieve current stats about the Subscriptions it is storing. Deprecated the ID property of our Subscription type, and use the Subscription.UserID property instead as our primary key. Subscriptions should be unique per user and we generally will want to access Subscriptions in the context of the User they belong to, so the UserID is a better primary key. This also means we removed the getSubscriptionByUserID method (and implementations) from our subscriptionStore, as getSubscriptions now fills that role. Implement our getSubscriptionStats method in the memstore. Implement the subscriptionStore interface on our new Postgres type. Run the subscription store tests on our Postgres type, as well, if the PG_TEST_DB environment variable is set. Round all our timestamps in our tests to the nearest millisecond, as Postgres silently truncates all timestamps to the nearest millisecond, and it was causing false test failures. Remove the tests for our getSubscriptionStoreByUser method, as that was removed.
| 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@0 | 13 subscriptionChangeStripeCustomer = 1 << iota |
| paddy@0 | 14 subscriptionChangeAmount |
| paddy@0 | 15 subscriptionChangePeriod |
| paddy@0 | 16 subscriptionChangeBeginCharging |
| paddy@0 | 17 subscriptionChangeLastCharged |
| paddy@0 | 18 subscriptionChangeLastNotified |
| paddy@0 | 19 subscriptionChangeInLockout |
| paddy@0 | 20 ) |
| paddy@0 | 21 |
| paddy@1 | 22 func init() { |
| paddy@1 | 23 if os.Getenv("PG_TEST_DB") != "" { |
| paddy@1 | 24 p, err := NewPostgres(os.Getenv("PG_TEST_DB")) |
| paddy@1 | 25 if err != nil { |
| paddy@1 | 26 panic(err) |
| paddy@1 | 27 } |
| paddy@1 | 28 testSubscriptionStores = append(testSubscriptionStores, p) |
| paddy@1 | 29 } |
| paddy@1 | 30 } |
| paddy@1 | 31 |
| paddy@0 | 32 var testSubscriptionStores = []subscriptionStore{ |
| paddy@0 | 33 NewMemstore(), |
| paddy@0 | 34 } |
| paddy@0 | 35 |
| paddy@0 | 36 func compareSubscriptions(sub1, sub2 Subscription) (bool, string, interface{}, interface{}) { |
| paddy@0 | 37 if !sub1.UserID.Equal(sub2.UserID) { |
| paddy@0 | 38 return false, "UserID", sub1.UserID, sub2.UserID |
| paddy@0 | 39 } |
| paddy@0 | 40 if sub1.StripeCustomer != sub2.StripeCustomer { |
| paddy@0 | 41 return false, "StripeCustomer", sub1.StripeCustomer, sub2.StripeCustomer |
| paddy@0 | 42 } |
| paddy@0 | 43 if sub1.Amount != sub2.Amount { |
| paddy@0 | 44 return false, "Amount", sub1.Amount, sub2.Amount |
| paddy@0 | 45 } |
| paddy@0 | 46 if sub1.Period != sub2.Period { |
| paddy@0 | 47 return false, "Period", sub1.Period, sub2.Period |
| paddy@0 | 48 } |
| paddy@0 | 49 if !sub1.Created.Equal(sub2.Created) { |
| paddy@0 | 50 return false, "Created", sub1.Created, sub2.Created |
| paddy@0 | 51 } |
| paddy@0 | 52 if !sub1.BeginCharging.Equal(sub2.BeginCharging) { |
| paddy@0 | 53 return false, "BeginCharging", sub1.BeginCharging, sub2.BeginCharging |
| paddy@0 | 54 } |
| paddy@0 | 55 if !sub1.LastCharged.Equal(sub2.LastCharged) { |
| paddy@0 | 56 return false, "LastCharged", sub1.LastCharged, sub2.LastCharged |
| paddy@0 | 57 } |
| paddy@0 | 58 if !sub1.LastNotified.Equal(sub2.LastNotified) { |
| paddy@0 | 59 return false, "LastNotified", sub1.LastNotified, sub2.LastNotified |
| paddy@0 | 60 } |
| paddy@0 | 61 if sub1.InLockout != sub2.InLockout { |
| paddy@0 | 62 return false, "InLockout", sub1.InLockout, sub2.InLockout |
| paddy@0 | 63 } |
| paddy@0 | 64 return true, "", nil, nil |
| paddy@0 | 65 } |
| paddy@0 | 66 |
| paddy@0 | 67 func subscriptionMapContains(subscriptionMap map[string]Subscription, subscriptions ...Subscription) (bool, []Subscription) { |
| paddy@0 | 68 var missing []Subscription |
| paddy@0 | 69 for _, sub := range subscriptions { |
| paddy@1 | 70 if _, ok := subscriptionMap[sub.UserID.String()]; !ok { |
| paddy@0 | 71 missing = append(missing, sub) |
| paddy@0 | 72 } |
| paddy@0 | 73 } |
| paddy@0 | 74 if len(missing) > 0 { |
| paddy@0 | 75 return false, missing |
| paddy@0 | 76 } |
| paddy@0 | 77 return true, missing |
| paddy@0 | 78 } |
| paddy@0 | 79 |
| paddy@0 | 80 func TestCreateSubscription(t *testing.T) { |
| paddy@0 | 81 for _, store := range testSubscriptionStores { |
| paddy@0 | 82 err := store.reset() |
| paddy@0 | 83 if err != nil { |
| paddy@0 | 84 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 85 } |
| paddy@0 | 86 customerID := uuid.NewID() |
| paddy@0 | 87 sub := Subscription{ |
| paddy@0 | 88 UserID: customerID, |
| paddy@0 | 89 StripeCustomer: "stripeCustomer1", |
| paddy@0 | 90 Amount: 200, |
| paddy@0 | 91 Period: MonthlyPeriod, |
| paddy@1 | 92 Created: time.Now().Round(time.Millisecond), |
| paddy@1 | 93 BeginCharging: time.Now().Round(time.Millisecond).Add(time.Hour), |
| paddy@0 | 94 } |
| paddy@0 | 95 err = store.createSubscription(sub) |
| paddy@0 | 96 if err != nil { |
| paddy@0 | 97 t.Errorf("Error creating subscription in %T: %+v\n", store, err) |
| paddy@0 | 98 } |
| paddy@1 | 99 retrieved, err := store.getSubscriptions([]uuid.ID{sub.UserID}) |
| paddy@0 | 100 if err != nil { |
| paddy@0 | 101 t.Errorf("Error retrieving subscription from %T: %+v\n", store, err) |
| paddy@0 | 102 } |
| paddy@1 | 103 if _, returned := retrieved[sub.UserID.String()]; !returned { |
| paddy@1 | 104 t.Errorf("Error retrieving subscription from %T: %s wasn't in the results.", store, sub.UserID) |
| paddy@0 | 105 } |
| paddy@1 | 106 ok, field, expected, result := compareSubscriptions(sub, retrieved[sub.UserID.String()]) |
| paddy@0 | 107 if !ok { |
| paddy@0 | 108 t.Errorf("Expected %s to be %v, got %v from %T\n", field, expected, result, store) |
| paddy@0 | 109 } |
| paddy@0 | 110 err = store.createSubscription(sub) |
| paddy@0 | 111 if err != ErrSubscriptionAlreadyExists { |
| paddy@0 | 112 t.Errorf("Unexpected error creating subscription in %T (wanted %+v): %+v\n", store, ErrSubscriptionAlreadyExists, err) |
| paddy@0 | 113 } |
| paddy@1 | 114 sub.UserID = uuid.NewID() |
| paddy@0 | 115 err = store.createSubscription(sub) |
| paddy@0 | 116 if err != ErrStripeCustomerAlreadyExists { |
| paddy@1 | 117 t.Errorf("Unexpected error creating subscription in %T (wanted %+v): %#+v\n", store, ErrStripeCustomerAlreadyExists, err) |
| paddy@0 | 118 } |
| paddy@0 | 119 sub.StripeCustomer = "stripeCustomer2" |
| paddy@0 | 120 err = store.createSubscription(sub) |
| paddy@0 | 121 if err != nil { |
| paddy@0 | 122 t.Errorf("Error creating subscription in %T: %+v\n", store, err) |
| paddy@0 | 123 } |
| paddy@0 | 124 } |
| paddy@0 | 125 } |
| paddy@0 | 126 |
| paddy@0 | 127 func TestUpdateSubscription(t *testing.T) { |
| paddy@0 | 128 variations := 1 << 7 |
| paddy@0 | 129 sub := Subscription{ |
| paddy@0 | 130 UserID: uuid.NewID(), |
| paddy@0 | 131 StripeCustomer: "default", |
| paddy@0 | 132 Amount: -1, |
| paddy@0 | 133 Period: MonthlyPeriod, |
| paddy@1 | 134 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -24), |
| paddy@1 | 135 BeginCharging: time.Now().Round(time.Millisecond).Add(time.Hour * -24), |
| paddy@1 | 136 LastCharged: time.Now().Round(time.Millisecond).Add(time.Hour * -24), |
| paddy@1 | 137 LastNotified: time.Now().Round(time.Millisecond).Add(time.Hour * -24), |
| paddy@0 | 138 InLockout: true, |
| paddy@0 | 139 } |
| paddy@0 | 140 sub2 := Subscription{ |
| paddy@0 | 141 UserID: uuid.NewID(), |
| paddy@0 | 142 StripeCustomer: "stripeCustomer2", |
| paddy@0 | 143 Amount: -2, |
| paddy@0 | 144 Period: MonthlyPeriod, |
| paddy@1 | 145 Created: time.Now().Round(time.Millisecond), |
| paddy@1 | 146 BeginCharging: time.Now().Round(time.Millisecond), |
| paddy@1 | 147 LastCharged: time.Now().Round(time.Millisecond), |
| paddy@1 | 148 LastNotified: time.Now().Round(time.Millisecond), |
| paddy@0 | 149 InLockout: false, |
| paddy@0 | 150 } |
| paddy@0 | 151 |
| paddy@0 | 152 for i := 1; i < variations; i++ { |
| paddy@0 | 153 var stripeCustomer string |
| paddy@0 | 154 var amount int |
| paddy@0 | 155 var inLockout bool |
| paddy@0 | 156 var per period |
| paddy@0 | 157 var beginCharging, lastCharged, lastNotified time.Time |
| paddy@0 | 158 |
| paddy@0 | 159 change := SubscriptionChange{} |
| paddy@0 | 160 empty := change.IsEmpty() |
| paddy@0 | 161 if !empty { |
| paddy@0 | 162 t.Errorf("Expected empty to be %t, was %t\n", true, empty) |
| paddy@0 | 163 } |
| paddy@0 | 164 expectation := sub |
| paddy@0 | 165 result := sub |
| paddy@0 | 166 strI := strconv.Itoa(i) |
| paddy@0 | 167 |
| paddy@0 | 168 if i&subscriptionChangeStripeCustomer != 0 { |
| paddy@0 | 169 stripeCustomer = "stripeCustomer-" + strI |
| paddy@0 | 170 change.StripeCustomer = &stripeCustomer |
| paddy@0 | 171 expectation.StripeCustomer = stripeCustomer |
| paddy@0 | 172 } |
| paddy@0 | 173 |
| paddy@0 | 174 if i&subscriptionChangeAmount != 0 { |
| paddy@0 | 175 amount = i |
| paddy@0 | 176 change.Amount = &amount |
| paddy@0 | 177 expectation.Amount = amount |
| paddy@0 | 178 } |
| paddy@0 | 179 |
| paddy@0 | 180 if i&subscriptionChangePeriod != 0 { |
| paddy@0 | 181 per = period("period-" + strI) |
| paddy@0 | 182 change.Period = &per |
| paddy@0 | 183 expectation.Period = per |
| paddy@0 | 184 } |
| paddy@0 | 185 |
| paddy@0 | 186 if i&subscriptionChangeBeginCharging != 0 { |
| paddy@1 | 187 beginCharging = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@0 | 188 change.BeginCharging = &beginCharging |
| paddy@0 | 189 expectation.BeginCharging = beginCharging |
| paddy@0 | 190 } |
| paddy@0 | 191 |
| paddy@0 | 192 if i&subscriptionChangeLastCharged != 0 { |
| paddy@1 | 193 lastCharged = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@0 | 194 change.LastCharged = &lastCharged |
| paddy@0 | 195 expectation.LastCharged = lastCharged |
| paddy@0 | 196 } |
| paddy@0 | 197 |
| paddy@0 | 198 if i&subscriptionChangeLastNotified != 0 { |
| paddy@1 | 199 lastNotified = time.Now().Round(time.Millisecond).Add(time.Hour * time.Duration(i)) |
| paddy@0 | 200 change.LastNotified = &lastNotified |
| paddy@0 | 201 expectation.LastNotified = lastNotified |
| paddy@0 | 202 } |
| paddy@0 | 203 |
| paddy@0 | 204 if i&subscriptionChangeInLockout != 0 { |
| paddy@0 | 205 inLockout = i%2 == 0 |
| paddy@0 | 206 change.InLockout = &inLockout |
| paddy@0 | 207 expectation.InLockout = inLockout |
| paddy@0 | 208 } |
| paddy@0 | 209 |
| paddy@0 | 210 empty = change.IsEmpty() |
| paddy@0 | 211 if empty { |
| paddy@0 | 212 t.Errorf("Expected empty to be %t, was %t\n", false, empty) |
| paddy@0 | 213 } |
| paddy@0 | 214 |
| paddy@0 | 215 result.ApplyChange(change) |
| paddy@0 | 216 match, field, expected, got := compareSubscriptions(expectation, result) |
| paddy@0 | 217 if !match { |
| paddy@0 | 218 t.Errorf("Expected field `%s` to be `%v`, got `%v`\n", field, expected, got) |
| paddy@0 | 219 } |
| paddy@0 | 220 for _, store := range testSubscriptionStores { |
| paddy@0 | 221 err := store.reset() |
| paddy@0 | 222 if err != nil { |
| paddy@0 | 223 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 224 } |
| paddy@0 | 225 err = store.createSubscription(sub) |
| paddy@0 | 226 if err != nil { |
| paddy@0 | 227 t.Fatalf("Error saving subscription in %T: %s\n", store, err) |
| paddy@0 | 228 } |
| paddy@1 | 229 err = store.updateSubscription(sub.UserID, change) |
| paddy@0 | 230 if err != nil { |
| paddy@0 | 231 t.Errorf("Error updating subscription in %T: %s\n", store, err) |
| paddy@0 | 232 } |
| paddy@1 | 233 retrieved, err := store.getSubscriptions([]uuid.ID{sub.UserID}) |
| paddy@0 | 234 if err != nil { |
| paddy@0 | 235 t.Errorf("Error getting subscription from %T: %s\n", store, err) |
| paddy@0 | 236 } |
| paddy@0 | 237 ok, missing := subscriptionMapContains(retrieved, sub) |
| paddy@0 | 238 if !ok { |
| paddy@1 | 239 t.Errorf("Expected to retrieve %s from %T, but missing was %+v\n", sub.UserID.String(), store, missing) |
| paddy@0 | 240 } |
| paddy@1 | 241 match, field, expected, got = compareSubscriptions(expectation, retrieved[sub.UserID.String()]) |
| paddy@0 | 242 if !match { |
| paddy@0 | 243 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T\n", field, expected, got, store) |
| paddy@0 | 244 } |
| paddy@0 | 245 } |
| paddy@0 | 246 } |
| paddy@0 | 247 for _, store := range testSubscriptionStores { |
| paddy@0 | 248 err := store.reset() |
| paddy@0 | 249 if err != nil { |
| paddy@0 | 250 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 251 } |
| paddy@0 | 252 err = store.createSubscription(sub) |
| paddy@0 | 253 if err != nil { |
| paddy@0 | 254 t.Fatalf("Error saving subscription in %T: %+v\n", store, err) |
| paddy@0 | 255 } |
| paddy@0 | 256 err = store.createSubscription(sub2) |
| paddy@0 | 257 if err != nil { |
| paddy@0 | 258 t.Fatalf("Error saving subscription in %T: %+v\n", store, err) |
| paddy@0 | 259 } |
| paddy@0 | 260 change := SubscriptionChange{} |
| paddy@1 | 261 err = store.updateSubscription(sub.UserID, change) |
| paddy@0 | 262 if err != ErrSubscriptionChangeEmpty { |
| paddy@0 | 263 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionChangeEmpty, err, store) |
| paddy@0 | 264 } |
| paddy@0 | 265 stripeCustomer := sub2.StripeCustomer |
| paddy@0 | 266 change.StripeCustomer = &stripeCustomer |
| paddy@0 | 267 err = store.updateSubscription(uuid.NewID(), change) |
| paddy@0 | 268 if err != ErrSubscriptionNotFound { |
| paddy@0 | 269 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionNotFound, err, store) |
| paddy@0 | 270 } |
| paddy@1 | 271 err = store.updateSubscription(sub.UserID, change) |
| paddy@0 | 272 if err != ErrStripeCustomerAlreadyExists { |
| paddy@0 | 273 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrStripeCustomerAlreadyExists, err, store) |
| paddy@0 | 274 } |
| paddy@0 | 275 } |
| paddy@0 | 276 } |
| paddy@0 | 277 |
| paddy@0 | 278 func TestDeleteSubscription(t *testing.T) { |
| paddy@0 | 279 for _, store := range testSubscriptionStores { |
| paddy@0 | 280 err := store.reset() |
| paddy@0 | 281 if err != nil { |
| paddy@0 | 282 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 283 } |
| paddy@0 | 284 sub1 := Subscription{ |
| paddy@0 | 285 UserID: uuid.NewID(), |
| paddy@0 | 286 StripeCustomer: "stripeCustomer1", |
| paddy@0 | 287 } |
| paddy@0 | 288 sub2 := Subscription{ |
| paddy@0 | 289 UserID: uuid.NewID(), |
| paddy@0 | 290 StripeCustomer: "stripeCustomer2", |
| paddy@0 | 291 } |
| paddy@0 | 292 err = store.createSubscription(sub1) |
| paddy@0 | 293 if err != nil { |
| paddy@0 | 294 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 295 } |
| paddy@0 | 296 err = store.createSubscription(sub2) |
| paddy@0 | 297 if err != nil { |
| paddy@0 | 298 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 299 } |
| paddy@1 | 300 err = store.deleteSubscription(sub1.UserID) |
| paddy@0 | 301 if err != nil { |
| paddy@0 | 302 t.Fatalf("Error deleting %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 303 } |
| paddy@1 | 304 retrieved, err := store.getSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID}) |
| paddy@0 | 305 if err != nil { |
| paddy@0 | 306 t.Errorf("Error retrieving subscriptions from %T: %+v\n", store, err) |
| paddy@0 | 307 } |
| paddy@0 | 308 ok, missing := subscriptionMapContains(retrieved, sub1) |
| paddy@0 | 309 if ok { |
| paddy@1 | 310 t.Errorf("Expected not to retrieve %s from %T, but missing was %+v\n", sub1.UserID.String(), store, missing) |
| paddy@0 | 311 } |
| paddy@0 | 312 ok, missing = subscriptionMapContains(retrieved, sub2) |
| paddy@0 | 313 if !ok { |
| paddy@1 | 314 t.Errorf("Expected to retrieve %s from %T, but missing was %+v\n", sub2.UserID.String(), store, missing) |
| paddy@0 | 315 } |
| paddy@1 | 316 err = store.deleteSubscription(sub1.UserID) |
| paddy@0 | 317 if err != ErrSubscriptionNotFound { |
| paddy@0 | 318 t.Errorf("Expected err to be %+v, but got %+v from %T\n", ErrSubscriptionNotFound, err, store) |
| paddy@0 | 319 } |
| paddy@0 | 320 } |
| paddy@0 | 321 } |
| paddy@0 | 322 |
| paddy@0 | 323 func TestListSubscriptionsLastChargedBefore(t *testing.T) { |
| paddy@0 | 324 for _, store := range testSubscriptionStores { |
| paddy@0 | 325 err := store.reset() |
| paddy@0 | 326 if err != nil { |
| paddy@0 | 327 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 328 } |
| paddy@0 | 329 sub1 := Subscription{ |
| paddy@0 | 330 UserID: uuid.NewID(), |
| paddy@0 | 331 StripeCustomer: "stripeCustomer1", |
| paddy@0 | 332 Amount: 200, |
| paddy@0 | 333 Period: MonthlyPeriod, |
| paddy@1 | 334 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -24 * 32), |
| paddy@1 | 335 BeginCharging: time.Now().Round(time.Millisecond).Add(time.Hour * -24), |
| paddy@1 | 336 LastCharged: time.Now().Round(time.Millisecond).Add(time.Hour * -24), |
| paddy@0 | 337 } |
| paddy@0 | 338 sub2 := Subscription{ |
| paddy@0 | 339 UserID: uuid.NewID(), |
| paddy@0 | 340 StripeCustomer: "stripeCustomer2", |
| paddy@0 | 341 Amount: 300, |
| paddy@0 | 342 Period: MonthlyPeriod, |
| paddy@1 | 343 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -24 * 61), |
| paddy@1 | 344 BeginCharging: time.Now().Round(time.Millisecond).Add(time.Hour * -24 * 31), |
| paddy@1 | 345 LastCharged: time.Now().Round(time.Millisecond).Add(time.Hour * -24 * 31), |
| paddy@0 | 346 } |
| paddy@0 | 347 sub3 := Subscription{ |
| paddy@0 | 348 UserID: uuid.NewID(), |
| paddy@0 | 349 StripeCustomer: "stripeCustomer3", |
| paddy@0 | 350 Amount: 100, |
| paddy@0 | 351 Period: MonthlyPeriod, |
| paddy@1 | 352 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -1), |
| paddy@1 | 353 BeginCharging: time.Now().Round(time.Millisecond).Add(time.Hour * 31), |
| paddy@0 | 354 LastCharged: time.Time{}, |
| paddy@0 | 355 } |
| paddy@0 | 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@0 | 360 err = store.createSubscription(sub2) |
| paddy@0 | 361 if err != nil { |
| paddy@0 | 362 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 363 } |
| paddy@0 | 364 err = store.createSubscription(sub3) |
| paddy@0 | 365 if err != nil { |
| paddy@0 | 366 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 367 } |
| paddy@0 | 368 t.Logf("sub1: %+v\n", sub1) |
| paddy@0 | 369 t.Logf("sub2: %+v\n", sub2) |
| paddy@0 | 370 t.Logf("sub3: %+v\n", sub3) |
| paddy@0 | 371 // subscriptions last charged before right now |
| paddy@0 | 372 // should be sub1, sub2, and sub3 |
| paddy@1 | 373 results, err := store.listSubscriptionsLastChargedBefore(time.Now().Round(time.Millisecond)) |
| paddy@0 | 374 if err != nil { |
| paddy@0 | 375 t.Errorf("Unexpected error listing subscriptions in %T: %+v\n", store, err) |
| paddy@0 | 376 } |
| paddy@0 | 377 if len(results) != 3 { |
| paddy@0 | 378 t.Errorf("Expected three results from %T, got %+v\n", store, results) |
| paddy@0 | 379 } |
| paddy@0 | 380 ok, field, expected, result := compareSubscriptions(sub3, results[0]) |
| paddy@0 | 381 if !ok { |
| paddy@0 | 382 t.Errorf("Expected %s in pos 0 to be %+v, got %+v from %T", field, expected, result, store) |
| paddy@0 | 383 } |
| paddy@0 | 384 ok, field, expected, result = compareSubscriptions(sub2, results[1]) |
| paddy@0 | 385 if !ok { |
| paddy@0 | 386 t.Errorf("Expected %s in pos 1 to be %+v, got %+v from %T", field, expected, result, store) |
| paddy@0 | 387 } |
| paddy@0 | 388 ok, field, expected, result = compareSubscriptions(sub1, results[2]) |
| paddy@0 | 389 if !ok { |
| paddy@0 | 390 t.Errorf("Expected %s in pos 2 to be %+v, got %+v from %T", field, expected, result, store) |
| paddy@0 | 391 } |
| paddy@0 | 392 // subscriptions last charged before a week ago |
| paddy@0 | 393 // should be sub2, sub3 |
| paddy@1 | 394 results, err = store.listSubscriptionsLastChargedBefore(time.Now().Round(time.Millisecond).Add(time.Hour * -24 * 7)) |
| paddy@0 | 395 if err != nil { |
| paddy@0 | 396 t.Errorf("Unexpected error listing subscriptions in %T: %+v\n", store, err) |
| paddy@0 | 397 } |
| paddy@0 | 398 if len(results) != 2 { |
| paddy@0 | 399 t.Errorf("Expected two results from %T, got %+v\n", store, results) |
| paddy@0 | 400 } |
| paddy@0 | 401 ok, field, expected, result = compareSubscriptions(sub3, results[0]) |
| paddy@0 | 402 if !ok { |
| paddy@0 | 403 t.Errorf("Expected %s in pos 0 to be %+v, got %+v from %T", field, expected, result, store) |
| paddy@0 | 404 } |
| paddy@0 | 405 ok, field, expected, result = compareSubscriptions(sub2, results[1]) |
| paddy@0 | 406 if !ok { |
| paddy@0 | 407 t.Errorf("Expected %s in pos 1 to be %+v, got %+v from %T", field, expected, result, store) |
| paddy@0 | 408 } |
| paddy@0 | 409 // subscriptions last charged before 32 days ago |
| paddy@0 | 410 // should be sub3 |
| paddy@1 | 411 results, err = store.listSubscriptionsLastChargedBefore(time.Now().Round(time.Millisecond).Add(time.Hour * -24 * 32)) |
| paddy@0 | 412 if err != nil { |
| paddy@0 | 413 t.Errorf("Unexpected error listing subscriptions in %T: %+v\n", store, err) |
| paddy@0 | 414 } |
| paddy@0 | 415 if len(results) != 1 { |
| paddy@0 | 416 t.Errorf("Expected one result from %T, got %+v\n", store, results) |
| paddy@0 | 417 } |
| paddy@0 | 418 ok, field, expected, result = compareSubscriptions(sub3, results[0]) |
| paddy@0 | 419 if !ok { |
| paddy@0 | 420 t.Errorf("Expected %s in pos 0 to be %+v, got %+v from %T", field, expected, result, store) |
| paddy@0 | 421 } |
| paddy@0 | 422 } |
| paddy@0 | 423 } |
| paddy@0 | 424 |
| paddy@0 | 425 func TestGetSubscriptions(t *testing.T) { |
| paddy@0 | 426 for _, store := range testSubscriptionStores { |
| paddy@0 | 427 err := store.reset() |
| paddy@0 | 428 if err != nil { |
| paddy@0 | 429 t.Fatalf("Error resetting %T: %+v\n", store, err) |
| paddy@0 | 430 } |
| paddy@0 | 431 sub1 := Subscription{ |
| paddy@0 | 432 UserID: uuid.NewID(), |
| paddy@0 | 433 StripeCustomer: "stripeCustomer1", |
| paddy@0 | 434 Amount: 200, |
| paddy@0 | 435 Period: MonthlyPeriod, |
| paddy@1 | 436 Created: time.Now().Round(time.Millisecond), |
| paddy@1 | 437 BeginCharging: time.Now().Round(time.Millisecond).Add(time.Hour), |
| paddy@0 | 438 } |
| paddy@0 | 439 sub2 := Subscription{ |
| paddy@0 | 440 UserID: uuid.NewID(), |
| paddy@0 | 441 StripeCustomer: "stripeCustomer2", |
| paddy@0 | 442 Amount: 300, |
| paddy@0 | 443 Period: MonthlyPeriod, |
| paddy@1 | 444 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -720), |
| paddy@1 | 445 BeginCharging: time.Now().Round(time.Millisecond).Add(time.Hour*-720 + time.Hour*2), |
| paddy@1 | 446 LastCharged: time.Now().Round(time.Millisecond), |
| paddy@0 | 447 } |
| paddy@0 | 448 sub3 := Subscription{ |
| paddy@0 | 449 UserID: uuid.NewID(), |
| paddy@0 | 450 StripeCustomer: "stripeCustomer3", |
| paddy@0 | 451 Amount: 100, |
| paddy@0 | 452 Period: MonthlyPeriod, |
| paddy@1 | 453 Created: time.Now().Round(time.Millisecond).Add(time.Hour * -1440), |
| paddy@1 | 454 BeginCharging: time.Now().Round(time.Millisecond).Add(time.Hour * -1440), |
| paddy@1 | 455 LastNotified: time.Now().Round(time.Millisecond).Add(time.Hour * -720), |
| paddy@0 | 456 InLockout: true, |
| paddy@0 | 457 } |
| paddy@0 | 458 err = store.createSubscription(sub1) |
| paddy@0 | 459 if err != nil { |
| paddy@0 | 460 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 461 } |
| paddy@0 | 462 err = store.createSubscription(sub2) |
| paddy@0 | 463 if err != nil { |
| paddy@0 | 464 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 465 } |
| paddy@0 | 466 err = store.createSubscription(sub3) |
| paddy@0 | 467 if err != nil { |
| paddy@0 | 468 t.Fatalf("Error creating %+v in %T: %+v\n", sub1, store, err) |
| paddy@0 | 469 } |
| paddy@0 | 470 retrieved, err := store.getSubscriptions([]uuid.ID{}) |
| paddy@0 | 471 if err != ErrNoSubscriptionID { |
| paddy@0 | 472 t.Errorf("Error retrieving no subscriptions from %T. Expected %+v, got %+v\n", store, ErrNoSubscriptionID, err) |
| paddy@0 | 473 } |
| paddy@1 | 474 retrieved, err = store.getSubscriptions([]uuid.ID{sub1.UserID}) |
| paddy@0 | 475 if err != nil { |
| paddy@1 | 476 t.Errorf("Error retrieving %s from %T: %+v\n", sub1.UserID, store, err) |
| paddy@0 | 477 } |
| paddy@0 | 478 ok, missing := subscriptionMapContains(retrieved, sub1) |
| paddy@0 | 479 if !ok { |
| paddy@0 | 480 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 481 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 482 } |
| paddy@1 | 483 retrieved, err = store.getSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID}) |
| paddy@0 | 484 if err != nil { |
| paddy@1 | 485 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub1.UserID, sub2.UserID, store, err) |
| paddy@0 | 486 } |
| paddy@0 | 487 ok, missing = subscriptionMapContains(retrieved, sub1, sub2) |
| paddy@0 | 488 if !ok { |
| paddy@0 | 489 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 490 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 491 } |
| paddy@1 | 492 retrieved, err = store.getSubscriptions([]uuid.ID{sub1.UserID, sub3.UserID}) |
| paddy@0 | 493 if err != nil { |
| paddy@1 | 494 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub1.UserID, sub3.UserID, store, err) |
| paddy@0 | 495 } |
| paddy@0 | 496 ok, missing = subscriptionMapContains(retrieved, sub1, sub3) |
| paddy@0 | 497 if !ok { |
| paddy@0 | 498 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 499 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 500 } |
| paddy@1 | 501 retrieved, err = store.getSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID, sub3.UserID}) |
| paddy@0 | 502 if err != nil { |
| paddy@1 | 503 t.Errorf("Error retrieving %s, %s, and %s from %T: %+v\n", sub1.UserID, sub2.UserID, sub3.UserID, store, err) |
| paddy@0 | 504 } |
| paddy@0 | 505 ok, missing = subscriptionMapContains(retrieved, sub1, sub2, sub3) |
| paddy@0 | 506 if !ok { |
| paddy@0 | 507 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 508 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 509 } |
| paddy@1 | 510 retrieved, err = store.getSubscriptions([]uuid.ID{sub2.UserID}) |
| paddy@0 | 511 if err != nil { |
| paddy@1 | 512 t.Errorf("Error retrieving %s from %T: %+v\n", sub2.UserID, store, err) |
| paddy@0 | 513 } |
| paddy@0 | 514 ok, missing = subscriptionMapContains(retrieved, sub2) |
| paddy@0 | 515 if !ok { |
| paddy@0 | 516 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 517 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 518 } |
| paddy@1 | 519 retrieved, err = store.getSubscriptions([]uuid.ID{sub2.UserID, sub3.UserID}) |
| paddy@0 | 520 if err != nil { |
| paddy@1 | 521 t.Errorf("Error retrieving %s and %s from %T: %+v\n", sub2.UserID, sub3.UserID, store, err) |
| paddy@0 | 522 } |
| paddy@0 | 523 ok, missing = subscriptionMapContains(retrieved, sub2, sub3) |
| paddy@0 | 524 if !ok { |
| paddy@0 | 525 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 526 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 527 } |
| paddy@1 | 528 retrieved, err = store.getSubscriptions([]uuid.ID{sub3.UserID}) |
| paddy@0 | 529 if err != nil { |
| paddy@1 | 530 t.Errorf("Error retrieving %s from %T: %+v\n", sub3.UserID, store, err) |
| paddy@0 | 531 } |
| paddy@0 | 532 ok, missing = subscriptionMapContains(retrieved, sub3) |
| paddy@0 | 533 if !ok { |
| paddy@0 | 534 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 535 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 536 } |
| paddy@0 | 537 retrieved, err = store.getSubscriptions([]uuid.ID{uuid.NewID()}) |
| paddy@0 | 538 if err != nil { |
| paddy@0 | 539 t.Errorf("Error retrieving non-existent ID from %T: %+v\n", store, err) |
| paddy@0 | 540 } |
| paddy@0 | 541 if len(retrieved) != 0 { |
| paddy@0 | 542 t.Errorf("Expected no results, %T returned %+v\n", store, retrieved) |
| paddy@0 | 543 } |
| paddy@1 | 544 retrieved, err = store.getSubscriptions([]uuid.ID{sub1.UserID, sub2.UserID, uuid.NewID(), sub3.UserID}) |
| paddy@0 | 545 if err != nil { |
| paddy@0 | 546 t.Errorf("Error retrieving non-existent ID from %T: %+v\n", store, err) |
| paddy@0 | 547 } |
| paddy@0 | 548 if len(retrieved) != 3 { |
| paddy@0 | 549 t.Errorf("Expected 3 results, %T returned %+v\n", store, retrieved) |
| paddy@0 | 550 } |
| paddy@0 | 551 ok, missing = subscriptionMapContains(retrieved, sub1, sub2, sub3) |
| paddy@0 | 552 if !ok { |
| paddy@0 | 553 t.Logf("Results: %+v\n", retrieved) |
| paddy@0 | 554 t.Errorf("Expected %+v to be in the results, was not for %T.\n", missing, store) |
| paddy@0 | 555 } |
| paddy@0 | 556 } |
| paddy@0 | 557 } |