mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-16 10:28:49 -07:00
44d30c83bf
This slightly changes the interface used for committing configuration changes. The two parts are now: - VerifyConfiguration, which runs synchronously and locked, and can abort the config change. These callbacks shouldn't *do* anything apart from looking at the config changes and saying yes or no. No change from previously. - CommitConfiguration, which runs asynchronously (one goroutine per call) *after* replacing the config and releasing any locks. Returning false from these methods sets the "requires restart" flag, which now lives in the config.Wrapper. This should be deadlock free as the CommitConfiguration calls can take as long as they like and can wait for locks to be released when they need to tweak things. I think this should be safe compared to before as the CommitConfiguration calls were always made from a random background goroutine (typically one from the HTTP server), so it was always concurrent with everything else anyway. Hence the CommitResponse type is gone, instead you get an error back on verification failure only, and need to explicitly check w.RequiresRestart() afterwards if you care. As an added bonus this fixes a bug where we would reset the "requires restart" indicator if a config that did not require restart was saved, even if we already were in the requires-restart state. GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3386
99 lines
2.3 KiB
Go
99 lines
2.3 KiB
Go
// Copyright (C) 2015 The Syncthing Authors.
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package config
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
type requiresRestart struct {
|
|
committed chan struct{}
|
|
}
|
|
|
|
func (requiresRestart) VerifyConfiguration(_, _ Configuration) error {
|
|
return nil
|
|
}
|
|
func (c requiresRestart) CommitConfiguration(_, _ Configuration) bool {
|
|
select {
|
|
case c.committed <- struct{}{}:
|
|
default:
|
|
}
|
|
return false
|
|
}
|
|
func (requiresRestart) String() string {
|
|
return "requiresRestart"
|
|
}
|
|
|
|
type validationError struct{}
|
|
|
|
func (validationError) VerifyConfiguration(_, _ Configuration) error {
|
|
return errors.New("some error")
|
|
}
|
|
func (c validationError) CommitConfiguration(_, _ Configuration) bool {
|
|
return true
|
|
}
|
|
func (validationError) String() string {
|
|
return "validationError"
|
|
}
|
|
|
|
func TestReplaceCommit(t *testing.T) {
|
|
w := Wrap("/dev/null", Configuration{Version: 0})
|
|
if w.Raw().Version != 0 {
|
|
t.Fatal("Config incorrect")
|
|
}
|
|
|
|
// Replace config. We should get back a clean response and the config
|
|
// should change.
|
|
|
|
err := w.Replace(Configuration{Version: 1})
|
|
if err != nil {
|
|
t.Fatal("Should not have a validation error:", err)
|
|
}
|
|
if w.RequiresRestart() {
|
|
t.Fatal("Should not require restart")
|
|
}
|
|
if w.Raw().Version != 1 {
|
|
t.Fatal("Config should have changed")
|
|
}
|
|
|
|
// Now with a subscriber requiring restart. We should get a clean response
|
|
// but with the restart flag set, and the config should change.
|
|
|
|
sub0 := requiresRestart{committed: make(chan struct{}, 1)}
|
|
w.Subscribe(sub0)
|
|
|
|
err = w.Replace(Configuration{Version: 2})
|
|
if err != nil {
|
|
t.Fatal("Should not have a validation error:", err)
|
|
}
|
|
|
|
<-sub0.committed
|
|
if !w.RequiresRestart() {
|
|
t.Fatal("Should require restart")
|
|
}
|
|
if w.Raw().Version != 2 {
|
|
t.Fatal("Config should have changed")
|
|
}
|
|
|
|
// Now with a subscriber that throws a validation error. The config should
|
|
// not change.
|
|
|
|
w.Subscribe(validationError{})
|
|
|
|
err = w.Replace(Configuration{Version: 3})
|
|
if err == nil {
|
|
t.Fatal("Should have a validation error")
|
|
}
|
|
if !w.RequiresRestart() {
|
|
t.Fatal("Should still require restart")
|
|
}
|
|
if w.Raw().Version != 2 {
|
|
t.Fatal("Config should not have changed")
|
|
}
|
|
}
|