chore: 并入 iotlcm-upstream-chan 历史到 upstream-chan/(原提交 1e74497)
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
package upstreamapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/consts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/model"
|
||||
)
|
||||
|
||||
type historyUsageTestChannel struct {
|
||||
model.SimCardChannelI
|
||||
monthlyCalls int
|
||||
dailyCalls int
|
||||
monthlyBatchCalls int
|
||||
dailyBatchCalls int
|
||||
currentCalls int
|
||||
}
|
||||
|
||||
func (c *historyUsageTestChannel) QuerySimDataUsageMonthly(_ context.Context, input *model.SimDataUsageMonthlyInput) (model.SimDataUsageMonthlyOutput, error) {
|
||||
c.monthlyCalls++
|
||||
output := make(model.SimDataUsageMonthlyOutput, 0, len(input.SimKeys))
|
||||
for _, simKey := range input.SimKeys {
|
||||
output = append(output, &model.SimBaseRes[model.SimDataUsageMonthlyOutputItem]{
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusSuccess,
|
||||
})
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (c *historyUsageTestChannel) QuerySimDataUsageDaily(_ context.Context, input *model.SimDataUsageDailyInput) (model.SimDataUsageDailyOutput, error) {
|
||||
c.dailyCalls++
|
||||
output := make(model.SimDataUsageDailyOutput, 0, len(input.SimKeys))
|
||||
for _, simKey := range input.SimKeys {
|
||||
output = append(output, &model.SimBaseRes[model.SimDataUsageDailyOutputItem]{
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusSuccess,
|
||||
})
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (c *historyUsageTestChannel) QuerySimDataUsageMonthlyBatch(_ context.Context, input *model.SimDataUsageMonthlyInput) (model.SimDataUsageMonthlyOutput, error) {
|
||||
c.monthlyBatchCalls++
|
||||
return c.QuerySimDataUsageMonthly(context.Background(), input)
|
||||
}
|
||||
|
||||
func (c *historyUsageTestChannel) QuerySimDataUsageDailyBatch(_ context.Context, input *model.SimDataUsageDailyInput) (model.SimDataUsageDailyOutput, error) {
|
||||
c.dailyBatchCalls++
|
||||
return c.QuerySimDataUsageDaily(context.Background(), input)
|
||||
}
|
||||
|
||||
func (c *historyUsageTestChannel) QuerySimCardStatusBatch(_ context.Context, _ *model.SimCardStatusInput) (model.SimCardStatusOutput, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *historyUsageTestChannel) QuerySimDataUsage(_ context.Context, input *model.SimDataUsageInput) (model.SimDataUsageOutput, error) {
|
||||
c.currentCalls++
|
||||
output := make(model.SimDataUsageOutput, 0, len(input.SimKeys))
|
||||
for _, simKey := range input.SimKeys {
|
||||
output = append(output, &model.SimBaseRes[model.SimDataUsageItem]{
|
||||
SimKey: simKey,
|
||||
Code: consts.ApiStatusSuccess,
|
||||
})
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func TestValidateHistoricalPeriodAtUTC8Boundary(t *testing.T) {
|
||||
now := time.Date(2026, time.September, 2, 16, 0, 0, 0, time.UTC)
|
||||
|
||||
monthCases := []struct {
|
||||
name string
|
||||
queryDate string
|
||||
want string
|
||||
}{
|
||||
{name: "previous month", queryDate: "202608", want: ""},
|
||||
{name: "current month", queryDate: "202609", want: historicalMonthRangeError},
|
||||
{name: "future month", queryDate: "202610", want: historicalMonthRangeError},
|
||||
{name: "empty month", queryDate: "", want: historicalMonthFormatError},
|
||||
{name: "hyphenated month", queryDate: "2026-08", want: historicalMonthFormatError},
|
||||
{name: "invalid month", queryDate: "202613", want: historicalMonthFormatError},
|
||||
}
|
||||
for _, tc := range monthCases {
|
||||
t.Run("month "+tc.name, func(t *testing.T) {
|
||||
if got := validateHistoricalMonth(tc.queryDate, now); got != tc.want {
|
||||
t.Fatalf("validateHistoricalMonth(%q) = %q, want %q", tc.queryDate, got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
batchMonthCases := []struct {
|
||||
name string
|
||||
queryDate string
|
||||
want string
|
||||
}{
|
||||
{name: "previous month", queryDate: "202608", want: currentBatchMonthRangeError},
|
||||
{name: "current month", queryDate: "202609", want: ""},
|
||||
{name: "future month", queryDate: "202610", want: currentBatchMonthRangeError},
|
||||
{name: "empty month", queryDate: "", want: historicalMonthFormatError},
|
||||
{name: "invalid month", queryDate: "202613", want: historicalMonthFormatError},
|
||||
}
|
||||
for _, tc := range batchMonthCases {
|
||||
t.Run("batch month "+tc.name, func(t *testing.T) {
|
||||
if got := validateCurrentBatchMonth(tc.queryDate, now); got != tc.want {
|
||||
t.Fatalf("validateCurrentBatchMonth(%q) = %q, want %q", tc.queryDate, got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
dayCases := []struct {
|
||||
name string
|
||||
queryDate string
|
||||
want string
|
||||
}{
|
||||
{name: "previous day", queryDate: "20260902", want: ""},
|
||||
{name: "current day", queryDate: "20260903", want: historicalDailyRangeError},
|
||||
{name: "future day", queryDate: "20260904", want: historicalDailyRangeError},
|
||||
{name: "empty day", queryDate: "", want: historicalDailyFormatError},
|
||||
{name: "hyphenated day", queryDate: "2026-09-02", want: historicalDailyFormatError},
|
||||
{name: "invalid day", queryDate: "20260230", want: historicalDailyFormatError},
|
||||
}
|
||||
for _, tc := range dayCases {
|
||||
t.Run("day "+tc.name, func(t *testing.T) {
|
||||
if got := validateHistoricalDay(tc.queryDate, now); got != tc.want {
|
||||
t.Fatalf("validateHistoricalDay(%q) = %q, want %q", tc.queryDate, got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateHistoricalPeriodAcrossMonthEnd(t *testing.T) {
|
||||
beforeMidnight := time.Date(2026, time.August, 31, 15, 59, 59, 0, time.UTC)
|
||||
afterMidnight := time.Date(2026, time.August, 31, 16, 0, 0, 0, time.UTC)
|
||||
|
||||
if got := validateHistoricalMonth("202608", beforeMidnight); got != historicalMonthRangeError {
|
||||
t.Fatalf("current month before UTC+8 month end = %q", got)
|
||||
}
|
||||
if got := validateHistoricalDay("20260831", beforeMidnight); got != historicalDailyRangeError {
|
||||
t.Fatalf("current day before UTC+8 month end = %q", got)
|
||||
}
|
||||
if got := validateHistoricalMonth("202608", afterMidnight); got != "" {
|
||||
t.Fatalf("completed month after UTC+8 month end = %q", got)
|
||||
}
|
||||
if got := validateHistoricalDay("20260831", afterMidnight); got != "" {
|
||||
t.Fatalf("completed day after UTC+8 month end = %q", got)
|
||||
}
|
||||
if got := validateCurrentBatchMonth("202608", beforeMidnight); got != "" {
|
||||
t.Fatalf("current batch month before UTC+8 month end = %q", got)
|
||||
}
|
||||
if got := validateCurrentBatchMonth("202608", afterMidnight); got != currentBatchMonthRangeError {
|
||||
t.Fatalf("previous batch month after UTC+8 month end = %q", got)
|
||||
}
|
||||
if got := validateCurrentBatchMonth("202609", afterMidnight); got != "" {
|
||||
t.Fatalf("current batch month after UTC+8 month end = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistoricalPeriodValidationSkipsChannels(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
api := NewUpstreamAPI()
|
||||
channel := &historyUsageTestChannel{}
|
||||
api.RegisterChan("test_channel", "v1", &model.SimCardChannelCache{Instance: channel})
|
||||
simKeys := []*model.SimKey{
|
||||
{ChanKey: "test_channel", ICCID: "iccid-1"},
|
||||
{ChanKey: "test_channel", ICCID: "iccid-2"},
|
||||
}
|
||||
now := time.Now().In(historicalPeriodLocation)
|
||||
|
||||
monthly, err := api.QuerySimDataUsageMonthly(ctx, &model.SimDataUsageMonthlyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageMonthlyInputItem{QueryDate: now.Format("200601")},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("QuerySimDataUsageMonthly returned error: %v", err)
|
||||
}
|
||||
assertMonthlyFailures(t, monthly, simKeys, historicalMonthRangeError)
|
||||
|
||||
daily, err := api.QuerySimDataUsageDaily(ctx, &model.SimDataUsageDailyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageDailyInputItem{QueryDate: now.Format("20060102")},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("QuerySimDataUsageDaily returned error: %v", err)
|
||||
}
|
||||
assertDailyFailures(t, daily, simKeys, historicalDailyRangeError)
|
||||
|
||||
monthlyBatch, err := api.QuerySimDataUsageMonthlyBatch(ctx, &model.SimDataUsageMonthlyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageMonthlyInputItem{QueryDate: "999912"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("QuerySimDataUsageMonthlyBatch returned error: %v", err)
|
||||
}
|
||||
assertMonthlyFailures(t, monthlyBatch, simKeys, currentBatchMonthRangeError)
|
||||
|
||||
dailyBatch, err := api.QuerySimDataUsageDailyBatch(ctx, &model.SimDataUsageDailyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageDailyInputItem{QueryDate: "99991231"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("QuerySimDataUsageDailyBatch returned error: %v", err)
|
||||
}
|
||||
assertDailyFailures(t, dailyBatch, simKeys, historicalDailyRangeError)
|
||||
|
||||
invalidMonthly, err := api.QuerySimDataUsageMonthly(ctx, &model.SimDataUsageMonthlyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageMonthlyInputItem{QueryDate: "2026-08"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("invalid monthly query returned error: %v", err)
|
||||
}
|
||||
assertMonthlyFailures(t, invalidMonthly, simKeys, historicalMonthFormatError)
|
||||
|
||||
invalidDaily, err := api.QuerySimDataUsageDailyBatch(ctx, &model.SimDataUsageDailyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageDailyInputItem{QueryDate: ""},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("invalid daily batch query returned error: %v", err)
|
||||
}
|
||||
assertDailyFailures(t, invalidDaily, simKeys, historicalDailyFormatError)
|
||||
|
||||
if channel.monthlyCalls != 0 || channel.dailyCalls != 0 || channel.monthlyBatchCalls != 0 || channel.dailyBatchCalls != 0 {
|
||||
t.Fatalf("rejected periods called channel: %+v", channel)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistoricalPeriodsRouteAndCurrentUsageRemainsAvailable(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
api := NewUpstreamAPI()
|
||||
channel := &historyUsageTestChannel{}
|
||||
api.RegisterChan("test_channel", "v1", &model.SimCardChannelCache{Instance: channel})
|
||||
simKeys := []*model.SimKey{{ChanKey: "test_channel", ICCID: "iccid-1"}}
|
||||
currentMonth := time.Now().In(historicalPeriodLocation).Format(historicalMonthLayout)
|
||||
|
||||
if _, err := api.QuerySimDataUsageMonthly(ctx, &model.SimDataUsageMonthlyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageMonthlyInputItem{QueryDate: "200001"},
|
||||
}); err != nil {
|
||||
t.Fatalf("historical monthly query returned error: %v", err)
|
||||
}
|
||||
if _, err := api.QuerySimDataUsageDaily(ctx, &model.SimDataUsageDailyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageDailyInputItem{QueryDate: "20000101"},
|
||||
}); err != nil {
|
||||
t.Fatalf("historical daily query returned error: %v", err)
|
||||
}
|
||||
if _, err := api.QuerySimDataUsageMonthlyBatch(ctx, &model.SimDataUsageMonthlyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageMonthlyInputItem{QueryDate: currentMonth},
|
||||
}); err != nil {
|
||||
t.Fatalf("current monthly batch query returned error: %v", err)
|
||||
}
|
||||
if _, err := api.QuerySimDataUsageDailyBatch(ctx, &model.SimDataUsageDailyInput{
|
||||
SimKeys: simKeys,
|
||||
ReqData: model.SimDataUsageDailyInputItem{QueryDate: "20000101"},
|
||||
}); err != nil {
|
||||
t.Fatalf("historical daily batch query returned error: %v", err)
|
||||
}
|
||||
if _, err := api.QuerySimDataUsage(ctx, &model.SimDataUsageInput{SimKeys: simKeys}); err != nil {
|
||||
t.Fatalf("current usage query returned error: %v", err)
|
||||
}
|
||||
|
||||
if channel.monthlyCalls != 2 || channel.dailyCalls != 2 || channel.monthlyBatchCalls != 1 || channel.dailyBatchCalls != 1 || channel.currentCalls != 1 {
|
||||
t.Fatalf("unexpected channel calls: %+v", channel)
|
||||
}
|
||||
}
|
||||
|
||||
func assertMonthlyFailures(t *testing.T, output model.SimDataUsageMonthlyOutput, simKeys []*model.SimKey, message string) {
|
||||
t.Helper()
|
||||
if len(output) != len(simKeys) {
|
||||
t.Fatalf("monthly output length = %d, want %d", len(output), len(simKeys))
|
||||
}
|
||||
for i, item := range output {
|
||||
if item.Code != consts.ApiStatusError || item.Message != message || item.SimKey != simKeys[i] {
|
||||
t.Fatalf("monthly output[%d] = %+v", i, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertDailyFailures(t *testing.T, output model.SimDataUsageDailyOutput, simKeys []*model.SimKey, message string) {
|
||||
t.Helper()
|
||||
if len(output) != len(simKeys) {
|
||||
t.Fatalf("daily output length = %d, want %d", len(output), len(simKeys))
|
||||
}
|
||||
for i, item := range output {
|
||||
if item.Code != consts.ApiStatusError || item.Message != message || item.SimKey != simKeys[i] {
|
||||
t.Fatalf("daily output[%d] = %+v", i, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user