storj/satellite/payments/stripecoinpayments/coupons_test.go

453 lines
14 KiB
Go
Raw Normal View History

// 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)
})
})
}