Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
b5f78ec1
Commit
b5f78ec1
authored
Mar 14, 2026
by
wucm667
Browse files
feat: 实现固定时间重置模式的 SQL 表达式,并添加相关单元测试
parent
2573107b
Changes
2
Show whitespace changes
Inline
Side-by-side
backend/internal/repository/account_repo.go
View file @
b5f78ec1
...
...
@@ -1747,21 +1747,70 @@ const weeklyExpiredExpr = `(
)`
// nextDailyResetAtExpr is a SQL expression to compute the next daily reset_at when a reset occurs.
// For fixed mode: advances current reset_at by 1 day. For rolling mode: not used (NULL).
// For fixed mode: computes the next future reset time based on NOW(), timezone, and configured hour.
// This correctly handles long-inactive accounts by jumping directly to the next valid reset point.
const
nextDailyResetAtExpr
=
`(
CASE WHEN COALESCE(extra->>'quota_daily_reset_mode', 'rolling') = 'fixed'
THEN to_char(
COALESCE((extra->>'quota_daily_reset_at')::timestamptz, NOW()) + '1 day'::interval
AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
THEN to_char((
-- Compute today's reset point in the configured timezone, then pick next future one
CASE WHEN NOW() >= (
date_trunc('day', NOW() AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC'))
+ (COALESCE((extra->>'quota_daily_reset_hour')::int, 0) || ' hours')::interval
) AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC')
-- NOW() is at or past today's reset point → next reset is tomorrow
THEN (
date_trunc('day', NOW() AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC'))
+ (COALESCE((extra->>'quota_daily_reset_hour')::int, 0) || ' hours')::interval
+ '1 day'::interval
) AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC')
-- NOW() is before today's reset point → next reset is today
ELSE (
date_trunc('day', NOW() AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC'))
+ (COALESCE((extra->>'quota_daily_reset_hour')::int, 0) || ' hours')::interval
) AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC')
END
) AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
ELSE NULL END
)`
// nextWeeklyResetAtExpr is a SQL expression to compute the next weekly reset_at when a reset occurs.
// For fixed mode: computes the next future reset time based on NOW(), timezone, configured day and hour.
// This correctly handles long-inactive accounts by jumping directly to the next valid reset point.
const
nextWeeklyResetAtExpr
=
`(
CASE WHEN COALESCE(extra->>'quota_weekly_reset_mode', 'rolling') = 'fixed'
THEN to_char(
COALESCE((extra->>'quota_weekly_reset_at')::timestamptz, NOW()) + '7 days'::interval
AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
THEN to_char((
-- Compute this week's reset point in the configured timezone
-- Step 1: get today's date at reset hour in configured tz
-- Step 2: compute days forward to target weekday
-- Step 3: if same day but past reset hour, advance 7 days
CASE
WHEN (
-- days_forward = (target_day - current_day + 7) % 7
(COALESCE((extra->>'quota_weekly_reset_day')::int, 1)
- EXTRACT(DOW FROM NOW() AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC'))::int
+ 7) % 7
) = 0 AND NOW() >= (
date_trunc('day', NOW() AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC'))
+ (COALESCE((extra->>'quota_weekly_reset_hour')::int, 0) || ' hours')::interval
) AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC')
-- Same weekday and past reset hour → next week
THEN (
date_trunc('day', NOW() AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC'))
+ (COALESCE((extra->>'quota_weekly_reset_hour')::int, 0) || ' hours')::interval
+ '7 days'::interval
) AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC')
ELSE (
-- Advance to target weekday this week (or next if days_forward > 0)
date_trunc('day', NOW() AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC'))
+ (COALESCE((extra->>'quota_weekly_reset_hour')::int, 0) || ' hours')::interval
+ ((
(COALESCE((extra->>'quota_weekly_reset_day')::int, 1)
- EXTRACT(DOW FROM NOW() AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC'))::int
+ 7) % 7
) || ' days')::interval
) AT TIME ZONE COALESCE(extra->>'quota_reset_timezone', 'UTC')
END
) AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
ELSE NULL END
)`
...
...
backend/internal/service/account_quota_reset_test.go
0 → 100644
View file @
b5f78ec1
//go:build unit
package
service
import
(
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// ---------------------------------------------------------------------------
// nextFixedDailyReset
// ---------------------------------------------------------------------------
func
TestNextFixedDailyReset_BeforeResetHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-14 06:00 UTC, reset hour = 9
after
:=
time
.
Date
(
2026
,
3
,
14
,
6
,
0
,
0
,
0
,
tz
)
got
:=
nextFixedDailyReset
(
9
,
tz
,
after
)
want
:=
time
.
Date
(
2026
,
3
,
14
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedDailyReset_AtResetHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// Exactly at reset hour → should return tomorrow
after
:=
time
.
Date
(
2026
,
3
,
14
,
9
,
0
,
0
,
0
,
tz
)
got
:=
nextFixedDailyReset
(
9
,
tz
,
after
)
want
:=
time
.
Date
(
2026
,
3
,
15
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedDailyReset_AfterResetHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// After reset hour → should return tomorrow
after
:=
time
.
Date
(
2026
,
3
,
14
,
15
,
30
,
0
,
0
,
tz
)
got
:=
nextFixedDailyReset
(
9
,
tz
,
after
)
want
:=
time
.
Date
(
2026
,
3
,
15
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedDailyReset_MidnightReset
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// Reset at hour 0 (midnight), currently 23:59
after
:=
time
.
Date
(
2026
,
3
,
14
,
23
,
59
,
0
,
0
,
tz
)
got
:=
nextFixedDailyReset
(
0
,
tz
,
after
)
want
:=
time
.
Date
(
2026
,
3
,
15
,
0
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedDailyReset_NonUTCTimezone
(
t
*
testing
.
T
)
{
tz
,
err
:=
time
.
LoadLocation
(
"Asia/Shanghai"
)
require
.
NoError
(
t
,
err
)
// 2026-03-14 07:00 UTC = 2026-03-14 15:00 CST, reset hour = 9 (CST)
after
:=
time
.
Date
(
2026
,
3
,
14
,
7
,
0
,
0
,
0
,
time
.
UTC
)
got
:=
nextFixedDailyReset
(
9
,
tz
,
after
)
// Already past 9:00 CST today → tomorrow 9:00 CST = 2026-03-15 01:00 UTC
want
:=
time
.
Date
(
2026
,
3
,
15
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
// ---------------------------------------------------------------------------
// lastFixedDailyReset
// ---------------------------------------------------------------------------
func
TestLastFixedDailyReset_BeforeResetHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
now
:=
time
.
Date
(
2026
,
3
,
14
,
6
,
0
,
0
,
0
,
tz
)
got
:=
lastFixedDailyReset
(
9
,
tz
,
now
)
// Before today's 9:00 → yesterday 9:00
want
:=
time
.
Date
(
2026
,
3
,
13
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestLastFixedDailyReset_AtResetHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
now
:=
time
.
Date
(
2026
,
3
,
14
,
9
,
0
,
0
,
0
,
tz
)
got
:=
lastFixedDailyReset
(
9
,
tz
,
now
)
// At exactly 9:00 → today 9:00
want
:=
time
.
Date
(
2026
,
3
,
14
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestLastFixedDailyReset_AfterResetHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
now
:=
time
.
Date
(
2026
,
3
,
14
,
15
,
0
,
0
,
0
,
tz
)
got
:=
lastFixedDailyReset
(
9
,
tz
,
now
)
// After 9:00 → today 9:00
want
:=
time
.
Date
(
2026
,
3
,
14
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
// ---------------------------------------------------------------------------
// nextFixedWeeklyReset
// ---------------------------------------------------------------------------
func
TestNextFixedWeeklyReset_TargetDayAhead
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-14 is Saturday (day=6), target = Monday (day=1), hour = 9
after
:=
time
.
Date
(
2026
,
3
,
14
,
10
,
0
,
0
,
0
,
tz
)
got
:=
nextFixedWeeklyReset
(
1
,
9
,
tz
,
after
)
// Next Monday = 2026-03-16
want
:=
time
.
Date
(
2026
,
3
,
16
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedWeeklyReset_TargetDayToday_BeforeHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-16 is Monday (day=1), target = Monday, hour = 9, before 9:00
after
:=
time
.
Date
(
2026
,
3
,
16
,
6
,
0
,
0
,
0
,
tz
)
got
:=
nextFixedWeeklyReset
(
1
,
9
,
tz
,
after
)
// Today at 9:00
want
:=
time
.
Date
(
2026
,
3
,
16
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedWeeklyReset_TargetDayToday_AtHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-16 is Monday, target = Monday, hour = 9, exactly at 9:00
after
:=
time
.
Date
(
2026
,
3
,
16
,
9
,
0
,
0
,
0
,
tz
)
got
:=
nextFixedWeeklyReset
(
1
,
9
,
tz
,
after
)
// Next Monday at 9:00
want
:=
time
.
Date
(
2026
,
3
,
23
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedWeeklyReset_TargetDayToday_AfterHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-16 is Monday, target = Monday, hour = 9, after 9:00
after
:=
time
.
Date
(
2026
,
3
,
16
,
15
,
0
,
0
,
0
,
tz
)
got
:=
nextFixedWeeklyReset
(
1
,
9
,
tz
,
after
)
// Next Monday at 9:00
want
:=
time
.
Date
(
2026
,
3
,
23
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedWeeklyReset_TargetDayPast
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-18 is Wednesday (day=3), target = Monday (day=1)
after
:=
time
.
Date
(
2026
,
3
,
18
,
10
,
0
,
0
,
0
,
tz
)
got
:=
nextFixedWeeklyReset
(
1
,
9
,
tz
,
after
)
// Next Monday = 2026-03-23
want
:=
time
.
Date
(
2026
,
3
,
23
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestNextFixedWeeklyReset_Sunday
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-14 is Saturday (day=6), target = Sunday (day=0)
after
:=
time
.
Date
(
2026
,
3
,
14
,
10
,
0
,
0
,
0
,
tz
)
got
:=
nextFixedWeeklyReset
(
0
,
0
,
tz
,
after
)
// Next Sunday = 2026-03-15
want
:=
time
.
Date
(
2026
,
3
,
15
,
0
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
// ---------------------------------------------------------------------------
// lastFixedWeeklyReset
// ---------------------------------------------------------------------------
func
TestLastFixedWeeklyReset_SameDay_AfterHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-16 is Monday (day=1), target = Monday, hour = 9, now = 15:00
now
:=
time
.
Date
(
2026
,
3
,
16
,
15
,
0
,
0
,
0
,
tz
)
got
:=
lastFixedWeeklyReset
(
1
,
9
,
tz
,
now
)
// Today at 9:00
want
:=
time
.
Date
(
2026
,
3
,
16
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestLastFixedWeeklyReset_SameDay_BeforeHour
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-16 is Monday, target = Monday, hour = 9, now = 06:00
now
:=
time
.
Date
(
2026
,
3
,
16
,
6
,
0
,
0
,
0
,
tz
)
got
:=
lastFixedWeeklyReset
(
1
,
9
,
tz
,
now
)
// Last Monday at 9:00 = 2026-03-09
want
:=
time
.
Date
(
2026
,
3
,
9
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
func
TestLastFixedWeeklyReset_DifferentDay
(
t
*
testing
.
T
)
{
tz
:=
time
.
UTC
// 2026-03-18 is Wednesday (day=3), target = Monday (day=1)
now
:=
time
.
Date
(
2026
,
3
,
18
,
10
,
0
,
0
,
0
,
tz
)
got
:=
lastFixedWeeklyReset
(
1
,
9
,
tz
,
now
)
// Last Monday = 2026-03-16
want
:=
time
.
Date
(
2026
,
3
,
16
,
9
,
0
,
0
,
0
,
tz
)
assert
.
Equal
(
t
,
want
,
got
)
}
// ---------------------------------------------------------------------------
// isFixedDailyPeriodExpired
// ---------------------------------------------------------------------------
func
TestIsFixedDailyPeriodExpired_ZeroPeriodStart
(
t
*
testing
.
T
)
{
a
:=
&
Account
{
Extra
:
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"UTC"
,
}}
assert
.
True
(
t
,
a
.
isFixedDailyPeriodExpired
(
time
.
Time
{}))
}
func
TestIsFixedDailyPeriodExpired_NotExpired
(
t
*
testing
.
T
)
{
a
:=
&
Account
{
Extra
:
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"UTC"
,
}}
// Period started after the most recent reset → not expired
// (This test uses a time very close to "now", which is after the last reset)
periodStart
:=
time
.
Now
()
.
Add
(
-
1
*
time
.
Minute
)
assert
.
False
(
t
,
a
.
isFixedDailyPeriodExpired
(
periodStart
))
}
func
TestIsFixedDailyPeriodExpired_Expired
(
t
*
testing
.
T
)
{
a
:=
&
Account
{
Extra
:
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"UTC"
,
}}
// Period started 3 days ago → definitely expired
periodStart
:=
time
.
Now
()
.
Add
(
-
72
*
time
.
Hour
)
assert
.
True
(
t
,
a
.
isFixedDailyPeriodExpired
(
periodStart
))
}
func
TestIsFixedDailyPeriodExpired_InvalidTimezone
(
t
*
testing
.
T
)
{
a
:=
&
Account
{
Extra
:
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"Invalid/Timezone"
,
}}
// Invalid timezone falls back to UTC
periodStart
:=
time
.
Now
()
.
Add
(
-
72
*
time
.
Hour
)
assert
.
True
(
t
,
a
.
isFixedDailyPeriodExpired
(
periodStart
))
}
// ---------------------------------------------------------------------------
// isFixedWeeklyPeriodExpired
// ---------------------------------------------------------------------------
func
TestIsFixedWeeklyPeriodExpired_ZeroPeriodStart
(
t
*
testing
.
T
)
{
a
:=
&
Account
{
Extra
:
map
[
string
]
any
{
"quota_weekly_reset_mode"
:
"fixed"
,
"quota_weekly_reset_day"
:
float64
(
1
),
"quota_weekly_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"UTC"
,
}}
assert
.
True
(
t
,
a
.
isFixedWeeklyPeriodExpired
(
time
.
Time
{}))
}
func
TestIsFixedWeeklyPeriodExpired_NotExpired
(
t
*
testing
.
T
)
{
a
:=
&
Account
{
Extra
:
map
[
string
]
any
{
"quota_weekly_reset_mode"
:
"fixed"
,
"quota_weekly_reset_day"
:
float64
(
1
),
"quota_weekly_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"UTC"
,
}}
// Period started 1 minute ago → not expired
periodStart
:=
time
.
Now
()
.
Add
(
-
1
*
time
.
Minute
)
assert
.
False
(
t
,
a
.
isFixedWeeklyPeriodExpired
(
periodStart
))
}
func
TestIsFixedWeeklyPeriodExpired_Expired
(
t
*
testing
.
T
)
{
a
:=
&
Account
{
Extra
:
map
[
string
]
any
{
"quota_weekly_reset_mode"
:
"fixed"
,
"quota_weekly_reset_day"
:
float64
(
1
),
"quota_weekly_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"UTC"
,
}}
// Period started 10 days ago → definitely expired
periodStart
:=
time
.
Now
()
.
Add
(
-
240
*
time
.
Hour
)
assert
.
True
(
t
,
a
.
isFixedWeeklyPeriodExpired
(
periodStart
))
}
// ---------------------------------------------------------------------------
// ValidateQuotaResetConfig
// ---------------------------------------------------------------------------
func
TestValidateQuotaResetConfig_NilExtra
(
t
*
testing
.
T
)
{
assert
.
NoError
(
t
,
ValidateQuotaResetConfig
(
nil
))
}
func
TestValidateQuotaResetConfig_EmptyExtra
(
t
*
testing
.
T
)
{
assert
.
NoError
(
t
,
ValidateQuotaResetConfig
(
map
[
string
]
any
{}))
}
func
TestValidateQuotaResetConfig_ValidFixed
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
9
),
"quota_weekly_reset_mode"
:
"fixed"
,
"quota_weekly_reset_day"
:
float64
(
1
),
"quota_weekly_reset_hour"
:
float64
(
0
),
"quota_reset_timezone"
:
"Asia/Shanghai"
,
}
assert
.
NoError
(
t
,
ValidateQuotaResetConfig
(
extra
))
}
func
TestValidateQuotaResetConfig_ValidRolling
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"rolling"
,
"quota_weekly_reset_mode"
:
"rolling"
,
}
assert
.
NoError
(
t
,
ValidateQuotaResetConfig
(
extra
))
}
func
TestValidateQuotaResetConfig_InvalidTimezone
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_reset_timezone"
:
"Not/A/Timezone"
,
}
err
:=
ValidateQuotaResetConfig
(
extra
)
require
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"quota_reset_timezone"
)
}
func
TestValidateQuotaResetConfig_InvalidDailyMode
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"invalid"
,
}
err
:=
ValidateQuotaResetConfig
(
extra
)
require
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"quota_daily_reset_mode"
)
}
func
TestValidateQuotaResetConfig_InvalidDailyHour_TooHigh
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_hour"
:
float64
(
24
),
}
err
:=
ValidateQuotaResetConfig
(
extra
)
require
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"quota_daily_reset_hour"
)
}
func
TestValidateQuotaResetConfig_InvalidDailyHour_Negative
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_hour"
:
float64
(
-
1
),
}
err
:=
ValidateQuotaResetConfig
(
extra
)
require
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"quota_daily_reset_hour"
)
}
func
TestValidateQuotaResetConfig_InvalidWeeklyMode
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_weekly_reset_mode"
:
"unknown"
,
}
err
:=
ValidateQuotaResetConfig
(
extra
)
require
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"quota_weekly_reset_mode"
)
}
func
TestValidateQuotaResetConfig_InvalidWeeklyDay_TooHigh
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_weekly_reset_day"
:
float64
(
7
),
}
err
:=
ValidateQuotaResetConfig
(
extra
)
require
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"quota_weekly_reset_day"
)
}
func
TestValidateQuotaResetConfig_InvalidWeeklyDay_Negative
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_weekly_reset_day"
:
float64
(
-
1
),
}
err
:=
ValidateQuotaResetConfig
(
extra
)
require
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"quota_weekly_reset_day"
)
}
func
TestValidateQuotaResetConfig_InvalidWeeklyHour
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_weekly_reset_hour"
:
float64
(
25
),
}
err
:=
ValidateQuotaResetConfig
(
extra
)
require
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"quota_weekly_reset_hour"
)
}
func
TestValidateQuotaResetConfig_BoundaryValues
(
t
*
testing
.
T
)
{
// All boundary values should be valid
extra
:=
map
[
string
]
any
{
"quota_daily_reset_hour"
:
float64
(
23
),
"quota_weekly_reset_day"
:
float64
(
0
),
// Sunday
"quota_weekly_reset_hour"
:
float64
(
0
),
"quota_reset_timezone"
:
"UTC"
,
}
assert
.
NoError
(
t
,
ValidateQuotaResetConfig
(
extra
))
extra2
:=
map
[
string
]
any
{
"quota_daily_reset_hour"
:
float64
(
0
),
"quota_weekly_reset_day"
:
float64
(
6
),
// Saturday
"quota_weekly_reset_hour"
:
float64
(
23
),
}
assert
.
NoError
(
t
,
ValidateQuotaResetConfig
(
extra2
))
}
// ---------------------------------------------------------------------------
// ComputeQuotaResetAt
// ---------------------------------------------------------------------------
func
TestComputeQuotaResetAt_RollingMode_NoResetAt
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"rolling"
,
"quota_weekly_reset_mode"
:
"rolling"
,
}
ComputeQuotaResetAt
(
extra
)
_
,
hasDailyResetAt
:=
extra
[
"quota_daily_reset_at"
]
_
,
hasWeeklyResetAt
:=
extra
[
"quota_weekly_reset_at"
]
assert
.
False
(
t
,
hasDailyResetAt
,
"rolling mode should not set quota_daily_reset_at"
)
assert
.
False
(
t
,
hasWeeklyResetAt
,
"rolling mode should not set quota_weekly_reset_at"
)
}
func
TestComputeQuotaResetAt_RollingMode_ClearsExistingResetAt
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"rolling"
,
"quota_weekly_reset_mode"
:
"rolling"
,
"quota_daily_reset_at"
:
"2026-03-14T09:00:00Z"
,
"quota_weekly_reset_at"
:
"2026-03-16T09:00:00Z"
,
}
ComputeQuotaResetAt
(
extra
)
_
,
hasDailyResetAt
:=
extra
[
"quota_daily_reset_at"
]
_
,
hasWeeklyResetAt
:=
extra
[
"quota_weekly_reset_at"
]
assert
.
False
(
t
,
hasDailyResetAt
,
"rolling mode should remove quota_daily_reset_at"
)
assert
.
False
(
t
,
hasWeeklyResetAt
,
"rolling mode should remove quota_weekly_reset_at"
)
}
func
TestComputeQuotaResetAt_FixedDaily_SetsResetAt
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"UTC"
,
}
ComputeQuotaResetAt
(
extra
)
resetAtStr
,
ok
:=
extra
[
"quota_daily_reset_at"
]
.
(
string
)
require
.
True
(
t
,
ok
,
"quota_daily_reset_at should be set"
)
resetAt
,
err
:=
time
.
Parse
(
time
.
RFC3339
,
resetAtStr
)
require
.
NoError
(
t
,
err
)
// Reset time should be in the future
assert
.
True
(
t
,
resetAt
.
After
(
time
.
Now
()),
"reset_at should be in the future"
)
// Reset hour should be 9 UTC
assert
.
Equal
(
t
,
9
,
resetAt
.
UTC
()
.
Hour
())
}
func
TestComputeQuotaResetAt_FixedWeekly_SetsResetAt
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_weekly_reset_mode"
:
"fixed"
,
"quota_weekly_reset_day"
:
float64
(
1
),
// Monday
"quota_weekly_reset_hour"
:
float64
(
0
),
"quota_reset_timezone"
:
"UTC"
,
}
ComputeQuotaResetAt
(
extra
)
resetAtStr
,
ok
:=
extra
[
"quota_weekly_reset_at"
]
.
(
string
)
require
.
True
(
t
,
ok
,
"quota_weekly_reset_at should be set"
)
resetAt
,
err
:=
time
.
Parse
(
time
.
RFC3339
,
resetAtStr
)
require
.
NoError
(
t
,
err
)
// Reset time should be in the future
assert
.
True
(
t
,
resetAt
.
After
(
time
.
Now
()),
"reset_at should be in the future"
)
// Reset day should be Monday
assert
.
Equal
(
t
,
time
.
Monday
,
resetAt
.
UTC
()
.
Weekday
())
}
func
TestComputeQuotaResetAt_FixedDaily_WithTimezone
(
t
*
testing
.
T
)
{
tz
,
err
:=
time
.
LoadLocation
(
"Asia/Shanghai"
)
require
.
NoError
(
t
,
err
)
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
9
),
"quota_reset_timezone"
:
"Asia/Shanghai"
,
}
ComputeQuotaResetAt
(
extra
)
resetAtStr
,
ok
:=
extra
[
"quota_daily_reset_at"
]
.
(
string
)
require
.
True
(
t
,
ok
)
resetAt
,
err
:=
time
.
Parse
(
time
.
RFC3339
,
resetAtStr
)
require
.
NoError
(
t
,
err
)
// In Shanghai timezone, the hour should be 9
assert
.
Equal
(
t
,
9
,
resetAt
.
In
(
tz
)
.
Hour
())
}
func
TestComputeQuotaResetAt_DefaultTimezone
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
12
),
}
ComputeQuotaResetAt
(
extra
)
resetAtStr
,
ok
:=
extra
[
"quota_daily_reset_at"
]
.
(
string
)
require
.
True
(
t
,
ok
)
resetAt
,
err
:=
time
.
Parse
(
time
.
RFC3339
,
resetAtStr
)
require
.
NoError
(
t
,
err
)
// Default timezone is UTC
assert
.
Equal
(
t
,
12
,
resetAt
.
UTC
()
.
Hour
())
}
func
TestComputeQuotaResetAt_InvalidHour_ClampedToZero
(
t
*
testing
.
T
)
{
extra
:=
map
[
string
]
any
{
"quota_daily_reset_mode"
:
"fixed"
,
"quota_daily_reset_hour"
:
float64
(
99
),
"quota_reset_timezone"
:
"UTC"
,
}
ComputeQuotaResetAt
(
extra
)
resetAtStr
,
ok
:=
extra
[
"quota_daily_reset_at"
]
.
(
string
)
require
.
True
(
t
,
ok
)
resetAt
,
err
:=
time
.
Parse
(
time
.
RFC3339
,
resetAtStr
)
require
.
NoError
(
t
,
err
)
// Invalid hour → clamped to 0
assert
.
Equal
(
t
,
0
,
resetAt
.
UTC
()
.
Hour
())
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment