ea772a8480
This change allows users to see the Stripe coupon applied to their account in the billing area. Change-Id: Ie1e810bfb2847f9b0c0bb827d5ca03c16cf5e818
453 lines
14 KiB
Go
453 lines
14 KiB
Go
// Copyright (C) 2019 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package stripecoinpayments_test
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"storj.io/common/memory"
|
|
"storj.io/common/testcontext"
|
|
"storj.io/common/testrand"
|
|
"storj.io/common/uuid"
|
|
"storj.io/storj/satellite"
|
|
"storj.io/storj/satellite/console"
|
|
"storj.io/storj/satellite/payments"
|
|
"storj.io/storj/satellite/payments/stripecoinpayments"
|
|
"storj.io/storj/satellite/satellitedb/satellitedbtest"
|
|
)
|
|
|
|
func TestCouponRepository(t *testing.T) {
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
|
duration := 2
|
|
couponsRepo := db.StripeCoinPayments().Coupons()
|
|
coupon := payments.CouponOld{
|
|
Duration: &duration,
|
|
Amount: 10,
|
|
Status: payments.CouponActive,
|
|
Description: "description",
|
|
UserID: testrand.UUID(),
|
|
}
|
|
|
|
now := time.Now().UTC()
|
|
|
|
t.Run("insert", func(t *testing.T) {
|
|
_, err := couponsRepo.Insert(ctx, coupon)
|
|
require.NoError(t, err)
|
|
|
|
coupons, err := couponsRepo.List(ctx, payments.CouponActive)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(coupons))
|
|
coupon = coupons[0]
|
|
})
|
|
|
|
t.Run("update", func(t *testing.T) {
|
|
_, err := couponsRepo.Update(ctx, coupon.ID, payments.CouponUsed)
|
|
require.NoError(t, err)
|
|
|
|
coupons, err := couponsRepo.List(ctx, payments.CouponUsed)
|
|
require.NoError(t, err)
|
|
require.Equal(t, payments.CouponUsed, coupons[0].Status)
|
|
coupon = coupons[0]
|
|
})
|
|
|
|
t.Run("get latest on empty table return stripecoinpayments.ErrNoCouponUsages", func(t *testing.T) {
|
|
_, err := couponsRepo.GetLatest(ctx, coupon.ID)
|
|
require.Error(t, err)
|
|
require.Equal(t, true, stripecoinpayments.ErrNoCouponUsages.Has(err))
|
|
})
|
|
|
|
t.Run("total on empty table returns 0", func(t *testing.T) {
|
|
total, err := couponsRepo.TotalUsage(ctx, coupon.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(0), total)
|
|
})
|
|
|
|
t.Run("add usage", func(t *testing.T) {
|
|
err := couponsRepo.AddUsage(ctx, stripecoinpayments.CouponUsage{
|
|
CouponID: coupon.ID,
|
|
Amount: 1,
|
|
Period: now,
|
|
})
|
|
require.NoError(t, err)
|
|
date, err := couponsRepo.GetLatest(ctx, coupon.ID)
|
|
require.NoError(t, err)
|
|
// go and postgres has different precision. go - nanoseconds, postgres micro
|
|
require.Equal(t, date.UTC(), now.Truncate(time.Microsecond))
|
|
})
|
|
|
|
t.Run("total usage", func(t *testing.T) {
|
|
amount, err := couponsRepo.TotalUsage(ctx, coupon.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, amount, int64(1))
|
|
})
|
|
})
|
|
}
|
|
|
|
// TestPopulatePromotionalCoupons is a test for PopulatePromotionalCoupons function
|
|
// that creates coupons with predefined values for each of user (from arguments) that have a project
|
|
// and that don't have a valid promotional coupon yet. Also it updates limits of selected projects to 1TB.
|
|
// Because the coupon should be added to a project, we select the first project of the user.
|
|
// In this test we have the following test cases:
|
|
// 1. Activated user, 2 projects, without coupon. For this case we should add new coupon to his first project.
|
|
// 2. Activated user, 1 project, without coupon. Coupon should be added.
|
|
// 3. Activated user without project. Coupon should not be added.
|
|
// 4. User with inactive account. Coupon should not be added.
|
|
// 5. Activated user with project and coupon. Coupon should not be added.
|
|
// 6. Activated user with project and expired coupon. Coupon should be added.
|
|
// 7. Activated user with project and fully consumed, non-expired coupon. Coupon should be added.
|
|
// 8. Next step - is populating coupons for all 7 users. 4 coupons should be added.
|
|
// 9. Creating new user with project.
|
|
// 10. Populating coupons again. For 8 users above. Only 1 new coupon should be added.
|
|
// Five new coupons total should be added by 2 runs of PopulatePromotionalCoupons method.
|
|
func TestPopulatePromotionalCoupons(t *testing.T) {
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
|
usersRepo := db.Console().Users()
|
|
projectsRepo := db.Console().Projects()
|
|
couponsRepo := db.StripeCoinPayments().Coupons()
|
|
usageRepo := db.ProjectAccounting()
|
|
|
|
// creating test users with different status.
|
|
|
|
// activated user with 2 project. New coupon should be added to the first project.
|
|
user1, err := usersRepo.Insert(ctx, &console.User{
|
|
ID: testrand.UUID(),
|
|
FullName: "user1",
|
|
ShortName: "",
|
|
Email: "test1@example.com",
|
|
PasswordHash: []byte("123qwe"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
user1.Status = console.Active
|
|
|
|
err = usersRepo.Update(ctx, user1)
|
|
require.NoError(t, err)
|
|
|
|
// activated user with proj. New coupon should be added.
|
|
user2, err := usersRepo.Insert(ctx, &console.User{
|
|
ID: testrand.UUID(),
|
|
FullName: "user2",
|
|
ShortName: "",
|
|
Email: "test2@example.com",
|
|
PasswordHash: []byte("123qwe"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
user2.Status = console.Active
|
|
|
|
err = usersRepo.Update(ctx, user2)
|
|
require.NoError(t, err)
|
|
|
|
// activated user without proj. New coupon should not be added.
|
|
user3, err := usersRepo.Insert(ctx, &console.User{
|
|
ID: testrand.UUID(),
|
|
FullName: "user3",
|
|
ShortName: "",
|
|
Email: "test3@example.com",
|
|
PasswordHash: []byte("123qwe"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
user3.Status = console.Active
|
|
|
|
err = usersRepo.Update(ctx, user3)
|
|
require.NoError(t, err)
|
|
|
|
// inactive user. New coupon should not be added.
|
|
user4, err := usersRepo.Insert(ctx, &console.User{
|
|
ID: testrand.UUID(),
|
|
FullName: "user4",
|
|
ShortName: "",
|
|
Email: "test4@example.com",
|
|
PasswordHash: []byte("123qwe"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// activated user with proj and coupon. New coupon should not be added.
|
|
user5, err := usersRepo.Insert(ctx, &console.User{
|
|
ID: testrand.UUID(),
|
|
FullName: "user5",
|
|
ShortName: "",
|
|
Email: "test5@example.com",
|
|
PasswordHash: []byte("123qwe"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
user5.Status = console.Active
|
|
|
|
err = usersRepo.Update(ctx, user5)
|
|
require.NoError(t, err)
|
|
|
|
// activated user with proj and expired coupon. New coupon should be added.
|
|
user6, err := usersRepo.Insert(ctx, &console.User{
|
|
ID: testrand.UUID(),
|
|
FullName: "user6",
|
|
ShortName: "",
|
|
Email: "test6@example.com",
|
|
PasswordHash: []byte("123qwe"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
user6.Status = console.Active
|
|
|
|
err = usersRepo.Update(ctx, user6)
|
|
require.NoError(t, err)
|
|
|
|
// activated user with proj and non-expired but consumed coupon. New coupon should be added.
|
|
user7, err := usersRepo.Insert(ctx, &console.User{
|
|
ID: testrand.UUID(),
|
|
FullName: "user7",
|
|
ShortName: "",
|
|
Email: "test7@example.com",
|
|
PasswordHash: []byte("123qwe"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
user7.Status = console.Active
|
|
|
|
err = usersRepo.Update(ctx, user7)
|
|
require.NoError(t, err)
|
|
|
|
// creating projects for users above.
|
|
proj1, err := projectsRepo.Insert(ctx, &console.Project{
|
|
ID: testrand.UUID(),
|
|
Name: "proj 1 of user 1",
|
|
Description: "descr 1",
|
|
OwnerID: user1.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// should not be processed as we takes only first project of the user.
|
|
proj2, err := projectsRepo.Insert(ctx, &console.Project{
|
|
ID: testrand.UUID(),
|
|
Name: "proj 2 of user 1",
|
|
Description: "descr 2",
|
|
OwnerID: user1.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
proj3, err := projectsRepo.Insert(ctx, &console.Project{
|
|
ID: testrand.UUID(),
|
|
Name: "proj 1 of user 2",
|
|
Description: "descr 3",
|
|
OwnerID: user2.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
_, err = projectsRepo.Insert(ctx, &console.Project{
|
|
ID: testrand.UUID(),
|
|
Name: "proj 1 of user 5",
|
|
Description: "descr 4",
|
|
OwnerID: user5.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
_, err = projectsRepo.Insert(ctx, &console.Project{
|
|
ID: testrand.UUID(),
|
|
Name: "proj 1 of user 6",
|
|
Description: "descr 5",
|
|
OwnerID: user6.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
_, err = projectsRepo.Insert(ctx, &console.Project{
|
|
ID: testrand.UUID(),
|
|
Name: "proj 1 of user 7",
|
|
Description: "descr 5",
|
|
OwnerID: user7.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// add coupons to users who should have them before PopulatePromotionalCoupons
|
|
duration := 2
|
|
couponID := testrand.UUID()
|
|
_, err = couponsRepo.Insert(ctx, payments.CouponOld{
|
|
ID: couponID,
|
|
UserID: user5.ID,
|
|
Amount: 5500,
|
|
Duration: &duration,
|
|
Description: "qw",
|
|
Type: payments.CouponTypePromotional,
|
|
Status: payments.CouponActive,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
couponID = testrand.UUID()
|
|
_, err = couponsRepo.Insert(ctx, payments.CouponOld{
|
|
ID: couponID,
|
|
UserID: user6.ID,
|
|
Amount: 1000,
|
|
Duration: &duration,
|
|
Description: "qw",
|
|
Type: payments.CouponTypePromotional,
|
|
Status: payments.CouponExpired,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
couponID = testrand.UUID()
|
|
_, err = couponsRepo.Insert(ctx, payments.CouponOld{
|
|
ID: couponID,
|
|
UserID: user7.ID,
|
|
Amount: 1000,
|
|
Duration: nil,
|
|
Description: "qw",
|
|
Type: payments.CouponTypePromotional,
|
|
Status: payments.CouponUsed,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// creating new users and projects to test that multiple execution of populate method wont generate extra coupons.
|
|
user8, err := usersRepo.Insert(ctx, &console.User{
|
|
ID: testrand.UUID(),
|
|
FullName: "user8",
|
|
ShortName: "",
|
|
Email: "test8@example.com",
|
|
PasswordHash: []byte("123qwe"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
user8.Status = console.Active
|
|
|
|
err = usersRepo.Update(ctx, user8)
|
|
require.NoError(t, err)
|
|
|
|
proj4, err := projectsRepo.Insert(ctx, &console.Project{
|
|
ID: testrand.UUID(),
|
|
Name: "proj 1 of user 8",
|
|
Description: "descr 7",
|
|
OwnerID: user8.ID,
|
|
})
|
|
if err != nil {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
t.Run("first population", func(t *testing.T) {
|
|
var usersIds = []uuid.UUID{
|
|
user1.ID,
|
|
user2.ID,
|
|
user3.ID,
|
|
user4.ID,
|
|
user5.ID,
|
|
user6.ID,
|
|
user7.ID,
|
|
}
|
|
duration := 2
|
|
err := couponsRepo.PopulatePromotionalCoupons(ctx, usersIds, &duration, 5500, memory.TB)
|
|
require.NoError(t, err)
|
|
|
|
user1Coupons, err := couponsRepo.ListByUserID(ctx, user1.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(user1Coupons))
|
|
|
|
proj1Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj1.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, memory.TB.Int64(), *proj1Usage)
|
|
|
|
proj2Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj2.ID)
|
|
require.NoError(t, err)
|
|
require.Nil(t, proj2Usage)
|
|
|
|
user2Coupons, err := couponsRepo.ListByUserID(ctx, user2.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(user2Coupons))
|
|
|
|
proj3Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj3.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, memory.TB.Int64(), *proj3Usage)
|
|
|
|
user3Coupons, err := couponsRepo.ListByUserID(ctx, user3.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(user3Coupons))
|
|
|
|
user4Coupons, err := couponsRepo.ListByUserID(ctx, user4.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(user4Coupons))
|
|
|
|
user5Coupons, err := couponsRepo.ListByUserID(ctx, user5.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(user5Coupons))
|
|
|
|
user6Coupons, err := couponsRepo.ListByUserID(ctx, user6.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(user6Coupons))
|
|
|
|
user7Coupons, err := couponsRepo.ListByUserID(ctx, user7.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(user7Coupons))
|
|
|
|
user8Coupons, err := couponsRepo.ListByUserID(ctx, user8.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(user8Coupons))
|
|
})
|
|
|
|
t.Run("second population", func(t *testing.T) {
|
|
var usersIds = []uuid.UUID{
|
|
user1.ID,
|
|
user2.ID,
|
|
user3.ID,
|
|
user4.ID,
|
|
user5.ID,
|
|
user6.ID,
|
|
user7.ID,
|
|
user8.ID,
|
|
}
|
|
duration := 2
|
|
err := couponsRepo.PopulatePromotionalCoupons(ctx, usersIds, &duration, 5500, memory.TB)
|
|
require.NoError(t, err)
|
|
|
|
user1Coupons, err := couponsRepo.ListByUserID(ctx, user1.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(user1Coupons))
|
|
|
|
proj1Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj1.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, memory.TB.Int64(), *proj1Usage)
|
|
|
|
proj2Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj2.ID)
|
|
require.NoError(t, err)
|
|
require.Nil(t, proj2Usage)
|
|
|
|
user2Coupons, err := couponsRepo.ListByUserID(ctx, user2.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(user2Coupons))
|
|
|
|
proj3Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj3.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, memory.TB.Int64(), *proj3Usage)
|
|
|
|
user3Coupons, err := couponsRepo.ListByUserID(ctx, user3.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(user3Coupons))
|
|
|
|
user4Coupons, err := couponsRepo.ListByUserID(ctx, user4.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(user4Coupons))
|
|
|
|
user5Coupons, err := couponsRepo.ListByUserID(ctx, user5.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(user5Coupons))
|
|
require.Equal(t, "qw", user5Coupons[0].Description)
|
|
|
|
user6Coupons, err := couponsRepo.ListByUserID(ctx, user6.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(user6Coupons))
|
|
|
|
user7Coupons, err := couponsRepo.ListByUserID(ctx, user7.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(user7Coupons))
|
|
|
|
user8Coupons, err := couponsRepo.ListByUserID(ctx, user8.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(user8Coupons))
|
|
|
|
proj4Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj4.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, memory.TB.Int64(), *proj4Usage)
|
|
})
|
|
})
|
|
}
|