2022-12-01 07:40:52 +00:00
|
|
|
// Copyright (C) 2022 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package paymentsconfig_test
|
|
|
|
|
|
|
|
import (
|
2023-01-11 20:17:54 +00:00
|
|
|
"fmt"
|
2022-12-01 07:40:52 +00:00
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/shopspring/decimal"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2023-01-12 03:41:14 +00:00
|
|
|
"storj.io/storj/satellite/payments"
|
2022-12-01 07:40:52 +00:00
|
|
|
"storj.io/storj/satellite/payments/paymentsconfig"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestProjectUsagePriceOverrides(t *testing.T) {
|
2023-01-12 03:41:14 +00:00
|
|
|
type Prices map[string]payments.ProjectUsagePriceModel
|
2022-12-01 07:40:52 +00:00
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
testID string
|
|
|
|
configValue string
|
|
|
|
expectedModel Prices
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
testID: "empty",
|
|
|
|
configValue: "",
|
|
|
|
expectedModel: Prices{},
|
|
|
|
}, {
|
|
|
|
testID: "missing prices",
|
|
|
|
configValue: "partner",
|
|
|
|
}, {
|
|
|
|
testID: "missing partner",
|
|
|
|
configValue: ":1,2,3",
|
|
|
|
}, {
|
|
|
|
testID: "too few prices",
|
|
|
|
configValue: "partner:1",
|
|
|
|
}, {
|
|
|
|
testID: "single price override",
|
|
|
|
configValue: "partner:1,2,3",
|
|
|
|
expectedModel: Prices{
|
|
|
|
// Shift is to change the precision from TB dollars to MB cents
|
2023-01-12 03:41:14 +00:00
|
|
|
"partner": payments.ProjectUsagePriceModel{
|
2022-12-01 07:40:52 +00:00
|
|
|
StorageMBMonthCents: decimal.NewFromInt(1).Shift(-4),
|
|
|
|
EgressMBCents: decimal.NewFromInt(2).Shift(-4),
|
|
|
|
SegmentMonthCents: decimal.NewFromInt(3).Shift(2),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
testID: "too many prices",
|
|
|
|
configValue: "partner:1,2,3,4",
|
|
|
|
}, {
|
|
|
|
testID: "invalid decimal",
|
|
|
|
configValue: "partner:0.0.1,2,3",
|
|
|
|
}, {
|
|
|
|
testID: "multiple price overrides",
|
|
|
|
configValue: "partner1:1,2,3;partner2:4,5,6",
|
|
|
|
expectedModel: Prices{
|
2023-01-12 03:41:14 +00:00
|
|
|
"partner1": payments.ProjectUsagePriceModel{
|
2022-12-01 07:40:52 +00:00
|
|
|
StorageMBMonthCents: decimal.NewFromInt(1).Shift(-4),
|
|
|
|
EgressMBCents: decimal.NewFromInt(2).Shift(-4),
|
|
|
|
SegmentMonthCents: decimal.NewFromInt(3).Shift(2),
|
|
|
|
},
|
2023-01-12 03:41:14 +00:00
|
|
|
"partner2": payments.ProjectUsagePriceModel{
|
2022-12-01 07:40:52 +00:00
|
|
|
StorageMBMonthCents: decimal.NewFromInt(4).Shift(-4),
|
|
|
|
EgressMBCents: decimal.NewFromInt(5).Shift(-4),
|
|
|
|
SegmentMonthCents: decimal.NewFromInt(6).Shift(2),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
c := c
|
|
|
|
t.Run(c.testID, func(t *testing.T) {
|
|
|
|
price := &paymentsconfig.ProjectUsagePriceOverrides{}
|
|
|
|
err := price.Set(c.configValue)
|
|
|
|
if c.expectedModel == nil {
|
|
|
|
require.Error(t, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
strParts := strings.Split(price.String(), ";")
|
|
|
|
sort.Strings(strParts)
|
|
|
|
require.Equal(t, c.configValue, strings.Join(strParts, ";"))
|
|
|
|
|
|
|
|
models, err := price.ToModels()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, models, len(c.expectedModel))
|
|
|
|
for partner, price := range c.expectedModel {
|
|
|
|
model := models[partner]
|
|
|
|
require.Contains(t, models, partner)
|
|
|
|
require.Equal(t, price.StorageMBMonthCents, model.StorageMBMonthCents)
|
|
|
|
require.Equal(t, price.EgressMBCents, model.EgressMBCents)
|
|
|
|
require.Equal(t, price.SegmentMonthCents, model.SegmentMonthCents)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-01-11 20:17:54 +00:00
|
|
|
|
|
|
|
func TestPackagePlans(t *testing.T) {
|
2023-01-30 22:11:12 +00:00
|
|
|
type packages map[string]payments.PackagePlan
|
2023-01-11 20:17:54 +00:00
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
testID string
|
|
|
|
configValue string
|
|
|
|
expectedPackagePlans packages
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
testID: "empty",
|
|
|
|
configValue: "",
|
|
|
|
expectedPackagePlans: packages{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "missing couponID and price",
|
|
|
|
configValue: "partner",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "missing partner",
|
2023-03-22 15:28:52 +00:00
|
|
|
configValue: ":100,100",
|
2023-01-11 20:17:54 +00:00
|
|
|
}, {
|
|
|
|
testID: "empty price",
|
2023-03-22 15:28:52 +00:00
|
|
|
configValue: "partner:,100",
|
|
|
|
}, {
|
|
|
|
testID: "empty credit",
|
|
|
|
configValue: "partner:100,",
|
2023-01-11 20:17:54 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "too few values",
|
2023-03-22 15:28:52 +00:00
|
|
|
configValue: "partner:100",
|
2023-01-11 20:17:54 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "too many values",
|
2023-03-22 15:28:52 +00:00
|
|
|
configValue: "partner:100,100,200",
|
2023-01-11 20:17:54 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "single package plan",
|
2023-03-22 15:28:52 +00:00
|
|
|
configValue: "partner1:100,200",
|
2023-01-11 20:17:54 +00:00
|
|
|
expectedPackagePlans: packages{
|
2023-01-30 22:11:12 +00:00
|
|
|
"partner1": payments.PackagePlan{
|
2023-03-22 15:28:52 +00:00
|
|
|
Price: 100,
|
|
|
|
Credit: 200,
|
2023-01-11 20:17:54 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "multiple package plans",
|
2023-03-22 15:28:52 +00:00
|
|
|
configValue: "partner1:100,200;partner2:200,300",
|
2023-01-11 20:17:54 +00:00
|
|
|
expectedPackagePlans: packages{
|
2023-01-30 22:11:12 +00:00
|
|
|
"partner1": payments.PackagePlan{
|
2023-03-22 15:28:52 +00:00
|
|
|
Price: 100,
|
|
|
|
Credit: 200,
|
2023-01-11 20:17:54 +00:00
|
|
|
},
|
2023-01-30 22:11:12 +00:00
|
|
|
"partner2": payments.PackagePlan{
|
2023-03-22 15:28:52 +00:00
|
|
|
Price: 200,
|
|
|
|
Credit: 300,
|
2023-01-11 20:17:54 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
c := c
|
|
|
|
t.Run(c.testID, func(t *testing.T) {
|
|
|
|
packagePlans := paymentsconfig.PackagePlans{}
|
|
|
|
err := packagePlans.Set(c.configValue)
|
|
|
|
if c.expectedPackagePlans == nil {
|
|
|
|
require.Error(t, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
strParts := strings.Split(packagePlans.String(), ";")
|
|
|
|
sort.Strings(strParts)
|
|
|
|
require.Equal(t, c.configValue, strings.Join(strParts, ";"))
|
|
|
|
|
|
|
|
for k, v := range c.expectedPackagePlans {
|
|
|
|
p, err := packagePlans.Get([]byte(k))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, v, p)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPackagePlansGet(t *testing.T) {
|
|
|
|
partner := "partnerName1"
|
2023-03-22 15:28:52 +00:00
|
|
|
credit := int64(200)
|
2023-01-11 20:17:54 +00:00
|
|
|
price := int64(100)
|
2023-03-22 15:28:52 +00:00
|
|
|
configStr := fmt.Sprintf("%s:%d,%d", partner, price, credit)
|
2023-01-11 20:17:54 +00:00
|
|
|
|
|
|
|
packagePlans := paymentsconfig.PackagePlans{}
|
|
|
|
require.NoError(t, packagePlans.Set(configStr))
|
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
testID string
|
|
|
|
userAgent []byte
|
|
|
|
shouldPass bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
testID: "user agent matches partner",
|
|
|
|
userAgent: []byte(partner),
|
|
|
|
shouldPass: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "partner is first entry of user agent",
|
|
|
|
userAgent: []byte(partner + "/0.1.2"),
|
|
|
|
shouldPass: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "partner is not first entry of user agent",
|
|
|
|
userAgent: []byte("app2/1.2.3 " + partner + "/1.2.3"),
|
|
|
|
shouldPass: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "partner is a prefix of user agent, but not equal",
|
|
|
|
userAgent: []byte("partnerName12/1.2.3"),
|
|
|
|
shouldPass: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
testID: "partner does not exist in user agent",
|
|
|
|
userAgent: []byte("partnerName2/1.2.3"),
|
|
|
|
shouldPass: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, c := range cases {
|
|
|
|
t.Run(c.testID, func(t *testing.T) {
|
|
|
|
p, err := packagePlans.Get(c.userAgent)
|
|
|
|
if c.shouldPass {
|
|
|
|
require.NoError(t, err)
|
2023-03-22 15:28:52 +00:00
|
|
|
require.Equal(t, credit, p.Credit)
|
2023-01-11 20:17:54 +00:00
|
|
|
require.Equal(t, price, p.Price)
|
|
|
|
} else {
|
|
|
|
require.Error(t, err)
|
|
|
|
require.Empty(t, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|