2019-11-26 17:58:51 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package stripecoinpayments_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2020-01-18 02:34:06 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-11-26 17:58:51 +00:00
|
|
|
|
2020-01-18 02:34:06 +00:00
|
|
|
"storj.io/common/memory"
|
2019-12-27 11:48:47 +00:00
|
|
|
"storj.io/common/testcontext"
|
|
|
|
"storj.io/common/testrand"
|
2020-03-30 10:08:50 +01:00
|
|
|
"storj.io/common/uuid"
|
2019-11-26 17:58:51 +00:00
|
|
|
"storj.io/storj/satellite"
|
2020-01-18 02:34:06 +00:00
|
|
|
"storj.io/storj/satellite/console"
|
2019-11-26 17:58:51 +00:00
|
|
|
"storj.io/storj/satellite/payments"
|
|
|
|
"storj.io/storj/satellite/payments/stripecoinpayments"
|
|
|
|
"storj.io/storj/satellite/satellitedb/satellitedbtest"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestCouponRepository(t *testing.T) {
|
2020-01-19 16:29:15 +00:00
|
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
2019-11-26 17:58:51 +00:00
|
|
|
couponsRepo := db.StripeCoinPayments().Coupons()
|
|
|
|
coupon := payments.Coupon{
|
2020-01-07 10:41:19 +00:00
|
|
|
Duration: 2,
|
2019-11-26 17:58:51 +00:00
|
|
|
Amount: 10,
|
|
|
|
Status: payments.CouponActive,
|
|
|
|
Description: "description",
|
2020-04-02 15:18:08 +01:00
|
|
|
UserID: testrand.UUID(),
|
2019-11-26 17:58:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
now := time.Now().UTC()
|
|
|
|
|
|
|
|
t.Run("insert", func(t *testing.T) {
|
2020-05-19 11:36:13 +01:00
|
|
|
_, err := couponsRepo.Insert(ctx, coupon)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2019-11-26 17:58:51 +00:00
|
|
|
|
|
|
|
coupons, err := couponsRepo.List(ctx, payments.CouponActive)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(coupons))
|
2019-11-26 17:58:51 +00:00
|
|
|
coupon = coupons[0]
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("update", func(t *testing.T) {
|
2020-05-19 11:36:13 +01:00
|
|
|
_, err := couponsRepo.Update(ctx, coupon.ID, payments.CouponUsed)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2019-11-26 17:58:51 +00:00
|
|
|
|
|
|
|
coupons, err := couponsRepo.List(ctx, payments.CouponUsed)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, payments.CouponUsed, coupons[0].Status)
|
2019-11-26 17:58:51 +00:00
|
|
|
coupon = coupons[0]
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("get latest on empty table return stripecoinpayments.ErrNoCouponUsages", func(t *testing.T) {
|
|
|
|
_, err := couponsRepo.GetLatest(ctx, coupon.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
require.Equal(t, true, stripecoinpayments.ErrNoCouponUsages.Has(err))
|
2019-11-26 17:58:51 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("total on empty table returns 0", func(t *testing.T) {
|
|
|
|
total, err := couponsRepo.TotalUsage(ctx, coupon.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, int64(0), total)
|
2019-11-26 17:58:51 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("add usage", func(t *testing.T) {
|
|
|
|
err := couponsRepo.AddUsage(ctx, stripecoinpayments.CouponUsage{
|
|
|
|
CouponID: coupon.ID,
|
|
|
|
Amount: 1,
|
2020-01-07 10:41:19 +00:00
|
|
|
Period: now,
|
2019-11-26 17:58:51 +00:00
|
|
|
})
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2019-11-26 17:58:51 +00:00
|
|
|
date, err := couponsRepo.GetLatest(ctx, coupon.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-01-16 21:10:33 +00:00
|
|
|
// go and postgres has different precision. go - nanoseconds, postgres micro
|
2020-06-28 04:56:29 +01:00
|
|
|
require.Equal(t, date.UTC(), now.Truncate(time.Microsecond))
|
2019-11-26 17:58:51 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("total usage", func(t *testing.T) {
|
|
|
|
amount, err := couponsRepo.TotalUsage(ctx, coupon.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, amount, int64(1))
|
2019-11-26 17:58:51 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
// 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 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 i have next 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.
|
|
|
|
// 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. Next step - is populating coupons for all 5 users. Only 2 coupons should be added.
|
|
|
|
// 7. Creating new user with project.
|
|
|
|
// 8. Populating coupons again. For 6 users above. Only 1 new coupon should be added.
|
|
|
|
// Three new coupons total should be added by 2 runs of PopulatePromotionalCoupons method.
|
|
|
|
func TestPopulatePromotionalCoupons(t *testing.T) {
|
2020-01-19 16:29:15 +00:00
|
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
2020-01-18 02:34:06 +00:00
|
|
|
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{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
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{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
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{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
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{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
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{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
// creating projects for users above.
|
|
|
|
proj1, err := projectsRepo.Insert(ctx, &console.Project{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
Name: "proj 1 of user 1",
|
|
|
|
Description: "descr 1",
|
|
|
|
OwnerID: user1.ID,
|
|
|
|
})
|
2020-01-29 00:57:15 +00:00
|
|
|
require.NoError(t, err)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
// should not be processed as we takes only first project of the user.
|
|
|
|
proj2, err := projectsRepo.Insert(ctx, &console.Project{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
Name: "proj 2 of user 1",
|
|
|
|
Description: "descr 2",
|
|
|
|
OwnerID: user1.ID,
|
|
|
|
})
|
2020-01-29 00:57:15 +00:00
|
|
|
require.NoError(t, err)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
proj3, err := projectsRepo.Insert(ctx, &console.Project{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
Name: "proj 1 of user 2",
|
|
|
|
Description: "descr 3",
|
|
|
|
OwnerID: user2.ID,
|
|
|
|
})
|
2020-01-29 00:57:15 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-04-02 15:18:08 +01:00
|
|
|
couponID := testrand.UUID()
|
2020-05-19 11:36:13 +01:00
|
|
|
_, err = couponsRepo.Insert(ctx, payments.Coupon{
|
2020-01-18 02:34:06 +00:00
|
|
|
ID: couponID,
|
|
|
|
UserID: user5.ID,
|
|
|
|
Amount: 5500,
|
|
|
|
Duration: 2,
|
|
|
|
Description: "qw",
|
|
|
|
Type: payments.CouponTypePromotional,
|
|
|
|
Status: payments.CouponActive,
|
|
|
|
})
|
2020-01-29 00:57:15 +00:00
|
|
|
require.NoError(t, err)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
// creating new users and projects to test that multiple execution of populate method wont generate extra coupons.
|
|
|
|
user6, err := usersRepo.Insert(ctx, &console.User{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
proj5, err := projectsRepo.Insert(ctx, &console.Project{
|
2020-04-02 15:18:08 +01:00
|
|
|
ID: testrand.UUID(),
|
2020-01-18 02:34:06 +00:00
|
|
|
Name: "proj 1 of user 6",
|
|
|
|
Description: "descr 6",
|
|
|
|
OwnerID: user6.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,
|
|
|
|
}
|
|
|
|
err := couponsRepo.PopulatePromotionalCoupons(ctx, usersIds, 2, 5500, memory.TB)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user1Coupons, err := couponsRepo.ListByUserID(ctx, user1.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(user1Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
proj1Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj1.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-06 00:02:12 +01:00
|
|
|
require.Equal(t, memory.TB.Int64(), *proj1Usage)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
proj2Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj2.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-23 15:59:04 +01:00
|
|
|
// require.Nil(t, proj2Usage)
|
|
|
|
require.Equal(t, memory.GB.Int64()*50, *proj2Usage)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user2Coupons, err := couponsRepo.ListByUserID(ctx, user2.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(user2Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
proj3Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj3.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-06 00:02:12 +01:00
|
|
|
require.Equal(t, memory.TB.Int64(), *proj3Usage)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user3Coupons, err := couponsRepo.ListByUserID(ctx, user3.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(user3Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user4Coupons, err := couponsRepo.ListByUserID(ctx, user4.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(user4Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user5Coupons, err := couponsRepo.ListByUserID(ctx, user5.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(user5Coupons))
|
|
|
|
require.Equal(t, "qw", user5Coupons[0].Description)
|
2020-01-18 02:34:06 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("second population", func(t *testing.T) {
|
|
|
|
var usersIds = []uuid.UUID{
|
|
|
|
user1.ID,
|
|
|
|
user2.ID,
|
|
|
|
user3.ID,
|
|
|
|
user4.ID,
|
|
|
|
user5.ID,
|
|
|
|
user6.ID,
|
|
|
|
}
|
|
|
|
err := couponsRepo.PopulatePromotionalCoupons(ctx, usersIds, 2, 5500, memory.TB)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user1Coupons, err := couponsRepo.ListByUserID(ctx, user1.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(user1Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
proj1Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj1.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-06 00:02:12 +01:00
|
|
|
require.Equal(t, memory.TB.Int64(), *proj1Usage)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
proj2Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj2.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-23 15:59:04 +01:00
|
|
|
// require.Nil(t, proj2Usage)
|
|
|
|
require.Equal(t, memory.GB.Int64()*50, *proj2Usage)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user2Coupons, err := couponsRepo.ListByUserID(ctx, user2.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(user2Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
proj3Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj3.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-06 00:02:12 +01:00
|
|
|
require.Equal(t, memory.TB.Int64(), *proj3Usage)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user3Coupons, err := couponsRepo.ListByUserID(ctx, user3.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(user3Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user4Coupons, err := couponsRepo.ListByUserID(ctx, user4.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(user4Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user5Coupons, err := couponsRepo.ListByUserID(ctx, user5.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(user5Coupons))
|
|
|
|
require.Equal(t, "qw", user5Coupons[0].Description)
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
user6Coupons, err := couponsRepo.ListByUserID(ctx, user6.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(user6Coupons))
|
2020-01-18 02:34:06 +00:00
|
|
|
|
|
|
|
proj5Usage, err := usageRepo.GetProjectStorageLimit(ctx, proj5.ID)
|
2020-01-20 12:27:38 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-06 00:02:12 +01:00
|
|
|
require.Equal(t, memory.TB.Int64(), *proj5Usage)
|
2020-01-18 02:34:06 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|