ducky/subscriptions

Paddy 2015-09-30 Parent:fb2c0e498e37 Child:b063bc0a6e84

15:aab6ba5ae392 Browse Files

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.

subscription.go subscription_store_test.go

     1.1 --- a/subscription.go	Wed Sep 30 01:03:39 2015 -0700
     1.2 +++ b/subscription.go	Wed Sep 30 01:33:53 2015 -0700
     1.3 @@ -66,11 +66,13 @@
     1.4  type SubscriptionChange struct {
     1.5  	UserID uuid.ID `json:"user_id"`
     1.6  
     1.7 -	// User-controlled
     1.8 +	// User-controlled and not stored in DB (helper properties for the API)
     1.9  	StripeSource *string `json:"stripe_source,omitempty"`
    1.10  	Email        *string `json:"email,omitempty"`
    1.11 -	Plan         *string `json:"plan,omitempty"`
    1.12 -	Canceling    *bool   `json:"cenceling,omitempty"`
    1.13 +
    1.14 +	// User-controlled and stored in DB
    1.15 +	Plan      *string `json:"plan,omitempty"`
    1.16 +	Canceling *bool   `json:"cenceling,omitempty"`
    1.17  
    1.18  	// System-controlled
    1.19  	StripeSubscription   *string    `json:"stripe_subscription,omitempty"`
    1.20 @@ -88,12 +90,6 @@
    1.21  // IsEmpty returns true if the SubscriptionChange doesn't request
    1.22  // a change to any property of the Subscription.
    1.23  func (change SubscriptionChange) IsEmpty() bool {
    1.24 -	if change.StripeSource != nil {
    1.25 -		return false
    1.26 -	}
    1.27 -	if change.Email != nil {
    1.28 -		return false
    1.29 -	}
    1.30  	if change.Plan != nil {
    1.31  		return false
    1.32  	}
     2.1 --- a/subscription_store_test.go	Wed Sep 30 01:03:39 2015 -0700
     2.2 +++ b/subscription_store_test.go	Wed Sep 30 01:33:53 2015 -0700
     2.3 @@ -10,9 +10,7 @@
     2.4  )
     2.5  
     2.6  const (
     2.7 -	subscriptionChangeStripeSource = 1 << iota
     2.8 -	subscriptionChangeEmail
     2.9 -	subscriptionChangeStripeSubscription
    2.10 +	subscriptionChangeStripeSubscription = 1 << iota
    2.11  	subscriptionChangePlan
    2.12  	subscriptionChangeStatus
    2.13  	subscriptionChangeCanceling
    2.14 @@ -171,7 +169,7 @@
    2.15  }
    2.16  
    2.17  func TestUpdateSubscription(t *testing.T) {
    2.18 -	variations := 1 << 14
    2.19 +	variations := 1 << 12
    2.20  	sub := Subscription{
    2.21  		UserID:             uuid.NewID(),
    2.22  		StripeSubscription: "default",
    2.23 @@ -199,7 +197,7 @@
    2.24  			t.Fatalf("Error saving subscription in %T: %s\n", store, err)
    2.25  		}
    2.26  		for i := 1; i < variations; i++ {
    2.27 -			var stripeSource, email, stripeSubscription, plan, status string
    2.28 +			var stripeSubscription, plan, status string
    2.29  			var canceling bool
    2.30  			var failedChargeAttempts int
    2.31  			var trialStart, trialEnd, periodStart, periodEnd, canceledAt, lastFailedCharge, lastNotified time.Time
    2.32 @@ -212,16 +210,6 @@
    2.33  			result := sub
    2.34  			strI := strconv.Itoa(i)
    2.35  
    2.36 -			if i&subscriptionChangeStripeSource != 0 {
    2.37 -				stripeSource = "stripeSource-" + strI
    2.38 -				change.StripeSource = &stripeSource
    2.39 -			}
    2.40 -
    2.41 -			if i&subscriptionChangeEmail != 0 {
    2.42 -				email = "email-" + strI
    2.43 -				change.Email = &email
    2.44 -			}
    2.45 -
    2.46  			if i&subscriptionChangeStripeSubscription != 0 {
    2.47  				stripeSubscription = "stripeSubscription-" + strI
    2.48  				change.StripeSubscription = &stripeSubscription
    2.49 @@ -306,6 +294,12 @@
    2.50  			}
    2.51  			err = store.UpdateSubscription(sub.UserID, change)
    2.52  			if err != nil {
    2.53 +				t.Logf("Change %d: %+v\n", i, change)
    2.54 +				if p, ok := store.(Postgres); ok {
    2.55 +					query := p.updateSubscriptionSQL(sub.UserID, change)
    2.56 +					t.Log(query.String())
    2.57 +					t.Log(query.Args...)
    2.58 +				}
    2.59  				t.Errorf("Error updating subscription in %T: %s\n", store, err)
    2.60  			}
    2.61  			retrieved, err := store.GetSubscriptions([]uuid.ID{sub.UserID})