fs: make BwTimetable.Set replace the timetable instead of appending to it

Set built the timetable with *x = append(*x, ts), so setting a bandwidth
timetable on a value that already held one kept both schedules. The single-value
branch of the same function has always done *x = BwTimetable{ts}, and the other
multi-token Set methods in this package build into a local and assign at the end.

The visible effect is through the rc API. The "main" options block registered in
fs.RegisterGlobalOptions is the live globalConfig, and options/set reshapes JSON
straight into it, so

  rclone rc options/set --json '{"main": {"BwLimit": "Mon-10:00,1Mi"}}'

added to the running daemon's timetable rather than replacing it, and the older
slot kept winning: LimitAt for a Sunday returned the previous 10Mi. The same
applies to a _config override on a single call, since AddConfig shallow-copies
the global.

Building into a local also stops a failed parse from leaving the previous
timetable partly overwritten, which the existing error cases already expect.
This commit is contained in:
youdie006
2026-09-09 10:28:44 +01:00
committed by Nick Craig-Wood
parent e45210765c
commit 5bbc5d5545
2 changed files with 51 additions and 2 deletions
+5 -2
View File
@@ -150,6 +150,8 @@ func (x *BwTimetable) Set(s string) error {
return nil
}
var newTimetable BwTimetable
// Split the timetable string by both spaces and semicolons
for tok := range strings.FieldsFuncSeq(s, func(r rune) bool {
return r == ' ' || r == ';'
@@ -178,7 +180,7 @@ func (x *BwTimetable) Set(s string) error {
if err := ts.Bandwidth.Set(tv[1]); err != nil {
return err
}
*x = append(*x, ts)
newTimetable = append(newTimetable, ts)
}
} else {
timespec := strings.Split(tv[0], "-")
@@ -205,9 +207,10 @@ func (x *BwTimetable) Set(s string) error {
if err := ts.Bandwidth.Set(tv[1]); err != nil {
return err
}
*x = append(*x, ts)
newTimetable = append(newTimetable, ts)
}
}
*x = newTimetable
return nil
}
+46
View File
@@ -316,6 +316,52 @@ func TestBwTimetableSet(t *testing.T) {
}
}
func TestBwTimetableSetReplaces(t *testing.T) {
for _, test := range []struct {
first string
second string
want string
}{
{"Sun-00:00,10M", "Mon-10:00,1M", "Mon-10:00,1Mi"},
{"Mon-10:00,1M", "Mon-10:00,1M", "Mon-10:00,1Mi"},
{"Mon-10:00,1M", "2M", "2Mi"},
{"2M", "Mon-10:00,1M", "Mon-10:00,1Mi"},
{"11:00,333;13:40,666", "Mon-10:00,1M", "Mon-10:00,1Mi"},
} {
tt := BwTimetable{}
require.NoError(t, tt.Set(test.first), test.first)
require.NoError(t, tt.Set(test.second), test.second)
assert.Equal(t, test.want, tt.String(), "%q then %q", test.first, test.second)
var want BwTimetable
require.NoError(t, want.Set(test.second))
assert.Equal(t, want, tt, "%q then %q", test.first, test.second)
}
}
func TestBwTimetableSetErrorKeepsPrevious(t *testing.T) {
for _, in := range []string{
"Mon-11:00,333 bad",
"Mon-11:00,333 Tue-13:40,bad",
"Mon-11:00,333 24:01,666",
"11:00,333;bad",
} {
tt := BwTimetable{}
require.NoError(t, tt.Set("Sun-20:00,10M"))
require.Error(t, tt.Set(in), in)
assert.Equal(t, "Sun-20:00,10Mi", tt.String(), in)
}
}
func TestBwTimetableUnmarshalJSONReplaces(t *testing.T) {
var tt BwTimetable
require.NoError(t, json.Unmarshal([]byte(`"Sun-00:00,10M"`), &tt))
require.NoError(t, json.Unmarshal([]byte(`"Mon-10:00,1M"`), &tt))
assert.Equal(t, BwTimetable{
BwTimeSlot{DayOfTheWeek: 1, HHMM: 1000, Bandwidth: BwPair{Tx: 1024 * 1024, Rx: 1024 * 1024}},
}, tt)
}
func TestBwTimetableLimitAt(t *testing.T) {
for _, test := range []struct {
tt BwTimetable