1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
package cli
import (
"strings"
"testing"
"time"
"codeberg.org/snonux/gitsyncer/internal/state"
)
func TestEvaluateSyncPolicy_SkipsRepoSyncedWithinDay(t *testing.T) {
st := &state.State{}
st.SetLastRepoSync("repo", time.Now().Add(-23*time.Hour))
decision := evaluateSyncPolicy("repo", st, false, false, false)
if !decision.Skip {
t.Fatal("expected repo synced within 24 hours to be skipped")
}
if !strings.Contains(decision.Message, "Use --force to override.") {
t.Fatalf("expected force override hint, got %q", decision.Message)
}
}
func TestEvaluateSyncPolicy_AllowsRepoAfterDailyWindow(t *testing.T) {
st := &state.State{}
st.SetLastRepoSync("repo", time.Now().Add(-25*time.Hour))
decision := evaluateSyncPolicy("repo", st, false, false, false)
if decision.Skip {
t.Fatalf("expected repo synced more than 24 hours ago to proceed, got %q", decision.Message)
}
}
func TestEvaluateSyncPolicy_ForceBypassesDailyAndThrottleLimits(t *testing.T) {
t.Setenv("HOME", t.TempDir())
st := &state.State{}
now := time.Now()
st.SetRepoSync("repo", now.Add(-1*time.Hour), now.Add(30*24*time.Hour))
decision := evaluateSyncPolicy("repo", st, false, true, true)
if decision.Skip {
t.Fatalf("expected --force to bypass sync limits, got %q", decision.Message)
}
if decision.SetNextAllowed {
t.Fatal("did not expect --force to request throttle-window persistence")
}
}
func TestEvaluateSyncPolicy_ThrottleSetsWindowWhenRepoIsIdle(t *testing.T) {
t.Setenv("HOME", t.TempDir())
start := time.Now()
decision := evaluateSyncPolicy("repo", &state.State{}, false, false, true)
end := time.Now()
if !decision.Skip {
t.Fatal("expected idle repo to be skipped when throttle is enabled")
}
if !decision.SetNextAllowed {
t.Fatal("expected throttle evaluation to request a persisted next-allowed time")
}
minAllowed := start.Add(throttleMinDays * 24 * time.Hour)
maxAllowed := end.Add(throttleMaxDays*24*time.Hour + time.Minute)
if decision.NextAllowed.Before(minAllowed) || decision.NextAllowed.After(maxAllowed) {
t.Fatalf("expected throttle window between %s and %s, got %s", minAllowed, maxAllowed, decision.NextAllowed)
}
}
func TestRecordRepoSync_ClearsThrottleWindowWhenThrottleDisabled(t *testing.T) {
st := &state.State{}
st.SetRepoSync("repo", time.Now().Add(-72*time.Hour), time.Now().Add(72*time.Hour))
recordRepoSync("repo", st, false)
if st.GetLastRepoSync("repo").IsZero() {
t.Fatal("expected last sync time to be recorded")
}
if !st.GetNextRepoSyncAllowed("repo").IsZero() {
t.Fatal("expected throttle window to be cleared when throttle is disabled")
}
}
func TestRecordRepoSync_SetsThrottleWindowWhenThrottleEnabled(t *testing.T) {
st := &state.State{}
recordRepoSync("repo", st, true)
lastSync := st.GetLastRepoSync("repo")
if lastSync.IsZero() {
t.Fatal("expected last sync time to be recorded")
}
nextAllowed := st.GetNextRepoSyncAllowed("repo")
if nextAllowed.IsZero() {
t.Fatal("expected throttle window to be recorded")
}
minAllowed := lastSync.Add(throttleMinDays * 24 * time.Hour)
maxAllowed := lastSync.Add(throttleMaxDays*24*time.Hour + time.Minute)
if nextAllowed.Before(minAllowed) || nextAllowed.After(maxAllowed) {
t.Fatalf("expected throttle window between %s and %s, got %s", minAllowed, maxAllowed, nextAllowed)
}
}
|