151 lines
5.4 KiB
Go
151 lines
5.4 KiB
Go
|
// Copyright (C) 2020 Storj Labs, Inc.
|
||
|
// See LICENSE for copying information.
|
||
|
|
||
|
package stripecoinpayments_test
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strconv"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/stretchr/testify/require"
|
||
|
"github.com/stripe/stripe-go"
|
||
|
|
||
|
"storj.io/common/testcontext"
|
||
|
"storj.io/common/testrand"
|
||
|
"storj.io/storj/private/testplanet"
|
||
|
"storj.io/storj/satellite/payments"
|
||
|
"storj.io/storj/satellite/payments/coinpayments"
|
||
|
"storj.io/storj/satellite/payments/stripecoinpayments"
|
||
|
)
|
||
|
|
||
|
func TestService_MigrateCredits(t *testing.T) {
|
||
|
testplanet.Run(t, testplanet.Config{
|
||
|
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
|
||
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||
|
satellite := planet.Satellites[0]
|
||
|
|
||
|
for i, tt := range []struct {
|
||
|
credits []int64
|
||
|
spedings []int64
|
||
|
}{
|
||
|
{ // user with no credits and spendings
|
||
|
},
|
||
|
{ // user with a single credit, but no spendings
|
||
|
credits: []int64{1000},
|
||
|
},
|
||
|
{ // user with a single credit and spending, some remaining balances
|
||
|
credits: []int64{1000},
|
||
|
spedings: []int64{700},
|
||
|
},
|
||
|
{ // user with a single credit and spending, no remaining balances
|
||
|
credits: []int64{1000},
|
||
|
spedings: []int64{1000},
|
||
|
},
|
||
|
{ // user with a single credit and spending, negative balances
|
||
|
credits: []int64{1000},
|
||
|
spedings: []int64{2000},
|
||
|
},
|
||
|
{ // user with a few credits and spendings, some remaining balance
|
||
|
credits: []int64{100, 200, 300},
|
||
|
spedings: []int64{50, 150},
|
||
|
},
|
||
|
{ // user with a few credits and spendings, no remaining balance
|
||
|
credits: []int64{100, 200, 300},
|
||
|
spedings: []int64{50, 150, 400},
|
||
|
},
|
||
|
{ // user with a few credits and spendings, negative remaining balance
|
||
|
credits: []int64{100, 200},
|
||
|
spedings: []int64{50, 150, 200},
|
||
|
},
|
||
|
} {
|
||
|
errTag := fmt.Sprintf("%d. %+v", i, tt)
|
||
|
|
||
|
user, err := satellite.AddUser(ctx, "testuser"+strconv.Itoa(i), "test@test"+strconv.Itoa(i), 1)
|
||
|
require.NoError(t, err, errTag)
|
||
|
|
||
|
project, err := satellite.AddProject(ctx, user.ID, "testproject-"+strconv.Itoa(i))
|
||
|
require.NoError(t, err, errTag)
|
||
|
|
||
|
// Keep track of the balance when adding all credits and spendings to the database
|
||
|
var initialBalance int64
|
||
|
|
||
|
// Add the credits to the database
|
||
|
for i, credit := range tt.credits {
|
||
|
initialBalance += credit
|
||
|
err = satellite.DB.StripeCoinPayments().Credits().InsertCredit(ctx, payments.Credit{
|
||
|
UserID: user.ID,
|
||
|
TransactionID: coinpayments.TransactionID(user.ID.String() + "-" + strconv.Itoa(i)),
|
||
|
Amount: credit,
|
||
|
Created: time.Now().UTC(),
|
||
|
})
|
||
|
require.NoError(t, err, errTag)
|
||
|
}
|
||
|
|
||
|
// Add the credit spendings to the database
|
||
|
for _, spending := range tt.spedings {
|
||
|
initialBalance -= spending
|
||
|
err = satellite.DB.StripeCoinPayments().Credits().InsertCreditsSpending(ctx, stripecoinpayments.CreditsSpending{
|
||
|
ID: testrand.UUID(),
|
||
|
ProjectID: project.ID,
|
||
|
UserID: user.ID,
|
||
|
Amount: spending,
|
||
|
Status: stripecoinpayments.CreditsSpendingStatusApplied,
|
||
|
Period: time.Now().UTC(),
|
||
|
Created: time.Now().UTC(),
|
||
|
})
|
||
|
require.NoError(t, err, errTag)
|
||
|
}
|
||
|
|
||
|
// Check that the initial credits balance is as expected
|
||
|
balance, err := satellite.DB.StripeCoinPayments().Credits().Balance(ctx, user.ID)
|
||
|
require.NoError(t, err, errTag)
|
||
|
require.EqualValues(t, initialBalance, balance, errTag)
|
||
|
|
||
|
// Migrate the credits to Stripe
|
||
|
err = satellite.API.Payments.Service.MigrateCredits(ctx)
|
||
|
require.NoError(t, err, errTag)
|
||
|
|
||
|
// Check that the credits balance in database is now zero.
|
||
|
balance, err = satellite.DB.StripeCoinPayments().Credits().Balance(ctx, user.ID)
|
||
|
require.NoError(t, err, errTag)
|
||
|
if initialBalance > 0 {
|
||
|
require.Zero(t, balance, errTag)
|
||
|
} else {
|
||
|
// If the initial balance was negative (should not be possible in reality) then after migration it remains the same
|
||
|
require.Equal(t, initialBalance, balance, errTag)
|
||
|
}
|
||
|
|
||
|
customerID, err := satellite.DB.StripeCoinPayments().Customers().GetCustomerID(ctx, user.ID)
|
||
|
require.NoError(t, err, errTag)
|
||
|
|
||
|
it := satellite.API.Payments.Stripe.CustomerBalanceTransactions().List(&stripe.CustomerBalanceTransactionListParams{Customer: stripe.String(customerID)})
|
||
|
if initialBalance > 0 {
|
||
|
// Check that we have only one balance transaction in Stripe, which is the one adding the unspent credits balance
|
||
|
require.True(t, it.Next(), errTag)
|
||
|
cbt := it.CustomerBalanceTransaction()
|
||
|
require.Equal(t, stripe.CustomerBalanceTransactionTypeAdjustment, cbt.Type, errTag)
|
||
|
require.Equal(t, stripecoinpayments.StripeMigratedDepositBonusTransactionDescription, cbt.Description, errTag)
|
||
|
require.EqualValues(t, -initialBalance, cbt.Amount, errTag)
|
||
|
}
|
||
|
require.False(t, it.Next(), errTag)
|
||
|
|
||
|
customer, err := satellite.API.Payments.Stripe.Customers().Get(customerID, nil)
|
||
|
require.NoError(t, err, errTag)
|
||
|
if len(tt.credits) == 0 {
|
||
|
require.Nil(t, customer.Metadata, errTag)
|
||
|
} else {
|
||
|
// Check that the Stripe customer metadata contains the history of added credits
|
||
|
require.NotNil(t, customer.Metadata, errTag)
|
||
|
require.Len(t, customer.Metadata, len(tt.credits), errTag)
|
||
|
for i, credit := range tt.credits {
|
||
|
txID := user.ID.String() + "-" + strconv.Itoa(i)
|
||
|
require.Contains(t, customer.Metadata, "credit_"+txID, errTag)
|
||
|
require.Contains(t, customer.Metadata["credit_"+txID], `"credit":`+strconv.FormatInt(credit, 10), errTag)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
}
|