mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-20 00:18:55 +00:00
fix(proxies): skip inactive fallback targets
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
//go:build integration
|
||||
|
||||
package repository
|
||||
|
||||
import (
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *ProxyExpirySuite) TestSweep_SkipsInactiveBackup() {
|
||||
for _, chain := range []bool{false, true} {
|
||||
s.Run(map[bool]string{false: "unresolved", true: "next active backup"}[chain], func() {
|
||||
now := time.Now()
|
||||
past := now.Add(-time.Hour)
|
||||
future := now.Add(time.Hour)
|
||||
healthy := s.mkProxy("active-tail", service.FallbackModeNone, &future, nil)
|
||||
backup := s.mkProxy("disabled-backup", service.FallbackModeNone, &future, nil)
|
||||
disabled, err := s.repo.GetByID(s.ctx, backup)
|
||||
s.Require().NoError(err)
|
||||
disabled.Status = "inactive"
|
||||
if chain {
|
||||
disabled.FallbackMode = service.FallbackModeProxy
|
||||
disabled.BackupProxyID = &healthy
|
||||
}
|
||||
s.Require().NoError(s.repo.Update(s.ctx, disabled))
|
||||
source := s.mkProxy("expired-source", service.FallbackModeProxy, &past, &backup)
|
||||
account := s.mkAccountWithProxy(source)
|
||||
_, err = s.repo.SweepExpiredProxies(s.ctx, now)
|
||||
s.Require().NoError(err)
|
||||
if chain {
|
||||
s.Equal(&healthy, s.accountProxyID(account))
|
||||
} else {
|
||||
s.Equal(&source, s.accountProxyID(account))
|
||||
}
|
||||
got, err := s.repo.GetByID(s.ctx, backup)
|
||||
s.Require().NoError(err)
|
||||
s.Equal("inactive", got.Status, "fallback traversal must not reactivate disabled proxies")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,8 @@ func ResolveProxyFallbackTarget(start Proxy, byID map[int64]Proxy, now time.Time
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
if !(&p).IsExpired(now) && p.Status != StatusExpired {
|
||||
// Disabled nodes may define a fallback, but cannot be selected as targets.
|
||||
if p.IsActive() && !p.IsExpired(now) {
|
||||
id := p.ID
|
||||
return &id, true
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func mkProxy(id int64, mode string, backup *int64, expiresInDays *int, now time.Time) Proxy {
|
||||
p := Proxy{ID: id, FallbackMode: mode, BackupProxyID: backup}
|
||||
p := Proxy{ID: id, Status: StatusActive, FallbackMode: mode, BackupProxyID: backup}
|
||||
if expiresInDays != nil {
|
||||
t := now.AddDate(0, 0, *expiresInDays)
|
||||
p.ExpiresAt = &t
|
||||
@@ -71,3 +71,35 @@ func TestResolveFallbackTarget(t *testing.T) {
|
||||
require.Nil(t, target)
|
||||
})
|
||||
}
|
||||
|
||||
func TestResolveFallbackSkipsInactiveBackup(t *testing.T) {
|
||||
now := time.Now()
|
||||
for _, mode := range []string{FallbackModeNone, FallbackModeProxy, FallbackModeDirect} {
|
||||
t.Run(mode, func(t *testing.T) {
|
||||
source := mkProxy(1, FallbackModeProxy, i64(2), di(-1), now)
|
||||
disabled := mkProxy(2, mode, i64(3), di(30), now)
|
||||
disabled.Status = "inactive"
|
||||
healthy := mkProxy(3, FallbackModeNone, nil, di(30), now)
|
||||
target, change := ResolveProxyFallbackTarget(source, map[int64]Proxy{1: source, 2: disabled, 3: healthy}, now)
|
||||
switch mode {
|
||||
case FallbackModeNone:
|
||||
require.False(t, change)
|
||||
require.Nil(t, target)
|
||||
case FallbackModeProxy:
|
||||
require.True(t, change)
|
||||
require.Equal(t, i64(3), target)
|
||||
case FallbackModeDirect:
|
||||
require.True(t, change)
|
||||
require.Nil(t, target)
|
||||
}
|
||||
})
|
||||
}
|
||||
t.Run("inactive cycle", func(t *testing.T) {
|
||||
source := mkProxy(1, FallbackModeProxy, i64(2), di(-1), now)
|
||||
disabled := mkProxy(2, FallbackModeProxy, i64(1), nil, now)
|
||||
disabled.Status = "inactive"
|
||||
target, change := ResolveProxyFallbackTarget(source, map[int64]Proxy{1: source, 2: disabled}, now)
|
||||
require.False(t, change)
|
||||
require.Nil(t, target)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user