Преглед изворни кода

lib: Use counterfeiter to mock interfaces in tests (#7375)

Simon Frei пре 4 година
родитељ
комит
3d91f7c975
46 измењених фајлова са 8947 додато и 887 уклоњено
  1. 20 1
      build.go
  2. 4 1
      go.mod
  3. 9 5
      go.sum
  4. 60 51
      lib/api/api_test.go
  5. 7 128
      lib/api/mocked_config_test.go
  6. 0 33
      lib/api/mocked_connections_test.go
  7. 0 46
      lib/api/mocked_discovery_test.go
  8. 0 21
      lib/api/mocked_events_test.go
  9. 0 26
      lib/api/mocked_logger_test.go
  10. 0 199
      lib/api/mocked_model_test.go
  11. 1745 0
      lib/config/mocks/mocked_wrapper.go
  12. 2 0
      lib/config/wrapper.go
  13. 437 0
      lib/connections/mocks/service.go
  14. 2 0
      lib/connections/service.go
  15. 0 3
      lib/discover/local.go
  16. 30 24
      lib/discover/local.pb.go
  17. 0 18
      lib/discover/local.proto
  18. 2 0
      lib/discover/manager.go
  19. 454 0
      lib/discover/mocks/manager.go
  20. 2 0
      lib/events/events.go
  21. 186 0
      lib/events/mocks/buffered_subscription.go
  22. 2 0
      lib/logger/logger.go
  23. 142 0
      lib/logger/mocks/logger.go
  24. 24 84
      lib/model/fakeconns_test.go
  25. 2 0
      lib/model/folder_summary.go
  26. 221 0
      lib/model/mocks/folderSummaryService.go
  27. 3238 0
      lib/model/mocks/model.go
  28. 2 0
      lib/model/model.go
  29. 19 26
      lib/model/model_test.go
  30. 1 1
      lib/model/progressemitter_test.go
  31. 87 114
      lib/model/requests_test.go
  32. 2 2
      lib/protocol/benchmark_test.go
  33. 0 3
      lib/protocol/deviceid_test.go
  34. 24 20
      lib/protocol/deviceid_test.pb.go
  35. 0 23
      lib/protocol/deviceid_test.proto
  36. 490 0
      lib/protocol/mocked_connection_info_test.go
  37. 1112 0
      lib/protocol/mocks/connection.go
  38. 494 0
      lib/protocol/mocks/connection_info.go
  39. 7 0
      lib/protocol/protocol.go
  40. 11 11
      lib/protocol/protocol_test.go
  41. 0 46
      lib/testutils/testutils.go
  42. 1 0
      meta/copyright_test.go
  43. 1 1
      proto/generate.go
  44. 13 0
      proto/lib/discover/local.proto
  45. 15 0
      proto/lib/protocol/deviceid_test.proto
  46. 79 0
      script/prune_mocks.go

+ 20 - 1
build.go

@@ -316,6 +316,9 @@ func runCommand(cmd string, target target) {
 	case "proto":
 		proto()
 
+	case "testmocks":
+		testmocks()
+
 	case "translate":
 		translate()
 
@@ -862,10 +865,26 @@ func proto() {
 		}
 		runPrintInDir(path, "git", "checkout", dep.commit)
 	}
-	runPrint(goCmd, "generate", "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/stdiscosrv")
+	runPrint(goCmd, "generate", "github.com/syncthing/syncthing/cmd/stdiscosrv")
 	runPrint(goCmd, "generate", "proto/generate.go")
 }
 
+func testmocks() {
+	runPrint(goCmd, "get", "golang.org/x/tools/cmd/goimports")
+	runPrint(goCmd, "get", "github.com/maxbrunsfeld/counterfeiter/v6")
+	args := []string{
+		"generate",
+		"github.com/syncthing/syncthing/lib/config",
+		"github.com/syncthing/syncthing/lib/connections",
+		"github.com/syncthing/syncthing/lib/discover",
+		"github.com/syncthing/syncthing/lib/events",
+		"github.com/syncthing/syncthing/lib/logger",
+		"github.com/syncthing/syncthing/lib/model",
+		"github.com/syncthing/syncthing/lib/protocol",
+	}
+	runPrint(goCmd, args...)
+}
+
 func translate() {
 	os.Chdir("gui/default/assets/lang")
 	runPipe("lang-en-new.json", goCmd, "run", "../../../../script/translate.go", "lang-en.json", "../../../")

+ 4 - 1
go.mod

@@ -30,6 +30,8 @@ require (
 	github.com/mattn/go-isatty v0.0.12
 	github.com/minio/sha256-simd v0.1.1
 	github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75
+	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
+	github.com/onsi/gomega v1.10.3 // indirect
 	github.com/oschwald/geoip2-golang v1.4.0
 	github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
 	github.com/pkg/errors v0.9.1
@@ -44,9 +46,10 @@ require (
 	github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
 	golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
 	golang.org/x/net v0.0.0-20201031054903-ff519b6c9102
-	golang.org/x/sys v0.0.0-20201101102859-da207088b7d1
+	golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
 	golang.org/x/text v0.3.4
 	golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
+	gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
 )
 
 go 1.14

+ 9 - 5
go.sum

@@ -231,7 +231,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -291,6 +290,8 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
 github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
@@ -303,8 +304,9 @@ github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
 github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
 github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
+github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
 github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@@ -504,6 +506,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
 golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -550,8 +553,8 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck=
-golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -623,8 +626,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=

+ 60 - 51
lib/api/api_test.go

@@ -28,9 +28,15 @@ import (
 	"github.com/d4l3k/messagediff"
 	"github.com/syncthing/syncthing/lib/assets"
 	"github.com/syncthing/syncthing/lib/config"
+	connmocks "github.com/syncthing/syncthing/lib/connections/mocks"
+	discovermocks "github.com/syncthing/syncthing/lib/discover/mocks"
 	"github.com/syncthing/syncthing/lib/events"
+	eventmocks "github.com/syncthing/syncthing/lib/events/mocks"
 	"github.com/syncthing/syncthing/lib/fs"
 	"github.com/syncthing/syncthing/lib/locations"
+	"github.com/syncthing/syncthing/lib/logger"
+	loggermocks "github.com/syncthing/syncthing/lib/logger/mocks"
+	modelmocks "github.com/syncthing/syncthing/lib/model/mocks"
 	"github.com/syncthing/syncthing/lib/protocol"
 	"github.com/syncthing/syncthing/lib/svcutil"
 	"github.com/syncthing/syncthing/lib/sync"
@@ -40,13 +46,16 @@ import (
 )
 
 var (
-	confDir = filepath.Join("testdata", "config")
-	token   = filepath.Join(confDir, "csrftokens.txt")
-	dev1    protocol.DeviceID
+	confDir    = filepath.Join("testdata", "config")
+	token      = filepath.Join(confDir, "csrftokens.txt")
+	dev1       protocol.DeviceID
+	apiCfg     = newMockedConfig()
+	testAPIKey = "foobarbaz"
 )
 
 func init() {
 	dev1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
+	apiCfg.GUIReturns(config.GUIConfiguration{APIKey: testAPIKey})
 }
 
 func TestMain(m *testing.M) {
@@ -246,10 +255,7 @@ type httpTestCase struct {
 func TestAPIServiceRequests(t *testing.T) {
 	t.Parallel()
 
-	const testAPIKey = "foobarbaz"
-	cfg := new(mockedConfig)
-	cfg.gui.APIKey = testAPIKey
-	baseURL, cancel, err := startHTTP(cfg)
+	baseURL, cancel, err := startHTTP(apiCfg)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -515,9 +521,11 @@ func testHTTPRequest(t *testing.T, baseURL string, tc httpTestCase, apikey strin
 func TestHTTPLogin(t *testing.T) {
 	t.Parallel()
 
-	cfg := new(mockedConfig)
-	cfg.gui.User = "üser"
-	cfg.gui.Password = "$2a$10$IdIZTxTg/dCNuNEGlmLynOjqg4B1FvDKuIV5e0BB3pnWVHNb8.GSq" // bcrypt of "räksmörgås" in UTF-8
+	cfg := newMockedConfig()
+	cfg.GUIReturns(config.GUIConfiguration{
+		User:     "üser",
+		Password: "$2a$10$IdIZTxTg/dCNuNEGlmLynOjqg4B1FvDKuIV5e0BB3pnWVHNb8.GSq", // bcrypt of "räksmörgås" in UTF-8
+	})
 	baseURL, cancel, err := startHTTP(cfg)
 	if err != nil {
 		t.Fatal(err)
@@ -581,19 +589,29 @@ func TestHTTPLogin(t *testing.T) {
 }
 
 func startHTTP(cfg config.Wrapper) (string, context.CancelFunc, error) {
-	m := new(mockedModel)
+	m := new(modelmocks.Model)
 	assetDir := "../../gui"
-	eventSub := new(mockedEventSub)
-	diskEventSub := new(mockedEventSub)
-	discoverer := new(mockedCachingMux)
-	connections := new(mockedConnections)
-	errorLog := new(mockedLoggerRecorder)
-	systemLog := new(mockedLoggerRecorder)
+	eventSub := new(eventmocks.BufferedSubscription)
+	diskEventSub := new(eventmocks.BufferedSubscription)
+	discoverer := new(discovermocks.Manager)
+	connections := new(connmocks.Service)
+	errorLog := new(loggermocks.Recorder)
+	systemLog := new(loggermocks.Recorder)
+	for _, l := range []*loggermocks.Recorder{errorLog, systemLog} {
+		l.SinceReturns([]logger.Line{
+			{
+				When:    time.Now(),
+				Message: "Test message",
+			},
+		})
+	}
 	addrChan := make(chan string)
+	mockedSummary := &modelmocks.FolderSummaryService{}
+	mockedSummary.SummaryReturns(map[string]interface{}{"mocked": true}, nil)
 
 	// Instantiate the API service
 	urService := ur.New(cfg, m, connections, false)
-	svc := New(protocol.LocalDeviceID, cfg, assetDir, "syncthing", m, eventSub, diskEventSub, events.NoopLogger, discoverer, connections, urService, &mockedFolderSummaryService{}, errorLog, systemLog, false).(*service)
+	svc := New(protocol.LocalDeviceID, cfg, assetDir, "syncthing", m, eventSub, diskEventSub, events.NoopLogger, discoverer, connections, urService, mockedSummary, errorLog, systemLog, false).(*service)
 	defer os.Remove(token)
 	svc.started = addrChan
 
@@ -625,10 +643,7 @@ func startHTTP(cfg config.Wrapper) (string, context.CancelFunc, error) {
 func TestCSRFRequired(t *testing.T) {
 	t.Parallel()
 
-	const testAPIKey = "foobarbaz"
-	cfg := new(mockedConfig)
-	cfg.gui.APIKey = testAPIKey
-	baseURL, cancel, err := startHTTP(cfg)
+	baseURL, cancel, err := startHTTP(apiCfg)
 	if err != nil {
 		t.Fatal("Unexpected error from getting base URL:", err)
 	}
@@ -701,10 +716,7 @@ func TestCSRFRequired(t *testing.T) {
 func TestRandomString(t *testing.T) {
 	t.Parallel()
 
-	const testAPIKey = "foobarbaz"
-	cfg := new(mockedConfig)
-	cfg.gui.APIKey = testAPIKey
-	baseURL, cancel, err := startHTTP(cfg)
+	baseURL, cancel, err := startHTTP(apiCfg)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -794,10 +806,7 @@ func TestConfigPostDupFolder(t *testing.T) {
 }
 
 func testConfigPost(data io.Reader) (*http.Response, error) {
-	const testAPIKey = "foobarbaz"
-	cfg := new(mockedConfig)
-	cfg.gui.APIKey = testAPIKey
-	baseURL, cancel, err := startHTTP(cfg)
+	baseURL, cancel, err := startHTTP(apiCfg)
 	if err != nil {
 		return nil, err
 	}
@@ -816,8 +825,8 @@ func TestHostCheck(t *testing.T) {
 
 	// An API service bound to localhost should reject non-localhost host Headers
 
-	cfg := new(mockedConfig)
-	cfg.gui.RawAddress = "127.0.0.1:0"
+	cfg := newMockedConfig()
+	cfg.GUIReturns(config.GUIConfiguration{RawAddress: "127.0.0.1:0"})
 	baseURL, cancel, err := startHTTP(cfg)
 	if err != nil {
 		t.Fatal(err)
@@ -876,9 +885,11 @@ func TestHostCheck(t *testing.T) {
 
 	// A server with InsecureSkipHostCheck set behaves differently
 
-	cfg = new(mockedConfig)
-	cfg.gui.RawAddress = "127.0.0.1:0"
-	cfg.gui.InsecureSkipHostCheck = true
+	cfg = newMockedConfig()
+	cfg.GUIReturns(config.GUIConfiguration{
+		RawAddress:            "127.0.0.1:0",
+		InsecureSkipHostCheck: true,
+	})
 	baseURL, cancel, err = startHTTP(cfg)
 	if err != nil {
 		t.Fatal(err)
@@ -900,9 +911,11 @@ func TestHostCheck(t *testing.T) {
 
 	// A server bound to a wildcard address also doesn't do the check
 
-	cfg = new(mockedConfig)
-	cfg.gui.RawAddress = "0.0.0.0:0"
-	cfg.gui.InsecureSkipHostCheck = true
+	cfg = newMockedConfig()
+	cfg.GUIReturns(config.GUIConfiguration{
+		RawAddress:            "0.0.0.0:0",
+		InsecureSkipHostCheck: true,
+	})
 	baseURL, cancel, err = startHTTP(cfg)
 	if err != nil {
 		t.Fatal(err)
@@ -929,8 +942,10 @@ func TestHostCheck(t *testing.T) {
 		return
 	}
 
-	cfg = new(mockedConfig)
-	cfg.gui.RawAddress = "[::1]:0"
+	cfg = newMockedConfig()
+	cfg.GUIReturns(config.GUIConfiguration{
+		RawAddress: "[::1]:0",
+	})
 	baseURL, cancel, err = startHTTP(cfg)
 	if err != nil {
 		t.Fatal(err)
@@ -1023,10 +1038,7 @@ func TestAddressIsLocalhost(t *testing.T) {
 func TestAccessControlAllowOriginHeader(t *testing.T) {
 	t.Parallel()
 
-	const testAPIKey = "foobarbaz"
-	cfg := new(mockedConfig)
-	cfg.gui.APIKey = testAPIKey
-	baseURL, cancel, err := startHTTP(cfg)
+	baseURL, cancel, err := startHTTP(apiCfg)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1054,10 +1066,7 @@ func TestAccessControlAllowOriginHeader(t *testing.T) {
 func TestOptionsRequest(t *testing.T) {
 	t.Parallel()
 
-	const testAPIKey = "foobarbaz"
-	cfg := new(mockedConfig)
-	cfg.gui.APIKey = testAPIKey
-	baseURL, cancel, err := startHTTP(cfg)
+	baseURL, cancel, err := startHTTP(apiCfg)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1090,9 +1099,9 @@ func TestOptionsRequest(t *testing.T) {
 func TestEventMasks(t *testing.T) {
 	t.Parallel()
 
-	cfg := new(mockedConfig)
-	defSub := new(mockedEventSub)
-	diskSub := new(mockedEventSub)
+	cfg := newMockedConfig()
+	defSub := new(eventmocks.BufferedSubscription)
+	diskSub := new(eventmocks.BufferedSubscription)
 	svc := New(protocol.LocalDeviceID, cfg, "", "syncthing", nil, defSub, diskSub, events.NoopLogger, nil, nil, nil, nil, nil, nil, false).(*service)
 	defer os.Remove(token)
 

+ 7 - 128
lib/api/mocked_config_test.go

@@ -7,136 +7,15 @@
 package api
 
 import (
-	"github.com/syncthing/syncthing/lib/config"
-	"github.com/syncthing/syncthing/lib/protocol"
-	"github.com/syncthing/syncthing/lib/util"
+	"github.com/syncthing/syncthing/lib/config/mocks"
 )
 
-type mockedConfig struct {
-	gui config.GUIConfiguration
-}
-
-func (c *mockedConfig) GUI() config.GUIConfiguration {
-	return c.gui
-}
-
-func (c *mockedConfig) ListenAddresses() []string {
-	return nil
-}
-
-func (c *mockedConfig) LDAP() config.LDAPConfiguration {
-	return config.LDAPConfiguration{}
-}
-
-func (c *mockedConfig) RawCopy() config.Configuration {
-	cfg := config.Configuration{}
-	util.SetDefaults(&cfg.Options)
-	return cfg
-}
-
-func (c *mockedConfig) Options() config.OptionsConfiguration {
-	return config.OptionsConfiguration{}
-}
-
-func (c *mockedConfig) Modify(config.ModifyFunction) (config.Waiter, error) {
-	return noopWaiter{}, nil
-}
-
-func (c *mockedConfig) Subscribe(cm config.Committer) config.Configuration {
-	return config.Configuration{}
-}
-
-func (c *mockedConfig) Unsubscribe(cm config.Committer) {}
-
-func (c *mockedConfig) Folders() map[string]config.FolderConfiguration {
-	return nil
-}
-
-func (c *mockedConfig) Devices() map[protocol.DeviceID]config.DeviceConfiguration {
-	return nil
-}
-
-func (c *mockedConfig) DeviceList() []config.DeviceConfiguration {
-	return nil
-}
-
-func (c *mockedConfig) Save() error {
-	return nil
-}
-
-func (c *mockedConfig) RequiresRestart() bool {
-	return false
-}
-
-func (c *mockedConfig) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) {}
-
-func (c *mockedConfig) AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID) {}
-
-func (c *mockedConfig) ConfigPath() string {
-	return ""
-}
-
-func (c *mockedConfig) Folder(id string) (config.FolderConfiguration, bool) {
-	return config.FolderConfiguration{}, false
-}
-
-func (c *mockedConfig) FolderList() []config.FolderConfiguration {
-	return nil
-}
-
-func (c *mockedConfig) RemoveFolder(id string) (config.Waiter, error) {
-	return noopWaiter{}, nil
-}
-
-func (c *mockedConfig) FolderPasswords(device protocol.DeviceID) map[string]string {
-	return nil
-}
-func (c *mockedConfig) Device(id protocol.DeviceID) (config.DeviceConfiguration, bool) {
-	return config.DeviceConfiguration{}, false
-}
-
-func (c *mockedConfig) RemoveDevice(id protocol.DeviceID) (config.Waiter, error) {
-	return noopWaiter{}, nil
-}
-
-func (c *mockedConfig) IgnoredDevice(id protocol.DeviceID) bool {
-	return false
-}
-
-func (c *mockedConfig) IgnoredDevices() []config.ObservedDevice {
-	return nil
-}
-
-func (c *mockedConfig) IgnoredFolder(device protocol.DeviceID, folder string) bool {
-	return false
-}
-
-func (c *mockedConfig) DefaultFolder() config.FolderConfiguration {
-	return config.FolderConfiguration{}
-}
-
-func (c *mockedConfig) SetDefaultFolder(config.FolderConfiguration) (config.Waiter, error) {
-	return noopWaiter{}, nil
-}
-
-func (c *mockedConfig) DefaultDevice() config.DeviceConfiguration {
-	return config.DeviceConfiguration{}
-}
-
-func (c *mockedConfig) SetDefaultDevice(config.DeviceConfiguration) (config.Waiter, error) {
-	return noopWaiter{}, nil
-}
-
-func (c *mockedConfig) GlobalDiscoveryServers() []string {
-	return nil
-}
-
-func (c *mockedConfig) StunServers() []string {
-	return nil
-}
-
-func (c *mockedConfig) MyID() protocol.DeviceID {
-	return protocol.DeviceID{}
+func newMockedConfig() *mocks.Wrapper {
+	m := &mocks.Wrapper{}
+	m.ModifyReturns(noopWaiter{}, nil)
+	m.RemoveFolderReturns(noopWaiter{}, nil)
+	m.RemoveDeviceReturns(noopWaiter{}, nil)
+	return m
 }
 
 type noopWaiter struct{}

+ 0 - 33
lib/api/mocked_connections_test.go

@@ -1,33 +0,0 @@
-// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
-
-package api
-
-import (
-	"context"
-
-	"github.com/syncthing/syncthing/lib/connections"
-)
-
-type mockedConnections struct{}
-
-func (m *mockedConnections) ListenerStatus() map[string]connections.ListenerStatusEntry {
-	return nil
-}
-
-func (m *mockedConnections) ConnectionStatus() map[string]connections.ConnectionStatusEntry {
-	return nil
-}
-
-func (m *mockedConnections) NATType() string {
-	return ""
-}
-
-func (m *mockedConnections) Serve(ctx context.Context) error { return nil }
-
-func (m *mockedConnections) ExternalAddresses() []string { return nil }
-
-func (m *mockedConnections) AllAddresses() []string { return nil }

+ 0 - 46
lib/api/mocked_discovery_test.go

@@ -1,46 +0,0 @@
-// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
-
-package api
-
-import (
-	"context"
-
-	"github.com/syncthing/syncthing/lib/discover"
-	"github.com/syncthing/syncthing/lib/protocol"
-)
-
-type mockedCachingMux struct{}
-
-// from suture.Service
-
-func (m *mockedCachingMux) Serve(ctx context.Context) error {
-	select {}
-}
-
-// from events.Finder
-
-func (m *mockedCachingMux) Lookup(ctx context.Context, deviceID protocol.DeviceID) (direct []string, err error) {
-	return nil, nil
-}
-
-func (m *mockedCachingMux) Error() error {
-	return nil
-}
-
-func (m *mockedCachingMux) String() string {
-	return "mockedCachingMux"
-}
-
-func (m *mockedCachingMux) Cache() map[protocol.DeviceID]discover.CacheEntry {
-	return nil
-}
-
-// from events.Manager
-
-func (m *mockedCachingMux) ChildErrors() map[string]error {
-	return nil
-}

+ 0 - 21
lib/api/mocked_events_test.go

@@ -1,21 +0,0 @@
-// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
-
-package api
-
-import (
-	"time"
-
-	"github.com/syncthing/syncthing/lib/events"
-)
-
-type mockedEventSub struct{}
-
-func (s *mockedEventSub) Since(id int, into []events.Event, timeout time.Duration) []events.Event {
-	select {}
-}
-
-func (s *mockedEventSub) Mask() events.EventType { return 0 }

+ 0 - 26
lib/api/mocked_logger_test.go

@@ -1,26 +0,0 @@
-// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
-
-package api
-
-import (
-	"time"
-
-	"github.com/syncthing/syncthing/lib/logger"
-)
-
-type mockedLoggerRecorder struct{}
-
-func (r *mockedLoggerRecorder) Since(t time.Time) []logger.Line {
-	return []logger.Line{
-		{
-			When:    time.Now(),
-			Message: "Test message",
-		},
-	}
-}
-
-func (r *mockedLoggerRecorder) Clear() {}

+ 0 - 199
lib/api/mocked_model_test.go

@@ -1,199 +0,0 @@
-// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
-
-package api
-
-import (
-	"context"
-	"net"
-	"time"
-
-	"github.com/syncthing/syncthing/lib/db"
-	"github.com/syncthing/syncthing/lib/model"
-	"github.com/syncthing/syncthing/lib/protocol"
-	"github.com/syncthing/syncthing/lib/stats"
-	"github.com/syncthing/syncthing/lib/ur/contract"
-	"github.com/syncthing/syncthing/lib/versioner"
-)
-
-type mockedModel struct{}
-
-func (m *mockedModel) GlobalDirectoryTree(folder, prefix string, levels int, dirsOnly bool) ([]*model.TreeEntry, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) Completion(device protocol.DeviceID, folder string) model.FolderCompletion {
-	return model.FolderCompletion{}
-}
-
-func (m *mockedModel) Override(folder string) {}
-
-func (m *mockedModel) Revert(folder string) {}
-
-func (m *mockedModel) NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, error) {
-	return nil, nil, nil, nil
-}
-
-func (*mockedModel) RemoteNeedFolderFiles(folder string, device protocol.DeviceID, page, perpage int) ([]db.FileInfoTruncated, error) {
-	return nil, nil
-}
-
-func (*mockedModel) LocalChangedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) FolderProgressBytesCompleted(_ string) int64 {
-	return 0
-}
-
-func (m *mockedModel) NumConnections() int {
-	return 0
-}
-
-func (m *mockedModel) ConnectionStats() map[string]interface{} {
-	return nil
-}
-
-func (m *mockedModel) DeviceStatistics() (map[protocol.DeviceID]stats.DeviceStatistics, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) FolderStatistics() (map[string]stats.FolderStatistics, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool) {
-	return protocol.FileInfo{}, false
-}
-
-func (m *mockedModel) CurrentGlobalFile(folder string, file string) (protocol.FileInfo, bool) {
-	return protocol.FileInfo{}, false
-}
-
-func (m *mockedModel) ResetFolder(folder string) {
-}
-
-func (m *mockedModel) Availability(folder string, file protocol.FileInfo, block protocol.BlockInfo) []model.Availability {
-	return nil
-}
-
-func (m *mockedModel) LoadIgnores(folder string) ([]string, []string, error) {
-	return nil, nil, nil
-}
-
-func (m *mockedModel) CurrentIgnores(folder string) ([]string, []string, error) {
-	return nil, nil, nil
-}
-
-func (m *mockedModel) SetIgnores(folder string, content []string) error {
-	return nil
-}
-
-func (m *mockedModel) GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]error, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) PauseDevice(device protocol.DeviceID) {
-}
-
-func (m *mockedModel) ResumeDevice(device protocol.DeviceID) {}
-
-func (m *mockedModel) DelayScan(folder string, next time.Duration) {}
-
-func (m *mockedModel) ScanFolder(folder string) error {
-	return nil
-}
-
-func (m *mockedModel) ScanFolders() map[string]error {
-	return nil
-}
-
-func (m *mockedModel) ScanFolderSubdirs(folder string, subs []string) error {
-	return nil
-}
-
-func (m *mockedModel) BringToFront(folder, file string) {}
-
-func (m *mockedModel) Connection(deviceID protocol.DeviceID) (protocol.Connection, bool) {
-	return nil, false
-}
-
-func (m *mockedModel) State(folder string) (string, time.Time, error) {
-	return "", time.Time{}, nil
-}
-
-func (m *mockedModel) UsageReportingStats(r *contract.Report, version int, preview bool) {
-}
-
-func (m *mockedModel) PendingDevices() (map[protocol.DeviceID]db.ObservedDevice, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) PendingFolders(device protocol.DeviceID) (map[string]db.PendingFolder, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) FolderErrors(folder string) ([]model.FileError, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) WatchError(folder string) error {
-	return nil
-}
-
-func (m *mockedModel) Serve(ctx context.Context) error { return nil }
-
-func (m *mockedModel) Index(deviceID protocol.DeviceID, folder string, files []protocol.FileInfo) error {
-	return nil
-}
-
-func (m *mockedModel) IndexUpdate(deviceID protocol.DeviceID, folder string, files []protocol.FileInfo) error {
-	return nil
-}
-
-func (m *mockedModel) Request(deviceID protocol.DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (protocol.RequestResponse, error) {
-	return nil, nil
-}
-
-func (m *mockedModel) ClusterConfig(deviceID protocol.DeviceID, config protocol.ClusterConfig) error {
-	return nil
-}
-
-func (m *mockedModel) Closed(conn protocol.Connection, err error) {}
-
-func (m *mockedModel) DownloadProgress(deviceID protocol.DeviceID, folder string, updates []protocol.FileDownloadProgressUpdate) error {
-	return nil
-}
-
-func (m *mockedModel) AddConnection(conn protocol.Connection, hello protocol.Hello) {}
-
-func (m *mockedModel) OnHello(protocol.DeviceID, net.Addr, protocol.Hello) error {
-	return nil
-}
-
-func (m *mockedModel) GetHello(protocol.DeviceID) protocol.HelloIntf {
-	return nil
-}
-
-func (m *mockedModel) StartDeadlockDetector(timeout time.Duration) {}
-
-func (m *mockedModel) DBSnapshot(_ string) (*db.Snapshot, error) {
-	return nil, nil
-}
-
-type mockedFolderSummaryService struct{}
-
-func (m *mockedFolderSummaryService) Serve(context.Context) error { return nil }
-
-func (m *mockedFolderSummaryService) Summary(folder string) (map[string]interface{}, error) {
-	return map[string]interface{}{"mocked": true}, nil
-}
-
-func (m *mockedFolderSummaryService) OnEventRequest() {}

+ 1745 - 0
lib/config/mocks/mocked_wrapper.go

@@ -0,0 +1,1745 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"sync"
+
+	"github.com/syncthing/syncthing/lib/config"
+	"github.com/syncthing/syncthing/lib/protocol"
+)
+
+type Wrapper struct {
+	ConfigPathStub        func() string
+	configPathMutex       sync.RWMutex
+	configPathArgsForCall []struct {
+	}
+	configPathReturns struct {
+		result1 string
+	}
+	configPathReturnsOnCall map[int]struct {
+		result1 string
+	}
+	DefaultDeviceStub        func() config.DeviceConfiguration
+	defaultDeviceMutex       sync.RWMutex
+	defaultDeviceArgsForCall []struct {
+	}
+	defaultDeviceReturns struct {
+		result1 config.DeviceConfiguration
+	}
+	defaultDeviceReturnsOnCall map[int]struct {
+		result1 config.DeviceConfiguration
+	}
+	DefaultFolderStub        func() config.FolderConfiguration
+	defaultFolderMutex       sync.RWMutex
+	defaultFolderArgsForCall []struct {
+	}
+	defaultFolderReturns struct {
+		result1 config.FolderConfiguration
+	}
+	defaultFolderReturnsOnCall map[int]struct {
+		result1 config.FolderConfiguration
+	}
+	DeviceStub        func(protocol.DeviceID) (config.DeviceConfiguration, bool)
+	deviceMutex       sync.RWMutex
+	deviceArgsForCall []struct {
+		arg1 protocol.DeviceID
+	}
+	deviceReturns struct {
+		result1 config.DeviceConfiguration
+		result2 bool
+	}
+	deviceReturnsOnCall map[int]struct {
+		result1 config.DeviceConfiguration
+		result2 bool
+	}
+	DeviceListStub        func() []config.DeviceConfiguration
+	deviceListMutex       sync.RWMutex
+	deviceListArgsForCall []struct {
+	}
+	deviceListReturns struct {
+		result1 []config.DeviceConfiguration
+	}
+	deviceListReturnsOnCall map[int]struct {
+		result1 []config.DeviceConfiguration
+	}
+	DevicesStub        func() map[protocol.DeviceID]config.DeviceConfiguration
+	devicesMutex       sync.RWMutex
+	devicesArgsForCall []struct {
+	}
+	devicesReturns struct {
+		result1 map[protocol.DeviceID]config.DeviceConfiguration
+	}
+	devicesReturnsOnCall map[int]struct {
+		result1 map[protocol.DeviceID]config.DeviceConfiguration
+	}
+	FolderStub        func(string) (config.FolderConfiguration, bool)
+	folderMutex       sync.RWMutex
+	folderArgsForCall []struct {
+		arg1 string
+	}
+	folderReturns struct {
+		result1 config.FolderConfiguration
+		result2 bool
+	}
+	folderReturnsOnCall map[int]struct {
+		result1 config.FolderConfiguration
+		result2 bool
+	}
+	FolderListStub        func() []config.FolderConfiguration
+	folderListMutex       sync.RWMutex
+	folderListArgsForCall []struct {
+	}
+	folderListReturns struct {
+		result1 []config.FolderConfiguration
+	}
+	folderListReturnsOnCall map[int]struct {
+		result1 []config.FolderConfiguration
+	}
+	FolderPasswordsStub        func(protocol.DeviceID) map[string]string
+	folderPasswordsMutex       sync.RWMutex
+	folderPasswordsArgsForCall []struct {
+		arg1 protocol.DeviceID
+	}
+	folderPasswordsReturns struct {
+		result1 map[string]string
+	}
+	folderPasswordsReturnsOnCall map[int]struct {
+		result1 map[string]string
+	}
+	FoldersStub        func() map[string]config.FolderConfiguration
+	foldersMutex       sync.RWMutex
+	foldersArgsForCall []struct {
+	}
+	foldersReturns struct {
+		result1 map[string]config.FolderConfiguration
+	}
+	foldersReturnsOnCall map[int]struct {
+		result1 map[string]config.FolderConfiguration
+	}
+	GUIStub        func() config.GUIConfiguration
+	gUIMutex       sync.RWMutex
+	gUIArgsForCall []struct {
+	}
+	gUIReturns struct {
+		result1 config.GUIConfiguration
+	}
+	gUIReturnsOnCall map[int]struct {
+		result1 config.GUIConfiguration
+	}
+	IgnoredDeviceStub        func(protocol.DeviceID) bool
+	ignoredDeviceMutex       sync.RWMutex
+	ignoredDeviceArgsForCall []struct {
+		arg1 protocol.DeviceID
+	}
+	ignoredDeviceReturns struct {
+		result1 bool
+	}
+	ignoredDeviceReturnsOnCall map[int]struct {
+		result1 bool
+	}
+	IgnoredDevicesStub        func() []config.ObservedDevice
+	ignoredDevicesMutex       sync.RWMutex
+	ignoredDevicesArgsForCall []struct {
+	}
+	ignoredDevicesReturns struct {
+		result1 []config.ObservedDevice
+	}
+	ignoredDevicesReturnsOnCall map[int]struct {
+		result1 []config.ObservedDevice
+	}
+	IgnoredFolderStub        func(protocol.DeviceID, string) bool
+	ignoredFolderMutex       sync.RWMutex
+	ignoredFolderArgsForCall []struct {
+		arg1 protocol.DeviceID
+		arg2 string
+	}
+	ignoredFolderReturns struct {
+		result1 bool
+	}
+	ignoredFolderReturnsOnCall map[int]struct {
+		result1 bool
+	}
+	LDAPStub        func() config.LDAPConfiguration
+	lDAPMutex       sync.RWMutex
+	lDAPArgsForCall []struct {
+	}
+	lDAPReturns struct {
+		result1 config.LDAPConfiguration
+	}
+	lDAPReturnsOnCall map[int]struct {
+		result1 config.LDAPConfiguration
+	}
+	ModifyStub        func(config.ModifyFunction) (config.Waiter, error)
+	modifyMutex       sync.RWMutex
+	modifyArgsForCall []struct {
+		arg1 config.ModifyFunction
+	}
+	modifyReturns struct {
+		result1 config.Waiter
+		result2 error
+	}
+	modifyReturnsOnCall map[int]struct {
+		result1 config.Waiter
+		result2 error
+	}
+	MyIDStub        func() protocol.DeviceID
+	myIDMutex       sync.RWMutex
+	myIDArgsForCall []struct {
+	}
+	myIDReturns struct {
+		result1 protocol.DeviceID
+	}
+	myIDReturnsOnCall map[int]struct {
+		result1 protocol.DeviceID
+	}
+	OptionsStub        func() config.OptionsConfiguration
+	optionsMutex       sync.RWMutex
+	optionsArgsForCall []struct {
+	}
+	optionsReturns struct {
+		result1 config.OptionsConfiguration
+	}
+	optionsReturnsOnCall map[int]struct {
+		result1 config.OptionsConfiguration
+	}
+	RawCopyStub        func() config.Configuration
+	rawCopyMutex       sync.RWMutex
+	rawCopyArgsForCall []struct {
+	}
+	rawCopyReturns struct {
+		result1 config.Configuration
+	}
+	rawCopyReturnsOnCall map[int]struct {
+		result1 config.Configuration
+	}
+	RemoveDeviceStub        func(protocol.DeviceID) (config.Waiter, error)
+	removeDeviceMutex       sync.RWMutex
+	removeDeviceArgsForCall []struct {
+		arg1 protocol.DeviceID
+	}
+	removeDeviceReturns struct {
+		result1 config.Waiter
+		result2 error
+	}
+	removeDeviceReturnsOnCall map[int]struct {
+		result1 config.Waiter
+		result2 error
+	}
+	RemoveFolderStub        func(string) (config.Waiter, error)
+	removeFolderMutex       sync.RWMutex
+	removeFolderArgsForCall []struct {
+		arg1 string
+	}
+	removeFolderReturns struct {
+		result1 config.Waiter
+		result2 error
+	}
+	removeFolderReturnsOnCall map[int]struct {
+		result1 config.Waiter
+		result2 error
+	}
+	RequiresRestartStub        func() bool
+	requiresRestartMutex       sync.RWMutex
+	requiresRestartArgsForCall []struct {
+	}
+	requiresRestartReturns struct {
+		result1 bool
+	}
+	requiresRestartReturnsOnCall map[int]struct {
+		result1 bool
+	}
+	SaveStub        func() error
+	saveMutex       sync.RWMutex
+	saveArgsForCall []struct {
+	}
+	saveReturns struct {
+		result1 error
+	}
+	saveReturnsOnCall map[int]struct {
+		result1 error
+	}
+	SubscribeStub        func(config.Committer) config.Configuration
+	subscribeMutex       sync.RWMutex
+	subscribeArgsForCall []struct {
+		arg1 config.Committer
+	}
+	subscribeReturns struct {
+		result1 config.Configuration
+	}
+	subscribeReturnsOnCall map[int]struct {
+		result1 config.Configuration
+	}
+	UnsubscribeStub        func(config.Committer)
+	unsubscribeMutex       sync.RWMutex
+	unsubscribeArgsForCall []struct {
+		arg1 config.Committer
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *Wrapper) ConfigPath() string {
+	fake.configPathMutex.Lock()
+	ret, specificReturn := fake.configPathReturnsOnCall[len(fake.configPathArgsForCall)]
+	fake.configPathArgsForCall = append(fake.configPathArgsForCall, struct {
+	}{})
+	stub := fake.ConfigPathStub
+	fakeReturns := fake.configPathReturns
+	fake.recordInvocation("ConfigPath", []interface{}{})
+	fake.configPathMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) ConfigPathCallCount() int {
+	fake.configPathMutex.RLock()
+	defer fake.configPathMutex.RUnlock()
+	return len(fake.configPathArgsForCall)
+}
+
+func (fake *Wrapper) ConfigPathCalls(stub func() string) {
+	fake.configPathMutex.Lock()
+	defer fake.configPathMutex.Unlock()
+	fake.ConfigPathStub = stub
+}
+
+func (fake *Wrapper) ConfigPathReturns(result1 string) {
+	fake.configPathMutex.Lock()
+	defer fake.configPathMutex.Unlock()
+	fake.ConfigPathStub = nil
+	fake.configPathReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Wrapper) ConfigPathReturnsOnCall(i int, result1 string) {
+	fake.configPathMutex.Lock()
+	defer fake.configPathMutex.Unlock()
+	fake.ConfigPathStub = nil
+	if fake.configPathReturnsOnCall == nil {
+		fake.configPathReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.configPathReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Wrapper) DefaultDevice() config.DeviceConfiguration {
+	fake.defaultDeviceMutex.Lock()
+	ret, specificReturn := fake.defaultDeviceReturnsOnCall[len(fake.defaultDeviceArgsForCall)]
+	fake.defaultDeviceArgsForCall = append(fake.defaultDeviceArgsForCall, struct {
+	}{})
+	stub := fake.DefaultDeviceStub
+	fakeReturns := fake.defaultDeviceReturns
+	fake.recordInvocation("DefaultDevice", []interface{}{})
+	fake.defaultDeviceMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) DefaultDeviceCallCount() int {
+	fake.defaultDeviceMutex.RLock()
+	defer fake.defaultDeviceMutex.RUnlock()
+	return len(fake.defaultDeviceArgsForCall)
+}
+
+func (fake *Wrapper) DefaultDeviceCalls(stub func() config.DeviceConfiguration) {
+	fake.defaultDeviceMutex.Lock()
+	defer fake.defaultDeviceMutex.Unlock()
+	fake.DefaultDeviceStub = stub
+}
+
+func (fake *Wrapper) DefaultDeviceReturns(result1 config.DeviceConfiguration) {
+	fake.defaultDeviceMutex.Lock()
+	defer fake.defaultDeviceMutex.Unlock()
+	fake.DefaultDeviceStub = nil
+	fake.defaultDeviceReturns = struct {
+		result1 config.DeviceConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) DefaultDeviceReturnsOnCall(i int, result1 config.DeviceConfiguration) {
+	fake.defaultDeviceMutex.Lock()
+	defer fake.defaultDeviceMutex.Unlock()
+	fake.DefaultDeviceStub = nil
+	if fake.defaultDeviceReturnsOnCall == nil {
+		fake.defaultDeviceReturnsOnCall = make(map[int]struct {
+			result1 config.DeviceConfiguration
+		})
+	}
+	fake.defaultDeviceReturnsOnCall[i] = struct {
+		result1 config.DeviceConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) DefaultFolder() config.FolderConfiguration {
+	fake.defaultFolderMutex.Lock()
+	ret, specificReturn := fake.defaultFolderReturnsOnCall[len(fake.defaultFolderArgsForCall)]
+	fake.defaultFolderArgsForCall = append(fake.defaultFolderArgsForCall, struct {
+	}{})
+	stub := fake.DefaultFolderStub
+	fakeReturns := fake.defaultFolderReturns
+	fake.recordInvocation("DefaultFolder", []interface{}{})
+	fake.defaultFolderMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) DefaultFolderCallCount() int {
+	fake.defaultFolderMutex.RLock()
+	defer fake.defaultFolderMutex.RUnlock()
+	return len(fake.defaultFolderArgsForCall)
+}
+
+func (fake *Wrapper) DefaultFolderCalls(stub func() config.FolderConfiguration) {
+	fake.defaultFolderMutex.Lock()
+	defer fake.defaultFolderMutex.Unlock()
+	fake.DefaultFolderStub = stub
+}
+
+func (fake *Wrapper) DefaultFolderReturns(result1 config.FolderConfiguration) {
+	fake.defaultFolderMutex.Lock()
+	defer fake.defaultFolderMutex.Unlock()
+	fake.DefaultFolderStub = nil
+	fake.defaultFolderReturns = struct {
+		result1 config.FolderConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) DefaultFolderReturnsOnCall(i int, result1 config.FolderConfiguration) {
+	fake.defaultFolderMutex.Lock()
+	defer fake.defaultFolderMutex.Unlock()
+	fake.DefaultFolderStub = nil
+	if fake.defaultFolderReturnsOnCall == nil {
+		fake.defaultFolderReturnsOnCall = make(map[int]struct {
+			result1 config.FolderConfiguration
+		})
+	}
+	fake.defaultFolderReturnsOnCall[i] = struct {
+		result1 config.FolderConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) Device(arg1 protocol.DeviceID) (config.DeviceConfiguration, bool) {
+	fake.deviceMutex.Lock()
+	ret, specificReturn := fake.deviceReturnsOnCall[len(fake.deviceArgsForCall)]
+	fake.deviceArgsForCall = append(fake.deviceArgsForCall, struct {
+		arg1 protocol.DeviceID
+	}{arg1})
+	stub := fake.DeviceStub
+	fakeReturns := fake.deviceReturns
+	fake.recordInvocation("Device", []interface{}{arg1})
+	fake.deviceMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Wrapper) DeviceCallCount() int {
+	fake.deviceMutex.RLock()
+	defer fake.deviceMutex.RUnlock()
+	return len(fake.deviceArgsForCall)
+}
+
+func (fake *Wrapper) DeviceCalls(stub func(protocol.DeviceID) (config.DeviceConfiguration, bool)) {
+	fake.deviceMutex.Lock()
+	defer fake.deviceMutex.Unlock()
+	fake.DeviceStub = stub
+}
+
+func (fake *Wrapper) DeviceArgsForCall(i int) protocol.DeviceID {
+	fake.deviceMutex.RLock()
+	defer fake.deviceMutex.RUnlock()
+	argsForCall := fake.deviceArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) DeviceReturns(result1 config.DeviceConfiguration, result2 bool) {
+	fake.deviceMutex.Lock()
+	defer fake.deviceMutex.Unlock()
+	fake.DeviceStub = nil
+	fake.deviceReturns = struct {
+		result1 config.DeviceConfiguration
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Wrapper) DeviceReturnsOnCall(i int, result1 config.DeviceConfiguration, result2 bool) {
+	fake.deviceMutex.Lock()
+	defer fake.deviceMutex.Unlock()
+	fake.DeviceStub = nil
+	if fake.deviceReturnsOnCall == nil {
+		fake.deviceReturnsOnCall = make(map[int]struct {
+			result1 config.DeviceConfiguration
+			result2 bool
+		})
+	}
+	fake.deviceReturnsOnCall[i] = struct {
+		result1 config.DeviceConfiguration
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Wrapper) DeviceList() []config.DeviceConfiguration {
+	fake.deviceListMutex.Lock()
+	ret, specificReturn := fake.deviceListReturnsOnCall[len(fake.deviceListArgsForCall)]
+	fake.deviceListArgsForCall = append(fake.deviceListArgsForCall, struct {
+	}{})
+	stub := fake.DeviceListStub
+	fakeReturns := fake.deviceListReturns
+	fake.recordInvocation("DeviceList", []interface{}{})
+	fake.deviceListMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) DeviceListCallCount() int {
+	fake.deviceListMutex.RLock()
+	defer fake.deviceListMutex.RUnlock()
+	return len(fake.deviceListArgsForCall)
+}
+
+func (fake *Wrapper) DeviceListCalls(stub func() []config.DeviceConfiguration) {
+	fake.deviceListMutex.Lock()
+	defer fake.deviceListMutex.Unlock()
+	fake.DeviceListStub = stub
+}
+
+func (fake *Wrapper) DeviceListReturns(result1 []config.DeviceConfiguration) {
+	fake.deviceListMutex.Lock()
+	defer fake.deviceListMutex.Unlock()
+	fake.DeviceListStub = nil
+	fake.deviceListReturns = struct {
+		result1 []config.DeviceConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) DeviceListReturnsOnCall(i int, result1 []config.DeviceConfiguration) {
+	fake.deviceListMutex.Lock()
+	defer fake.deviceListMutex.Unlock()
+	fake.DeviceListStub = nil
+	if fake.deviceListReturnsOnCall == nil {
+		fake.deviceListReturnsOnCall = make(map[int]struct {
+			result1 []config.DeviceConfiguration
+		})
+	}
+	fake.deviceListReturnsOnCall[i] = struct {
+		result1 []config.DeviceConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) Devices() map[protocol.DeviceID]config.DeviceConfiguration {
+	fake.devicesMutex.Lock()
+	ret, specificReturn := fake.devicesReturnsOnCall[len(fake.devicesArgsForCall)]
+	fake.devicesArgsForCall = append(fake.devicesArgsForCall, struct {
+	}{})
+	stub := fake.DevicesStub
+	fakeReturns := fake.devicesReturns
+	fake.recordInvocation("Devices", []interface{}{})
+	fake.devicesMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) DevicesCallCount() int {
+	fake.devicesMutex.RLock()
+	defer fake.devicesMutex.RUnlock()
+	return len(fake.devicesArgsForCall)
+}
+
+func (fake *Wrapper) DevicesCalls(stub func() map[protocol.DeviceID]config.DeviceConfiguration) {
+	fake.devicesMutex.Lock()
+	defer fake.devicesMutex.Unlock()
+	fake.DevicesStub = stub
+}
+
+func (fake *Wrapper) DevicesReturns(result1 map[protocol.DeviceID]config.DeviceConfiguration) {
+	fake.devicesMutex.Lock()
+	defer fake.devicesMutex.Unlock()
+	fake.DevicesStub = nil
+	fake.devicesReturns = struct {
+		result1 map[protocol.DeviceID]config.DeviceConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) DevicesReturnsOnCall(i int, result1 map[protocol.DeviceID]config.DeviceConfiguration) {
+	fake.devicesMutex.Lock()
+	defer fake.devicesMutex.Unlock()
+	fake.DevicesStub = nil
+	if fake.devicesReturnsOnCall == nil {
+		fake.devicesReturnsOnCall = make(map[int]struct {
+			result1 map[protocol.DeviceID]config.DeviceConfiguration
+		})
+	}
+	fake.devicesReturnsOnCall[i] = struct {
+		result1 map[protocol.DeviceID]config.DeviceConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) Folder(arg1 string) (config.FolderConfiguration, bool) {
+	fake.folderMutex.Lock()
+	ret, specificReturn := fake.folderReturnsOnCall[len(fake.folderArgsForCall)]
+	fake.folderArgsForCall = append(fake.folderArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.FolderStub
+	fakeReturns := fake.folderReturns
+	fake.recordInvocation("Folder", []interface{}{arg1})
+	fake.folderMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Wrapper) FolderCallCount() int {
+	fake.folderMutex.RLock()
+	defer fake.folderMutex.RUnlock()
+	return len(fake.folderArgsForCall)
+}
+
+func (fake *Wrapper) FolderCalls(stub func(string) (config.FolderConfiguration, bool)) {
+	fake.folderMutex.Lock()
+	defer fake.folderMutex.Unlock()
+	fake.FolderStub = stub
+}
+
+func (fake *Wrapper) FolderArgsForCall(i int) string {
+	fake.folderMutex.RLock()
+	defer fake.folderMutex.RUnlock()
+	argsForCall := fake.folderArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) FolderReturns(result1 config.FolderConfiguration, result2 bool) {
+	fake.folderMutex.Lock()
+	defer fake.folderMutex.Unlock()
+	fake.FolderStub = nil
+	fake.folderReturns = struct {
+		result1 config.FolderConfiguration
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Wrapper) FolderReturnsOnCall(i int, result1 config.FolderConfiguration, result2 bool) {
+	fake.folderMutex.Lock()
+	defer fake.folderMutex.Unlock()
+	fake.FolderStub = nil
+	if fake.folderReturnsOnCall == nil {
+		fake.folderReturnsOnCall = make(map[int]struct {
+			result1 config.FolderConfiguration
+			result2 bool
+		})
+	}
+	fake.folderReturnsOnCall[i] = struct {
+		result1 config.FolderConfiguration
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Wrapper) FolderList() []config.FolderConfiguration {
+	fake.folderListMutex.Lock()
+	ret, specificReturn := fake.folderListReturnsOnCall[len(fake.folderListArgsForCall)]
+	fake.folderListArgsForCall = append(fake.folderListArgsForCall, struct {
+	}{})
+	stub := fake.FolderListStub
+	fakeReturns := fake.folderListReturns
+	fake.recordInvocation("FolderList", []interface{}{})
+	fake.folderListMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) FolderListCallCount() int {
+	fake.folderListMutex.RLock()
+	defer fake.folderListMutex.RUnlock()
+	return len(fake.folderListArgsForCall)
+}
+
+func (fake *Wrapper) FolderListCalls(stub func() []config.FolderConfiguration) {
+	fake.folderListMutex.Lock()
+	defer fake.folderListMutex.Unlock()
+	fake.FolderListStub = stub
+}
+
+func (fake *Wrapper) FolderListReturns(result1 []config.FolderConfiguration) {
+	fake.folderListMutex.Lock()
+	defer fake.folderListMutex.Unlock()
+	fake.FolderListStub = nil
+	fake.folderListReturns = struct {
+		result1 []config.FolderConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) FolderListReturnsOnCall(i int, result1 []config.FolderConfiguration) {
+	fake.folderListMutex.Lock()
+	defer fake.folderListMutex.Unlock()
+	fake.FolderListStub = nil
+	if fake.folderListReturnsOnCall == nil {
+		fake.folderListReturnsOnCall = make(map[int]struct {
+			result1 []config.FolderConfiguration
+		})
+	}
+	fake.folderListReturnsOnCall[i] = struct {
+		result1 []config.FolderConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) FolderPasswords(arg1 protocol.DeviceID) map[string]string {
+	fake.folderPasswordsMutex.Lock()
+	ret, specificReturn := fake.folderPasswordsReturnsOnCall[len(fake.folderPasswordsArgsForCall)]
+	fake.folderPasswordsArgsForCall = append(fake.folderPasswordsArgsForCall, struct {
+		arg1 protocol.DeviceID
+	}{arg1})
+	stub := fake.FolderPasswordsStub
+	fakeReturns := fake.folderPasswordsReturns
+	fake.recordInvocation("FolderPasswords", []interface{}{arg1})
+	fake.folderPasswordsMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) FolderPasswordsCallCount() int {
+	fake.folderPasswordsMutex.RLock()
+	defer fake.folderPasswordsMutex.RUnlock()
+	return len(fake.folderPasswordsArgsForCall)
+}
+
+func (fake *Wrapper) FolderPasswordsCalls(stub func(protocol.DeviceID) map[string]string) {
+	fake.folderPasswordsMutex.Lock()
+	defer fake.folderPasswordsMutex.Unlock()
+	fake.FolderPasswordsStub = stub
+}
+
+func (fake *Wrapper) FolderPasswordsArgsForCall(i int) protocol.DeviceID {
+	fake.folderPasswordsMutex.RLock()
+	defer fake.folderPasswordsMutex.RUnlock()
+	argsForCall := fake.folderPasswordsArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) FolderPasswordsReturns(result1 map[string]string) {
+	fake.folderPasswordsMutex.Lock()
+	defer fake.folderPasswordsMutex.Unlock()
+	fake.FolderPasswordsStub = nil
+	fake.folderPasswordsReturns = struct {
+		result1 map[string]string
+	}{result1}
+}
+
+func (fake *Wrapper) FolderPasswordsReturnsOnCall(i int, result1 map[string]string) {
+	fake.folderPasswordsMutex.Lock()
+	defer fake.folderPasswordsMutex.Unlock()
+	fake.FolderPasswordsStub = nil
+	if fake.folderPasswordsReturnsOnCall == nil {
+		fake.folderPasswordsReturnsOnCall = make(map[int]struct {
+			result1 map[string]string
+		})
+	}
+	fake.folderPasswordsReturnsOnCall[i] = struct {
+		result1 map[string]string
+	}{result1}
+}
+
+func (fake *Wrapper) Folders() map[string]config.FolderConfiguration {
+	fake.foldersMutex.Lock()
+	ret, specificReturn := fake.foldersReturnsOnCall[len(fake.foldersArgsForCall)]
+	fake.foldersArgsForCall = append(fake.foldersArgsForCall, struct {
+	}{})
+	stub := fake.FoldersStub
+	fakeReturns := fake.foldersReturns
+	fake.recordInvocation("Folders", []interface{}{})
+	fake.foldersMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) FoldersCallCount() int {
+	fake.foldersMutex.RLock()
+	defer fake.foldersMutex.RUnlock()
+	return len(fake.foldersArgsForCall)
+}
+
+func (fake *Wrapper) FoldersCalls(stub func() map[string]config.FolderConfiguration) {
+	fake.foldersMutex.Lock()
+	defer fake.foldersMutex.Unlock()
+	fake.FoldersStub = stub
+}
+
+func (fake *Wrapper) FoldersReturns(result1 map[string]config.FolderConfiguration) {
+	fake.foldersMutex.Lock()
+	defer fake.foldersMutex.Unlock()
+	fake.FoldersStub = nil
+	fake.foldersReturns = struct {
+		result1 map[string]config.FolderConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) FoldersReturnsOnCall(i int, result1 map[string]config.FolderConfiguration) {
+	fake.foldersMutex.Lock()
+	defer fake.foldersMutex.Unlock()
+	fake.FoldersStub = nil
+	if fake.foldersReturnsOnCall == nil {
+		fake.foldersReturnsOnCall = make(map[int]struct {
+			result1 map[string]config.FolderConfiguration
+		})
+	}
+	fake.foldersReturnsOnCall[i] = struct {
+		result1 map[string]config.FolderConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) GUI() config.GUIConfiguration {
+	fake.gUIMutex.Lock()
+	ret, specificReturn := fake.gUIReturnsOnCall[len(fake.gUIArgsForCall)]
+	fake.gUIArgsForCall = append(fake.gUIArgsForCall, struct {
+	}{})
+	stub := fake.GUIStub
+	fakeReturns := fake.gUIReturns
+	fake.recordInvocation("GUI", []interface{}{})
+	fake.gUIMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) GUICallCount() int {
+	fake.gUIMutex.RLock()
+	defer fake.gUIMutex.RUnlock()
+	return len(fake.gUIArgsForCall)
+}
+
+func (fake *Wrapper) GUICalls(stub func() config.GUIConfiguration) {
+	fake.gUIMutex.Lock()
+	defer fake.gUIMutex.Unlock()
+	fake.GUIStub = stub
+}
+
+func (fake *Wrapper) GUIReturns(result1 config.GUIConfiguration) {
+	fake.gUIMutex.Lock()
+	defer fake.gUIMutex.Unlock()
+	fake.GUIStub = nil
+	fake.gUIReturns = struct {
+		result1 config.GUIConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) GUIReturnsOnCall(i int, result1 config.GUIConfiguration) {
+	fake.gUIMutex.Lock()
+	defer fake.gUIMutex.Unlock()
+	fake.GUIStub = nil
+	if fake.gUIReturnsOnCall == nil {
+		fake.gUIReturnsOnCall = make(map[int]struct {
+			result1 config.GUIConfiguration
+		})
+	}
+	fake.gUIReturnsOnCall[i] = struct {
+		result1 config.GUIConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) IgnoredDevice(arg1 protocol.DeviceID) bool {
+	fake.ignoredDeviceMutex.Lock()
+	ret, specificReturn := fake.ignoredDeviceReturnsOnCall[len(fake.ignoredDeviceArgsForCall)]
+	fake.ignoredDeviceArgsForCall = append(fake.ignoredDeviceArgsForCall, struct {
+		arg1 protocol.DeviceID
+	}{arg1})
+	stub := fake.IgnoredDeviceStub
+	fakeReturns := fake.ignoredDeviceReturns
+	fake.recordInvocation("IgnoredDevice", []interface{}{arg1})
+	fake.ignoredDeviceMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) IgnoredDeviceCallCount() int {
+	fake.ignoredDeviceMutex.RLock()
+	defer fake.ignoredDeviceMutex.RUnlock()
+	return len(fake.ignoredDeviceArgsForCall)
+}
+
+func (fake *Wrapper) IgnoredDeviceCalls(stub func(protocol.DeviceID) bool) {
+	fake.ignoredDeviceMutex.Lock()
+	defer fake.ignoredDeviceMutex.Unlock()
+	fake.IgnoredDeviceStub = stub
+}
+
+func (fake *Wrapper) IgnoredDeviceArgsForCall(i int) protocol.DeviceID {
+	fake.ignoredDeviceMutex.RLock()
+	defer fake.ignoredDeviceMutex.RUnlock()
+	argsForCall := fake.ignoredDeviceArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) IgnoredDeviceReturns(result1 bool) {
+	fake.ignoredDeviceMutex.Lock()
+	defer fake.ignoredDeviceMutex.Unlock()
+	fake.IgnoredDeviceStub = nil
+	fake.ignoredDeviceReturns = struct {
+		result1 bool
+	}{result1}
+}
+
+func (fake *Wrapper) IgnoredDeviceReturnsOnCall(i int, result1 bool) {
+	fake.ignoredDeviceMutex.Lock()
+	defer fake.ignoredDeviceMutex.Unlock()
+	fake.IgnoredDeviceStub = nil
+	if fake.ignoredDeviceReturnsOnCall == nil {
+		fake.ignoredDeviceReturnsOnCall = make(map[int]struct {
+			result1 bool
+		})
+	}
+	fake.ignoredDeviceReturnsOnCall[i] = struct {
+		result1 bool
+	}{result1}
+}
+
+func (fake *Wrapper) IgnoredDevices() []config.ObservedDevice {
+	fake.ignoredDevicesMutex.Lock()
+	ret, specificReturn := fake.ignoredDevicesReturnsOnCall[len(fake.ignoredDevicesArgsForCall)]
+	fake.ignoredDevicesArgsForCall = append(fake.ignoredDevicesArgsForCall, struct {
+	}{})
+	stub := fake.IgnoredDevicesStub
+	fakeReturns := fake.ignoredDevicesReturns
+	fake.recordInvocation("IgnoredDevices", []interface{}{})
+	fake.ignoredDevicesMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) IgnoredDevicesCallCount() int {
+	fake.ignoredDevicesMutex.RLock()
+	defer fake.ignoredDevicesMutex.RUnlock()
+	return len(fake.ignoredDevicesArgsForCall)
+}
+
+func (fake *Wrapper) IgnoredDevicesCalls(stub func() []config.ObservedDevice) {
+	fake.ignoredDevicesMutex.Lock()
+	defer fake.ignoredDevicesMutex.Unlock()
+	fake.IgnoredDevicesStub = stub
+}
+
+func (fake *Wrapper) IgnoredDevicesReturns(result1 []config.ObservedDevice) {
+	fake.ignoredDevicesMutex.Lock()
+	defer fake.ignoredDevicesMutex.Unlock()
+	fake.IgnoredDevicesStub = nil
+	fake.ignoredDevicesReturns = struct {
+		result1 []config.ObservedDevice
+	}{result1}
+}
+
+func (fake *Wrapper) IgnoredDevicesReturnsOnCall(i int, result1 []config.ObservedDevice) {
+	fake.ignoredDevicesMutex.Lock()
+	defer fake.ignoredDevicesMutex.Unlock()
+	fake.IgnoredDevicesStub = nil
+	if fake.ignoredDevicesReturnsOnCall == nil {
+		fake.ignoredDevicesReturnsOnCall = make(map[int]struct {
+			result1 []config.ObservedDevice
+		})
+	}
+	fake.ignoredDevicesReturnsOnCall[i] = struct {
+		result1 []config.ObservedDevice
+	}{result1}
+}
+
+func (fake *Wrapper) IgnoredFolder(arg1 protocol.DeviceID, arg2 string) bool {
+	fake.ignoredFolderMutex.Lock()
+	ret, specificReturn := fake.ignoredFolderReturnsOnCall[len(fake.ignoredFolderArgsForCall)]
+	fake.ignoredFolderArgsForCall = append(fake.ignoredFolderArgsForCall, struct {
+		arg1 protocol.DeviceID
+		arg2 string
+	}{arg1, arg2})
+	stub := fake.IgnoredFolderStub
+	fakeReturns := fake.ignoredFolderReturns
+	fake.recordInvocation("IgnoredFolder", []interface{}{arg1, arg2})
+	fake.ignoredFolderMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) IgnoredFolderCallCount() int {
+	fake.ignoredFolderMutex.RLock()
+	defer fake.ignoredFolderMutex.RUnlock()
+	return len(fake.ignoredFolderArgsForCall)
+}
+
+func (fake *Wrapper) IgnoredFolderCalls(stub func(protocol.DeviceID, string) bool) {
+	fake.ignoredFolderMutex.Lock()
+	defer fake.ignoredFolderMutex.Unlock()
+	fake.IgnoredFolderStub = stub
+}
+
+func (fake *Wrapper) IgnoredFolderArgsForCall(i int) (protocol.DeviceID, string) {
+	fake.ignoredFolderMutex.RLock()
+	defer fake.ignoredFolderMutex.RUnlock()
+	argsForCall := fake.ignoredFolderArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Wrapper) IgnoredFolderReturns(result1 bool) {
+	fake.ignoredFolderMutex.Lock()
+	defer fake.ignoredFolderMutex.Unlock()
+	fake.IgnoredFolderStub = nil
+	fake.ignoredFolderReturns = struct {
+		result1 bool
+	}{result1}
+}
+
+func (fake *Wrapper) IgnoredFolderReturnsOnCall(i int, result1 bool) {
+	fake.ignoredFolderMutex.Lock()
+	defer fake.ignoredFolderMutex.Unlock()
+	fake.IgnoredFolderStub = nil
+	if fake.ignoredFolderReturnsOnCall == nil {
+		fake.ignoredFolderReturnsOnCall = make(map[int]struct {
+			result1 bool
+		})
+	}
+	fake.ignoredFolderReturnsOnCall[i] = struct {
+		result1 bool
+	}{result1}
+}
+
+func (fake *Wrapper) LDAP() config.LDAPConfiguration {
+	fake.lDAPMutex.Lock()
+	ret, specificReturn := fake.lDAPReturnsOnCall[len(fake.lDAPArgsForCall)]
+	fake.lDAPArgsForCall = append(fake.lDAPArgsForCall, struct {
+	}{})
+	stub := fake.LDAPStub
+	fakeReturns := fake.lDAPReturns
+	fake.recordInvocation("LDAP", []interface{}{})
+	fake.lDAPMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) LDAPCallCount() int {
+	fake.lDAPMutex.RLock()
+	defer fake.lDAPMutex.RUnlock()
+	return len(fake.lDAPArgsForCall)
+}
+
+func (fake *Wrapper) LDAPCalls(stub func() config.LDAPConfiguration) {
+	fake.lDAPMutex.Lock()
+	defer fake.lDAPMutex.Unlock()
+	fake.LDAPStub = stub
+}
+
+func (fake *Wrapper) LDAPReturns(result1 config.LDAPConfiguration) {
+	fake.lDAPMutex.Lock()
+	defer fake.lDAPMutex.Unlock()
+	fake.LDAPStub = nil
+	fake.lDAPReturns = struct {
+		result1 config.LDAPConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) LDAPReturnsOnCall(i int, result1 config.LDAPConfiguration) {
+	fake.lDAPMutex.Lock()
+	defer fake.lDAPMutex.Unlock()
+	fake.LDAPStub = nil
+	if fake.lDAPReturnsOnCall == nil {
+		fake.lDAPReturnsOnCall = make(map[int]struct {
+			result1 config.LDAPConfiguration
+		})
+	}
+	fake.lDAPReturnsOnCall[i] = struct {
+		result1 config.LDAPConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) Modify(arg1 config.ModifyFunction) (config.Waiter, error) {
+	fake.modifyMutex.Lock()
+	ret, specificReturn := fake.modifyReturnsOnCall[len(fake.modifyArgsForCall)]
+	fake.modifyArgsForCall = append(fake.modifyArgsForCall, struct {
+		arg1 config.ModifyFunction
+	}{arg1})
+	stub := fake.ModifyStub
+	fakeReturns := fake.modifyReturns
+	fake.recordInvocation("Modify", []interface{}{arg1})
+	fake.modifyMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Wrapper) ModifyCallCount() int {
+	fake.modifyMutex.RLock()
+	defer fake.modifyMutex.RUnlock()
+	return len(fake.modifyArgsForCall)
+}
+
+func (fake *Wrapper) ModifyCalls(stub func(config.ModifyFunction) (config.Waiter, error)) {
+	fake.modifyMutex.Lock()
+	defer fake.modifyMutex.Unlock()
+	fake.ModifyStub = stub
+}
+
+func (fake *Wrapper) ModifyArgsForCall(i int) config.ModifyFunction {
+	fake.modifyMutex.RLock()
+	defer fake.modifyMutex.RUnlock()
+	argsForCall := fake.modifyArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) ModifyReturns(result1 config.Waiter, result2 error) {
+	fake.modifyMutex.Lock()
+	defer fake.modifyMutex.Unlock()
+	fake.ModifyStub = nil
+	fake.modifyReturns = struct {
+		result1 config.Waiter
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Wrapper) ModifyReturnsOnCall(i int, result1 config.Waiter, result2 error) {
+	fake.modifyMutex.Lock()
+	defer fake.modifyMutex.Unlock()
+	fake.ModifyStub = nil
+	if fake.modifyReturnsOnCall == nil {
+		fake.modifyReturnsOnCall = make(map[int]struct {
+			result1 config.Waiter
+			result2 error
+		})
+	}
+	fake.modifyReturnsOnCall[i] = struct {
+		result1 config.Waiter
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Wrapper) MyID() protocol.DeviceID {
+	fake.myIDMutex.Lock()
+	ret, specificReturn := fake.myIDReturnsOnCall[len(fake.myIDArgsForCall)]
+	fake.myIDArgsForCall = append(fake.myIDArgsForCall, struct {
+	}{})
+	stub := fake.MyIDStub
+	fakeReturns := fake.myIDReturns
+	fake.recordInvocation("MyID", []interface{}{})
+	fake.myIDMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) MyIDCallCount() int {
+	fake.myIDMutex.RLock()
+	defer fake.myIDMutex.RUnlock()
+	return len(fake.myIDArgsForCall)
+}
+
+func (fake *Wrapper) MyIDCalls(stub func() protocol.DeviceID) {
+	fake.myIDMutex.Lock()
+	defer fake.myIDMutex.Unlock()
+	fake.MyIDStub = stub
+}
+
+func (fake *Wrapper) MyIDReturns(result1 protocol.DeviceID) {
+	fake.myIDMutex.Lock()
+	defer fake.myIDMutex.Unlock()
+	fake.MyIDStub = nil
+	fake.myIDReturns = struct {
+		result1 protocol.DeviceID
+	}{result1}
+}
+
+func (fake *Wrapper) MyIDReturnsOnCall(i int, result1 protocol.DeviceID) {
+	fake.myIDMutex.Lock()
+	defer fake.myIDMutex.Unlock()
+	fake.MyIDStub = nil
+	if fake.myIDReturnsOnCall == nil {
+		fake.myIDReturnsOnCall = make(map[int]struct {
+			result1 protocol.DeviceID
+		})
+	}
+	fake.myIDReturnsOnCall[i] = struct {
+		result1 protocol.DeviceID
+	}{result1}
+}
+
+func (fake *Wrapper) Options() config.OptionsConfiguration {
+	fake.optionsMutex.Lock()
+	ret, specificReturn := fake.optionsReturnsOnCall[len(fake.optionsArgsForCall)]
+	fake.optionsArgsForCall = append(fake.optionsArgsForCall, struct {
+	}{})
+	stub := fake.OptionsStub
+	fakeReturns := fake.optionsReturns
+	fake.recordInvocation("Options", []interface{}{})
+	fake.optionsMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) OptionsCallCount() int {
+	fake.optionsMutex.RLock()
+	defer fake.optionsMutex.RUnlock()
+	return len(fake.optionsArgsForCall)
+}
+
+func (fake *Wrapper) OptionsCalls(stub func() config.OptionsConfiguration) {
+	fake.optionsMutex.Lock()
+	defer fake.optionsMutex.Unlock()
+	fake.OptionsStub = stub
+}
+
+func (fake *Wrapper) OptionsReturns(result1 config.OptionsConfiguration) {
+	fake.optionsMutex.Lock()
+	defer fake.optionsMutex.Unlock()
+	fake.OptionsStub = nil
+	fake.optionsReturns = struct {
+		result1 config.OptionsConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) OptionsReturnsOnCall(i int, result1 config.OptionsConfiguration) {
+	fake.optionsMutex.Lock()
+	defer fake.optionsMutex.Unlock()
+	fake.OptionsStub = nil
+	if fake.optionsReturnsOnCall == nil {
+		fake.optionsReturnsOnCall = make(map[int]struct {
+			result1 config.OptionsConfiguration
+		})
+	}
+	fake.optionsReturnsOnCall[i] = struct {
+		result1 config.OptionsConfiguration
+	}{result1}
+}
+
+func (fake *Wrapper) RawCopy() config.Configuration {
+	fake.rawCopyMutex.Lock()
+	ret, specificReturn := fake.rawCopyReturnsOnCall[len(fake.rawCopyArgsForCall)]
+	fake.rawCopyArgsForCall = append(fake.rawCopyArgsForCall, struct {
+	}{})
+	stub := fake.RawCopyStub
+	fakeReturns := fake.rawCopyReturns
+	fake.recordInvocation("RawCopy", []interface{}{})
+	fake.rawCopyMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) RawCopyCallCount() int {
+	fake.rawCopyMutex.RLock()
+	defer fake.rawCopyMutex.RUnlock()
+	return len(fake.rawCopyArgsForCall)
+}
+
+func (fake *Wrapper) RawCopyCalls(stub func() config.Configuration) {
+	fake.rawCopyMutex.Lock()
+	defer fake.rawCopyMutex.Unlock()
+	fake.RawCopyStub = stub
+}
+
+func (fake *Wrapper) RawCopyReturns(result1 config.Configuration) {
+	fake.rawCopyMutex.Lock()
+	defer fake.rawCopyMutex.Unlock()
+	fake.RawCopyStub = nil
+	fake.rawCopyReturns = struct {
+		result1 config.Configuration
+	}{result1}
+}
+
+func (fake *Wrapper) RawCopyReturnsOnCall(i int, result1 config.Configuration) {
+	fake.rawCopyMutex.Lock()
+	defer fake.rawCopyMutex.Unlock()
+	fake.RawCopyStub = nil
+	if fake.rawCopyReturnsOnCall == nil {
+		fake.rawCopyReturnsOnCall = make(map[int]struct {
+			result1 config.Configuration
+		})
+	}
+	fake.rawCopyReturnsOnCall[i] = struct {
+		result1 config.Configuration
+	}{result1}
+}
+
+func (fake *Wrapper) RemoveDevice(arg1 protocol.DeviceID) (config.Waiter, error) {
+	fake.removeDeviceMutex.Lock()
+	ret, specificReturn := fake.removeDeviceReturnsOnCall[len(fake.removeDeviceArgsForCall)]
+	fake.removeDeviceArgsForCall = append(fake.removeDeviceArgsForCall, struct {
+		arg1 protocol.DeviceID
+	}{arg1})
+	stub := fake.RemoveDeviceStub
+	fakeReturns := fake.removeDeviceReturns
+	fake.recordInvocation("RemoveDevice", []interface{}{arg1})
+	fake.removeDeviceMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Wrapper) RemoveDeviceCallCount() int {
+	fake.removeDeviceMutex.RLock()
+	defer fake.removeDeviceMutex.RUnlock()
+	return len(fake.removeDeviceArgsForCall)
+}
+
+func (fake *Wrapper) RemoveDeviceCalls(stub func(protocol.DeviceID) (config.Waiter, error)) {
+	fake.removeDeviceMutex.Lock()
+	defer fake.removeDeviceMutex.Unlock()
+	fake.RemoveDeviceStub = stub
+}
+
+func (fake *Wrapper) RemoveDeviceArgsForCall(i int) protocol.DeviceID {
+	fake.removeDeviceMutex.RLock()
+	defer fake.removeDeviceMutex.RUnlock()
+	argsForCall := fake.removeDeviceArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) RemoveDeviceReturns(result1 config.Waiter, result2 error) {
+	fake.removeDeviceMutex.Lock()
+	defer fake.removeDeviceMutex.Unlock()
+	fake.RemoveDeviceStub = nil
+	fake.removeDeviceReturns = struct {
+		result1 config.Waiter
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Wrapper) RemoveDeviceReturnsOnCall(i int, result1 config.Waiter, result2 error) {
+	fake.removeDeviceMutex.Lock()
+	defer fake.removeDeviceMutex.Unlock()
+	fake.RemoveDeviceStub = nil
+	if fake.removeDeviceReturnsOnCall == nil {
+		fake.removeDeviceReturnsOnCall = make(map[int]struct {
+			result1 config.Waiter
+			result2 error
+		})
+	}
+	fake.removeDeviceReturnsOnCall[i] = struct {
+		result1 config.Waiter
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Wrapper) RemoveFolder(arg1 string) (config.Waiter, error) {
+	fake.removeFolderMutex.Lock()
+	ret, specificReturn := fake.removeFolderReturnsOnCall[len(fake.removeFolderArgsForCall)]
+	fake.removeFolderArgsForCall = append(fake.removeFolderArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.RemoveFolderStub
+	fakeReturns := fake.removeFolderReturns
+	fake.recordInvocation("RemoveFolder", []interface{}{arg1})
+	fake.removeFolderMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Wrapper) RemoveFolderCallCount() int {
+	fake.removeFolderMutex.RLock()
+	defer fake.removeFolderMutex.RUnlock()
+	return len(fake.removeFolderArgsForCall)
+}
+
+func (fake *Wrapper) RemoveFolderCalls(stub func(string) (config.Waiter, error)) {
+	fake.removeFolderMutex.Lock()
+	defer fake.removeFolderMutex.Unlock()
+	fake.RemoveFolderStub = stub
+}
+
+func (fake *Wrapper) RemoveFolderArgsForCall(i int) string {
+	fake.removeFolderMutex.RLock()
+	defer fake.removeFolderMutex.RUnlock()
+	argsForCall := fake.removeFolderArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) RemoveFolderReturns(result1 config.Waiter, result2 error) {
+	fake.removeFolderMutex.Lock()
+	defer fake.removeFolderMutex.Unlock()
+	fake.RemoveFolderStub = nil
+	fake.removeFolderReturns = struct {
+		result1 config.Waiter
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Wrapper) RemoveFolderReturnsOnCall(i int, result1 config.Waiter, result2 error) {
+	fake.removeFolderMutex.Lock()
+	defer fake.removeFolderMutex.Unlock()
+	fake.RemoveFolderStub = nil
+	if fake.removeFolderReturnsOnCall == nil {
+		fake.removeFolderReturnsOnCall = make(map[int]struct {
+			result1 config.Waiter
+			result2 error
+		})
+	}
+	fake.removeFolderReturnsOnCall[i] = struct {
+		result1 config.Waiter
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Wrapper) RequiresRestart() bool {
+	fake.requiresRestartMutex.Lock()
+	ret, specificReturn := fake.requiresRestartReturnsOnCall[len(fake.requiresRestartArgsForCall)]
+	fake.requiresRestartArgsForCall = append(fake.requiresRestartArgsForCall, struct {
+	}{})
+	stub := fake.RequiresRestartStub
+	fakeReturns := fake.requiresRestartReturns
+	fake.recordInvocation("RequiresRestart", []interface{}{})
+	fake.requiresRestartMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) RequiresRestartCallCount() int {
+	fake.requiresRestartMutex.RLock()
+	defer fake.requiresRestartMutex.RUnlock()
+	return len(fake.requiresRestartArgsForCall)
+}
+
+func (fake *Wrapper) RequiresRestartCalls(stub func() bool) {
+	fake.requiresRestartMutex.Lock()
+	defer fake.requiresRestartMutex.Unlock()
+	fake.RequiresRestartStub = stub
+}
+
+func (fake *Wrapper) RequiresRestartReturns(result1 bool) {
+	fake.requiresRestartMutex.Lock()
+	defer fake.requiresRestartMutex.Unlock()
+	fake.RequiresRestartStub = nil
+	fake.requiresRestartReturns = struct {
+		result1 bool
+	}{result1}
+}
+
+func (fake *Wrapper) RequiresRestartReturnsOnCall(i int, result1 bool) {
+	fake.requiresRestartMutex.Lock()
+	defer fake.requiresRestartMutex.Unlock()
+	fake.RequiresRestartStub = nil
+	if fake.requiresRestartReturnsOnCall == nil {
+		fake.requiresRestartReturnsOnCall = make(map[int]struct {
+			result1 bool
+		})
+	}
+	fake.requiresRestartReturnsOnCall[i] = struct {
+		result1 bool
+	}{result1}
+}
+
+func (fake *Wrapper) Save() error {
+	fake.saveMutex.Lock()
+	ret, specificReturn := fake.saveReturnsOnCall[len(fake.saveArgsForCall)]
+	fake.saveArgsForCall = append(fake.saveArgsForCall, struct {
+	}{})
+	stub := fake.SaveStub
+	fakeReturns := fake.saveReturns
+	fake.recordInvocation("Save", []interface{}{})
+	fake.saveMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) SaveCallCount() int {
+	fake.saveMutex.RLock()
+	defer fake.saveMutex.RUnlock()
+	return len(fake.saveArgsForCall)
+}
+
+func (fake *Wrapper) SaveCalls(stub func() error) {
+	fake.saveMutex.Lock()
+	defer fake.saveMutex.Unlock()
+	fake.SaveStub = stub
+}
+
+func (fake *Wrapper) SaveReturns(result1 error) {
+	fake.saveMutex.Lock()
+	defer fake.saveMutex.Unlock()
+	fake.SaveStub = nil
+	fake.saveReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Wrapper) SaveReturnsOnCall(i int, result1 error) {
+	fake.saveMutex.Lock()
+	defer fake.saveMutex.Unlock()
+	fake.SaveStub = nil
+	if fake.saveReturnsOnCall == nil {
+		fake.saveReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.saveReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Wrapper) Subscribe(arg1 config.Committer) config.Configuration {
+	fake.subscribeMutex.Lock()
+	ret, specificReturn := fake.subscribeReturnsOnCall[len(fake.subscribeArgsForCall)]
+	fake.subscribeArgsForCall = append(fake.subscribeArgsForCall, struct {
+		arg1 config.Committer
+	}{arg1})
+	stub := fake.SubscribeStub
+	fakeReturns := fake.subscribeReturns
+	fake.recordInvocation("Subscribe", []interface{}{arg1})
+	fake.subscribeMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Wrapper) SubscribeCallCount() int {
+	fake.subscribeMutex.RLock()
+	defer fake.subscribeMutex.RUnlock()
+	return len(fake.subscribeArgsForCall)
+}
+
+func (fake *Wrapper) SubscribeCalls(stub func(config.Committer) config.Configuration) {
+	fake.subscribeMutex.Lock()
+	defer fake.subscribeMutex.Unlock()
+	fake.SubscribeStub = stub
+}
+
+func (fake *Wrapper) SubscribeArgsForCall(i int) config.Committer {
+	fake.subscribeMutex.RLock()
+	defer fake.subscribeMutex.RUnlock()
+	argsForCall := fake.subscribeArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) SubscribeReturns(result1 config.Configuration) {
+	fake.subscribeMutex.Lock()
+	defer fake.subscribeMutex.Unlock()
+	fake.SubscribeStub = nil
+	fake.subscribeReturns = struct {
+		result1 config.Configuration
+	}{result1}
+}
+
+func (fake *Wrapper) SubscribeReturnsOnCall(i int, result1 config.Configuration) {
+	fake.subscribeMutex.Lock()
+	defer fake.subscribeMutex.Unlock()
+	fake.SubscribeStub = nil
+	if fake.subscribeReturnsOnCall == nil {
+		fake.subscribeReturnsOnCall = make(map[int]struct {
+			result1 config.Configuration
+		})
+	}
+	fake.subscribeReturnsOnCall[i] = struct {
+		result1 config.Configuration
+	}{result1}
+}
+
+func (fake *Wrapper) Unsubscribe(arg1 config.Committer) {
+	fake.unsubscribeMutex.Lock()
+	fake.unsubscribeArgsForCall = append(fake.unsubscribeArgsForCall, struct {
+		arg1 config.Committer
+	}{arg1})
+	stub := fake.UnsubscribeStub
+	fake.recordInvocation("Unsubscribe", []interface{}{arg1})
+	fake.unsubscribeMutex.Unlock()
+	if stub != nil {
+		fake.UnsubscribeStub(arg1)
+	}
+}
+
+func (fake *Wrapper) UnsubscribeCallCount() int {
+	fake.unsubscribeMutex.RLock()
+	defer fake.unsubscribeMutex.RUnlock()
+	return len(fake.unsubscribeArgsForCall)
+}
+
+func (fake *Wrapper) UnsubscribeCalls(stub func(config.Committer)) {
+	fake.unsubscribeMutex.Lock()
+	defer fake.unsubscribeMutex.Unlock()
+	fake.UnsubscribeStub = stub
+}
+
+func (fake *Wrapper) UnsubscribeArgsForCall(i int) config.Committer {
+	fake.unsubscribeMutex.RLock()
+	defer fake.unsubscribeMutex.RUnlock()
+	argsForCall := fake.unsubscribeArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Wrapper) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.configPathMutex.RLock()
+	defer fake.configPathMutex.RUnlock()
+	fake.defaultDeviceMutex.RLock()
+	defer fake.defaultDeviceMutex.RUnlock()
+	fake.defaultFolderMutex.RLock()
+	defer fake.defaultFolderMutex.RUnlock()
+	fake.deviceMutex.RLock()
+	defer fake.deviceMutex.RUnlock()
+	fake.deviceListMutex.RLock()
+	defer fake.deviceListMutex.RUnlock()
+	fake.devicesMutex.RLock()
+	defer fake.devicesMutex.RUnlock()
+	fake.folderMutex.RLock()
+	defer fake.folderMutex.RUnlock()
+	fake.folderListMutex.RLock()
+	defer fake.folderListMutex.RUnlock()
+	fake.folderPasswordsMutex.RLock()
+	defer fake.folderPasswordsMutex.RUnlock()
+	fake.foldersMutex.RLock()
+	defer fake.foldersMutex.RUnlock()
+	fake.gUIMutex.RLock()
+	defer fake.gUIMutex.RUnlock()
+	fake.ignoredDeviceMutex.RLock()
+	defer fake.ignoredDeviceMutex.RUnlock()
+	fake.ignoredDevicesMutex.RLock()
+	defer fake.ignoredDevicesMutex.RUnlock()
+	fake.ignoredFolderMutex.RLock()
+	defer fake.ignoredFolderMutex.RUnlock()
+	fake.lDAPMutex.RLock()
+	defer fake.lDAPMutex.RUnlock()
+	fake.modifyMutex.RLock()
+	defer fake.modifyMutex.RUnlock()
+	fake.myIDMutex.RLock()
+	defer fake.myIDMutex.RUnlock()
+	fake.optionsMutex.RLock()
+	defer fake.optionsMutex.RUnlock()
+	fake.rawCopyMutex.RLock()
+	defer fake.rawCopyMutex.RUnlock()
+	fake.removeDeviceMutex.RLock()
+	defer fake.removeDeviceMutex.RUnlock()
+	fake.removeFolderMutex.RLock()
+	defer fake.removeFolderMutex.RUnlock()
+	fake.requiresRestartMutex.RLock()
+	defer fake.requiresRestartMutex.RUnlock()
+	fake.saveMutex.RLock()
+	defer fake.saveMutex.RUnlock()
+	fake.subscribeMutex.RLock()
+	defer fake.subscribeMutex.RUnlock()
+	fake.unsubscribeMutex.RLock()
+	defer fake.unsubscribeMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *Wrapper) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ config.Wrapper = new(Wrapper)

+ 2 - 0
lib/config/wrapper.go

@@ -4,6 +4,8 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // You can obtain one at https://mozilla.org/MPL/2.0/.
 
+//go:generate counterfeiter -o mocks/mocked_wrapper.go --fake-name Wrapper . Wrapper
+
 package config
 
 import (

+ 437 - 0
lib/connections/mocks/service.go

@@ -0,0 +1,437 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"context"
+	"sync"
+
+	"github.com/syncthing/syncthing/lib/connections"
+)
+
+type Service struct {
+	AllAddressesStub        func() []string
+	allAddressesMutex       sync.RWMutex
+	allAddressesArgsForCall []struct {
+	}
+	allAddressesReturns struct {
+		result1 []string
+	}
+	allAddressesReturnsOnCall map[int]struct {
+		result1 []string
+	}
+	ConnectionStatusStub        func() map[string]connections.ConnectionStatusEntry
+	connectionStatusMutex       sync.RWMutex
+	connectionStatusArgsForCall []struct {
+	}
+	connectionStatusReturns struct {
+		result1 map[string]connections.ConnectionStatusEntry
+	}
+	connectionStatusReturnsOnCall map[int]struct {
+		result1 map[string]connections.ConnectionStatusEntry
+	}
+	ExternalAddressesStub        func() []string
+	externalAddressesMutex       sync.RWMutex
+	externalAddressesArgsForCall []struct {
+	}
+	externalAddressesReturns struct {
+		result1 []string
+	}
+	externalAddressesReturnsOnCall map[int]struct {
+		result1 []string
+	}
+	ListenerStatusStub        func() map[string]connections.ListenerStatusEntry
+	listenerStatusMutex       sync.RWMutex
+	listenerStatusArgsForCall []struct {
+	}
+	listenerStatusReturns struct {
+		result1 map[string]connections.ListenerStatusEntry
+	}
+	listenerStatusReturnsOnCall map[int]struct {
+		result1 map[string]connections.ListenerStatusEntry
+	}
+	NATTypeStub        func() string
+	nATTypeMutex       sync.RWMutex
+	nATTypeArgsForCall []struct {
+	}
+	nATTypeReturns struct {
+		result1 string
+	}
+	nATTypeReturnsOnCall map[int]struct {
+		result1 string
+	}
+	ServeStub        func(context.Context) error
+	serveMutex       sync.RWMutex
+	serveArgsForCall []struct {
+		arg1 context.Context
+	}
+	serveReturns struct {
+		result1 error
+	}
+	serveReturnsOnCall map[int]struct {
+		result1 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *Service) AllAddresses() []string {
+	fake.allAddressesMutex.Lock()
+	ret, specificReturn := fake.allAddressesReturnsOnCall[len(fake.allAddressesArgsForCall)]
+	fake.allAddressesArgsForCall = append(fake.allAddressesArgsForCall, struct {
+	}{})
+	stub := fake.AllAddressesStub
+	fakeReturns := fake.allAddressesReturns
+	fake.recordInvocation("AllAddresses", []interface{}{})
+	fake.allAddressesMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Service) AllAddressesCallCount() int {
+	fake.allAddressesMutex.RLock()
+	defer fake.allAddressesMutex.RUnlock()
+	return len(fake.allAddressesArgsForCall)
+}
+
+func (fake *Service) AllAddressesCalls(stub func() []string) {
+	fake.allAddressesMutex.Lock()
+	defer fake.allAddressesMutex.Unlock()
+	fake.AllAddressesStub = stub
+}
+
+func (fake *Service) AllAddressesReturns(result1 []string) {
+	fake.allAddressesMutex.Lock()
+	defer fake.allAddressesMutex.Unlock()
+	fake.AllAddressesStub = nil
+	fake.allAddressesReturns = struct {
+		result1 []string
+	}{result1}
+}
+
+func (fake *Service) AllAddressesReturnsOnCall(i int, result1 []string) {
+	fake.allAddressesMutex.Lock()
+	defer fake.allAddressesMutex.Unlock()
+	fake.AllAddressesStub = nil
+	if fake.allAddressesReturnsOnCall == nil {
+		fake.allAddressesReturnsOnCall = make(map[int]struct {
+			result1 []string
+		})
+	}
+	fake.allAddressesReturnsOnCall[i] = struct {
+		result1 []string
+	}{result1}
+}
+
+func (fake *Service) ConnectionStatus() map[string]connections.ConnectionStatusEntry {
+	fake.connectionStatusMutex.Lock()
+	ret, specificReturn := fake.connectionStatusReturnsOnCall[len(fake.connectionStatusArgsForCall)]
+	fake.connectionStatusArgsForCall = append(fake.connectionStatusArgsForCall, struct {
+	}{})
+	stub := fake.ConnectionStatusStub
+	fakeReturns := fake.connectionStatusReturns
+	fake.recordInvocation("ConnectionStatus", []interface{}{})
+	fake.connectionStatusMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Service) ConnectionStatusCallCount() int {
+	fake.connectionStatusMutex.RLock()
+	defer fake.connectionStatusMutex.RUnlock()
+	return len(fake.connectionStatusArgsForCall)
+}
+
+func (fake *Service) ConnectionStatusCalls(stub func() map[string]connections.ConnectionStatusEntry) {
+	fake.connectionStatusMutex.Lock()
+	defer fake.connectionStatusMutex.Unlock()
+	fake.ConnectionStatusStub = stub
+}
+
+func (fake *Service) ConnectionStatusReturns(result1 map[string]connections.ConnectionStatusEntry) {
+	fake.connectionStatusMutex.Lock()
+	defer fake.connectionStatusMutex.Unlock()
+	fake.ConnectionStatusStub = nil
+	fake.connectionStatusReturns = struct {
+		result1 map[string]connections.ConnectionStatusEntry
+	}{result1}
+}
+
+func (fake *Service) ConnectionStatusReturnsOnCall(i int, result1 map[string]connections.ConnectionStatusEntry) {
+	fake.connectionStatusMutex.Lock()
+	defer fake.connectionStatusMutex.Unlock()
+	fake.ConnectionStatusStub = nil
+	if fake.connectionStatusReturnsOnCall == nil {
+		fake.connectionStatusReturnsOnCall = make(map[int]struct {
+			result1 map[string]connections.ConnectionStatusEntry
+		})
+	}
+	fake.connectionStatusReturnsOnCall[i] = struct {
+		result1 map[string]connections.ConnectionStatusEntry
+	}{result1}
+}
+
+func (fake *Service) ExternalAddresses() []string {
+	fake.externalAddressesMutex.Lock()
+	ret, specificReturn := fake.externalAddressesReturnsOnCall[len(fake.externalAddressesArgsForCall)]
+	fake.externalAddressesArgsForCall = append(fake.externalAddressesArgsForCall, struct {
+	}{})
+	stub := fake.ExternalAddressesStub
+	fakeReturns := fake.externalAddressesReturns
+	fake.recordInvocation("ExternalAddresses", []interface{}{})
+	fake.externalAddressesMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Service) ExternalAddressesCallCount() int {
+	fake.externalAddressesMutex.RLock()
+	defer fake.externalAddressesMutex.RUnlock()
+	return len(fake.externalAddressesArgsForCall)
+}
+
+func (fake *Service) ExternalAddressesCalls(stub func() []string) {
+	fake.externalAddressesMutex.Lock()
+	defer fake.externalAddressesMutex.Unlock()
+	fake.ExternalAddressesStub = stub
+}
+
+func (fake *Service) ExternalAddressesReturns(result1 []string) {
+	fake.externalAddressesMutex.Lock()
+	defer fake.externalAddressesMutex.Unlock()
+	fake.ExternalAddressesStub = nil
+	fake.externalAddressesReturns = struct {
+		result1 []string
+	}{result1}
+}
+
+func (fake *Service) ExternalAddressesReturnsOnCall(i int, result1 []string) {
+	fake.externalAddressesMutex.Lock()
+	defer fake.externalAddressesMutex.Unlock()
+	fake.ExternalAddressesStub = nil
+	if fake.externalAddressesReturnsOnCall == nil {
+		fake.externalAddressesReturnsOnCall = make(map[int]struct {
+			result1 []string
+		})
+	}
+	fake.externalAddressesReturnsOnCall[i] = struct {
+		result1 []string
+	}{result1}
+}
+
+func (fake *Service) ListenerStatus() map[string]connections.ListenerStatusEntry {
+	fake.listenerStatusMutex.Lock()
+	ret, specificReturn := fake.listenerStatusReturnsOnCall[len(fake.listenerStatusArgsForCall)]
+	fake.listenerStatusArgsForCall = append(fake.listenerStatusArgsForCall, struct {
+	}{})
+	stub := fake.ListenerStatusStub
+	fakeReturns := fake.listenerStatusReturns
+	fake.recordInvocation("ListenerStatus", []interface{}{})
+	fake.listenerStatusMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Service) ListenerStatusCallCount() int {
+	fake.listenerStatusMutex.RLock()
+	defer fake.listenerStatusMutex.RUnlock()
+	return len(fake.listenerStatusArgsForCall)
+}
+
+func (fake *Service) ListenerStatusCalls(stub func() map[string]connections.ListenerStatusEntry) {
+	fake.listenerStatusMutex.Lock()
+	defer fake.listenerStatusMutex.Unlock()
+	fake.ListenerStatusStub = stub
+}
+
+func (fake *Service) ListenerStatusReturns(result1 map[string]connections.ListenerStatusEntry) {
+	fake.listenerStatusMutex.Lock()
+	defer fake.listenerStatusMutex.Unlock()
+	fake.ListenerStatusStub = nil
+	fake.listenerStatusReturns = struct {
+		result1 map[string]connections.ListenerStatusEntry
+	}{result1}
+}
+
+func (fake *Service) ListenerStatusReturnsOnCall(i int, result1 map[string]connections.ListenerStatusEntry) {
+	fake.listenerStatusMutex.Lock()
+	defer fake.listenerStatusMutex.Unlock()
+	fake.ListenerStatusStub = nil
+	if fake.listenerStatusReturnsOnCall == nil {
+		fake.listenerStatusReturnsOnCall = make(map[int]struct {
+			result1 map[string]connections.ListenerStatusEntry
+		})
+	}
+	fake.listenerStatusReturnsOnCall[i] = struct {
+		result1 map[string]connections.ListenerStatusEntry
+	}{result1}
+}
+
+func (fake *Service) NATType() string {
+	fake.nATTypeMutex.Lock()
+	ret, specificReturn := fake.nATTypeReturnsOnCall[len(fake.nATTypeArgsForCall)]
+	fake.nATTypeArgsForCall = append(fake.nATTypeArgsForCall, struct {
+	}{})
+	stub := fake.NATTypeStub
+	fakeReturns := fake.nATTypeReturns
+	fake.recordInvocation("NATType", []interface{}{})
+	fake.nATTypeMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Service) NATTypeCallCount() int {
+	fake.nATTypeMutex.RLock()
+	defer fake.nATTypeMutex.RUnlock()
+	return len(fake.nATTypeArgsForCall)
+}
+
+func (fake *Service) NATTypeCalls(stub func() string) {
+	fake.nATTypeMutex.Lock()
+	defer fake.nATTypeMutex.Unlock()
+	fake.NATTypeStub = stub
+}
+
+func (fake *Service) NATTypeReturns(result1 string) {
+	fake.nATTypeMutex.Lock()
+	defer fake.nATTypeMutex.Unlock()
+	fake.NATTypeStub = nil
+	fake.nATTypeReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Service) NATTypeReturnsOnCall(i int, result1 string) {
+	fake.nATTypeMutex.Lock()
+	defer fake.nATTypeMutex.Unlock()
+	fake.NATTypeStub = nil
+	if fake.nATTypeReturnsOnCall == nil {
+		fake.nATTypeReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.nATTypeReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Service) Serve(arg1 context.Context) error {
+	fake.serveMutex.Lock()
+	ret, specificReturn := fake.serveReturnsOnCall[len(fake.serveArgsForCall)]
+	fake.serveArgsForCall = append(fake.serveArgsForCall, struct {
+		arg1 context.Context
+	}{arg1})
+	stub := fake.ServeStub
+	fakeReturns := fake.serveReturns
+	fake.recordInvocation("Serve", []interface{}{arg1})
+	fake.serveMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Service) ServeCallCount() int {
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	return len(fake.serveArgsForCall)
+}
+
+func (fake *Service) ServeCalls(stub func(context.Context) error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = stub
+}
+
+func (fake *Service) ServeArgsForCall(i int) context.Context {
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	argsForCall := fake.serveArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Service) ServeReturns(result1 error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = nil
+	fake.serveReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Service) ServeReturnsOnCall(i int, result1 error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = nil
+	if fake.serveReturnsOnCall == nil {
+		fake.serveReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.serveReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Service) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.allAddressesMutex.RLock()
+	defer fake.allAddressesMutex.RUnlock()
+	fake.connectionStatusMutex.RLock()
+	defer fake.connectionStatusMutex.RUnlock()
+	fake.externalAddressesMutex.RLock()
+	defer fake.externalAddressesMutex.RUnlock()
+	fake.listenerStatusMutex.RLock()
+	defer fake.listenerStatusMutex.RUnlock()
+	fake.nATTypeMutex.RLock()
+	defer fake.nATTypeMutex.RUnlock()
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *Service) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ connections.Service = new(Service)

+ 2 - 0
lib/connections/service.go

@@ -4,6 +4,8 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // You can obtain one at https://mozilla.org/MPL/2.0/.
 
+//go:generate counterfeiter -o mocks/service.go --fake-name Service . Service
+
 package connections
 
 import (

+ 0 - 3
lib/discover/local.go

@@ -4,9 +4,6 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // You can obtain one at https://mozilla.org/MPL/2.0/.
 
-//go:generate go run ../../proto/scripts/protofmt.go local.proto
-//go:generate protoc -I ../../ -I . --gogofast_out=. local.proto
-
 package discover
 
 import (

+ 30 - 24
lib/discover/local.pb.go

@@ -1,5 +1,5 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
-// source: local.proto
+// source: lib/discover/local.proto
 
 package discover
 
@@ -8,6 +8,7 @@ import (
 	_ "github.com/gogo/protobuf/gogoproto"
 	proto "github.com/gogo/protobuf/proto"
 	github_com_syncthing_syncthing_lib_protocol "github.com/syncthing/syncthing/lib/protocol"
+	_ "github.com/syncthing/syncthing/proto/ext"
 	io "io"
 	math "math"
 	math_bits "math/bits"
@@ -25,16 +26,16 @@ var _ = math.Inf
 const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 
 type Announce struct {
-	ID         github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,1,opt,name=id,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"id"`
-	Addresses  []string                                             `protobuf:"bytes,2,rep,name=addresses,proto3" json:"addresses,omitempty"`
-	InstanceID int64                                                `protobuf:"varint,3,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"`
+	ID         github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,1,opt,name=id,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"id" xml:"id"`
+	Addresses  []string                                             `protobuf:"bytes,2,rep,name=addresses,proto3" json:"addresses" xml:"address"`
+	InstanceID int64                                                `protobuf:"varint,3,opt,name=instance_id,json=instanceId,proto3" json:"instanceId" xml:"instanceId"`
 }
 
 func (m *Announce) Reset()         { *m = Announce{} }
 func (m *Announce) String() string { return proto.CompactTextString(m) }
 func (*Announce) ProtoMessage()    {}
 func (*Announce) Descriptor() ([]byte, []int) {
-	return fileDescriptor_aaf1a48d01603033, []int{0}
+	return fileDescriptor_18afca46562fdaf4, []int{0}
 }
 func (m *Announce) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -67,26 +68,31 @@ func init() {
 	proto.RegisterType((*Announce)(nil), "discover.Announce")
 }
 
-func init() { proto.RegisterFile("local.proto", fileDescriptor_aaf1a48d01603033) }
+func init() { proto.RegisterFile("lib/discover/local.proto", fileDescriptor_18afca46562fdaf4) }
 
-var fileDescriptor_aaf1a48d01603033 = []byte{
-	// 252 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x8e, 0x31, 0x4e, 0x84, 0x40,
-	0x14, 0x86, 0x67, 0x20, 0x31, 0xbb, 0xb3, 0xc6, 0x82, 0x8a, 0x18, 0x33, 0x10, 0x6d, 0xa8, 0xa0,
-	0xd0, 0x0b, 0x48, 0x68, 0xa6, 0xe5, 0x02, 0x06, 0x66, 0x46, 0xf6, 0x25, 0x38, 0x6f, 0xc3, 0xc0,
-	0x26, 0xde, 0xc2, 0x23, 0x78, 0x01, 0xef, 0x41, 0xb9, 0xa5, 0xb1, 0x20, 0x3a, 0x5c, 0xc4, 0x04,
-	0x34, 0xda, 0x7d, 0xef, 0xcb, 0x97, 0xbc, 0x9f, 0xed, 0x5a, 0x94, 0x55, 0x9b, 0x1e, 0x3a, 0xec,
-	0x31, 0xd8, 0x28, 0xb0, 0x12, 0x8f, 0xba, 0xbb, 0xbc, 0xe9, 0xf4, 0x01, 0x6d, 0xb6, 0xe8, 0x7a,
-	0x78, 0xcc, 0x1a, 0x6c, 0x70, 0x39, 0x16, 0x5a, 0xf3, 0xeb, 0x37, 0xca, 0x36, 0xf7, 0xc6, 0xe0,
-	0x60, 0xa4, 0x0e, 0x4a, 0xe6, 0x81, 0x0a, 0x69, 0x4c, 0x93, 0xf3, 0x3c, 0x1f, 0xa7, 0x88, 0x7c,
-	0x4c, 0xd1, 0x5d, 0x03, 0xfd, 0x7e, 0xa8, 0x53, 0x89, 0x4f, 0x99, 0x7d, 0x36, 0xb2, 0xdf, 0x83,
-	0x69, 0xfe, 0x51, 0x0b, 0xf5, 0xfa, 0x42, 0x62, 0x9b, 0x16, 0xfa, 0x08, 0x52, 0x8b, 0xc2, 0x4d,
-	0x91, 0x27, 0x8a, 0xd2, 0x03, 0x15, 0x5c, 0xb1, 0x6d, 0xa5, 0x54, 0xa7, 0xad, 0xd5, 0x36, 0xf4,
-	0x62, 0x3f, 0xd9, 0x96, 0x7f, 0x22, 0xc8, 0xd8, 0x0e, 0x8c, 0xed, 0x2b, 0x23, 0xf5, 0x03, 0xa8,
-	0xd0, 0x8f, 0x69, 0xe2, 0xe7, 0x17, 0x6e, 0x8a, 0x98, 0xf8, 0xd1, 0xa2, 0x28, 0xd9, 0x6f, 0x22,
-	0x54, 0x1e, 0x8f, 0x5f, 0x9c, 0x8c, 0x8e, 0xd3, 0x93, 0xe3, 0xf4, 0xd3, 0x71, 0xf2, 0x32, 0x73,
-	0xf2, 0x3a, 0x73, 0x7a, 0x9a, 0x39, 0x79, 0x9f, 0x39, 0xa9, 0xcf, 0x96, 0x35, 0xb7, 0xdf, 0x01,
-	0x00, 0x00, 0xff, 0xff, 0xbc, 0x46, 0xaf, 0x1d, 0x16, 0x01, 0x00, 0x00,
+var fileDescriptor_18afca46562fdaf4 = []byte{
+	// 334 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x31, 0x6b, 0xe3, 0x30,
+	0x18, 0x86, 0x2d, 0x05, 0x8e, 0x44, 0x77, 0x07, 0x87, 0x27, 0x93, 0x41, 0x0a, 0xbe, 0x0c, 0x81,
+	0x42, 0x3c, 0xb4, 0x53, 0x29, 0x85, 0x1a, 0x2f, 0x1e, 0xba, 0x64, 0xec, 0xd0, 0x10, 0x4b, 0xaa,
+	0x23, 0x70, 0xa4, 0x60, 0x39, 0x21, 0xfd, 0x07, 0x1d, 0x4b, 0xb6, 0x6e, 0xfd, 0x39, 0x19, 0x3d,
+	0x96, 0x0e, 0x82, 0xd8, 0x5b, 0xc6, 0xfc, 0x82, 0x12, 0x25, 0x69, 0x32, 0x76, 0x7b, 0xf5, 0xe8,
+	0x95, 0x78, 0xf8, 0x3e, 0xe4, 0x65, 0x22, 0x09, 0x98, 0xd0, 0x54, 0xcd, 0x79, 0x1e, 0x64, 0x8a,
+	0x8e, 0xb2, 0xfe, 0x34, 0x57, 0x85, 0x72, 0x9b, 0x47, 0xda, 0xfe, 0x9f, 0xf3, 0xa9, 0xd2, 0x81,
+	0xc5, 0xc9, 0xec, 0x29, 0x48, 0x55, 0xaa, 0xec, 0xc1, 0xa6, 0x7d, 0xbd, 0xdd, 0xe2, 0x8b, 0x62,
+	0x1f, 0xfd, 0x37, 0x88, 0x9a, 0x77, 0x52, 0xaa, 0x99, 0xa4, 0xdc, 0x95, 0x08, 0x0a, 0xe6, 0x81,
+	0x0e, 0xe8, 0xfd, 0x09, 0x1f, 0x57, 0x86, 0x38, 0x9f, 0x86, 0x5c, 0xa5, 0xa2, 0x18, 0xcf, 0x92,
+	0x3e, 0x55, 0x93, 0x40, 0x3f, 0x4b, 0x5a, 0x8c, 0x85, 0x4c, 0xcf, 0xd2, 0xce, 0xc9, 0x7e, 0x45,
+	0x55, 0xd6, 0x8f, 0xf8, 0x5c, 0x50, 0x1e, 0x47, 0x95, 0x21, 0x30, 0x8e, 0x36, 0x86, 0x40, 0xc1,
+	0xb6, 0x86, 0x34, 0x17, 0x93, 0xec, 0xda, 0x17, 0xcc, 0x7f, 0x29, 0xbb, 0x60, 0x59, 0x76, 0x61,
+	0x1c, 0x0d, 0xa0, 0x60, 0xee, 0x0d, 0x6a, 0x8d, 0x18, 0xcb, 0xb9, 0xd6, 0x5c, 0x7b, 0xb0, 0xd3,
+	0xe8, 0xb5, 0x42, 0xbc, 0x31, 0xe4, 0x04, 0xb7, 0x86, 0xfc, 0xb5, 0x6f, 0x0f, 0xc4, 0x1f, 0x9c,
+	0xee, 0xdc, 0x21, 0xfa, 0x2d, 0xa4, 0x2e, 0x46, 0x92, 0xf2, 0xa1, 0x60, 0x5e, 0xa3, 0x03, 0x7a,
+	0x8d, 0xf0, 0xb6, 0x32, 0x04, 0xc5, 0x07, 0x6c, 0x15, 0xd0, 0xb1, 0x14, 0xef, 0x54, 0xfe, 0xed,
+	0x55, 0xbe, 0x91, 0xbf, 0x2c, 0xbb, 0x67, 0xfd, 0xc1, 0x59, 0x3b, 0xbc, 0x5f, 0xad, 0xb1, 0x53,
+	0xae, 0xb1, 0xb3, 0xaa, 0x30, 0x28, 0x2b, 0x0c, 0x5e, 0x6b, 0xec, 0xbc, 0xd7, 0x18, 0x94, 0x35,
+	0x76, 0x3e, 0x6a, 0xec, 0x3c, 0x5c, 0xfc, 0x60, 0x38, 0xc7, 0xd5, 0x24, 0xbf, 0xec, 0x98, 0x2e,
+	0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xe8, 0x9a, 0xd0, 0xc7, 0x01, 0x00, 0x00,
 }
 
 func (m *Announce) Marshal() (dAtA []byte, err error) {

+ 0 - 18
lib/discover/local.proto

@@ -1,18 +0,0 @@
-syntax = "proto3";
-
-package discover;
-
-import "repos/protobuf/gogoproto/gogo.proto";
-
-option (gogoproto.goproto_getters_all) = false;
-option (gogoproto.sizer_all) = false;
-option (gogoproto.protosizer_all) = true;
-option (gogoproto.goproto_unkeyed_all) = false;
-option (gogoproto.goproto_unrecognized_all) = false;
-option (gogoproto.goproto_sizecache_all) = false;
-
-message Announce {
-    bytes           id          = 1 [(gogoproto.customname) = "ID", (gogoproto.customtype) = "github.com/syncthing/syncthing/lib/protocol.DeviceID", (gogoproto.nullable) = false];
-    repeated string addresses   = 2;
-    int64           instance_id = 3 [(gogoproto.customname) = "InstanceID"];
-}

+ 2 - 0
lib/discover/manager.go

@@ -4,6 +4,8 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // You can obtain one at https://mozilla.org/MPL/2.0/.
 
+//go:generate counterfeiter -o mocks/manager.go --fake-name Manager . Manager
+
 package discover
 
 import (

+ 454 - 0
lib/discover/mocks/manager.go

@@ -0,0 +1,454 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"context"
+	"sync"
+
+	"github.com/syncthing/syncthing/lib/discover"
+	"github.com/syncthing/syncthing/lib/protocol"
+)
+
+type Manager struct {
+	CacheStub        func() map[protocol.DeviceID]discover.CacheEntry
+	cacheMutex       sync.RWMutex
+	cacheArgsForCall []struct {
+	}
+	cacheReturns struct {
+		result1 map[protocol.DeviceID]discover.CacheEntry
+	}
+	cacheReturnsOnCall map[int]struct {
+		result1 map[protocol.DeviceID]discover.CacheEntry
+	}
+	ChildErrorsStub        func() map[string]error
+	childErrorsMutex       sync.RWMutex
+	childErrorsArgsForCall []struct {
+	}
+	childErrorsReturns struct {
+		result1 map[string]error
+	}
+	childErrorsReturnsOnCall map[int]struct {
+		result1 map[string]error
+	}
+	ErrorStub        func() error
+	errorMutex       sync.RWMutex
+	errorArgsForCall []struct {
+	}
+	errorReturns struct {
+		result1 error
+	}
+	errorReturnsOnCall map[int]struct {
+		result1 error
+	}
+	LookupStub        func(context.Context, protocol.DeviceID) ([]string, error)
+	lookupMutex       sync.RWMutex
+	lookupArgsForCall []struct {
+		arg1 context.Context
+		arg2 protocol.DeviceID
+	}
+	lookupReturns struct {
+		result1 []string
+		result2 error
+	}
+	lookupReturnsOnCall map[int]struct {
+		result1 []string
+		result2 error
+	}
+	ServeStub        func(context.Context) error
+	serveMutex       sync.RWMutex
+	serveArgsForCall []struct {
+		arg1 context.Context
+	}
+	serveReturns struct {
+		result1 error
+	}
+	serveReturnsOnCall map[int]struct {
+		result1 error
+	}
+	StringStub        func() string
+	stringMutex       sync.RWMutex
+	stringArgsForCall []struct {
+	}
+	stringReturns struct {
+		result1 string
+	}
+	stringReturnsOnCall map[int]struct {
+		result1 string
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *Manager) Cache() map[protocol.DeviceID]discover.CacheEntry {
+	fake.cacheMutex.Lock()
+	ret, specificReturn := fake.cacheReturnsOnCall[len(fake.cacheArgsForCall)]
+	fake.cacheArgsForCall = append(fake.cacheArgsForCall, struct {
+	}{})
+	stub := fake.CacheStub
+	fakeReturns := fake.cacheReturns
+	fake.recordInvocation("Cache", []interface{}{})
+	fake.cacheMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) CacheCallCount() int {
+	fake.cacheMutex.RLock()
+	defer fake.cacheMutex.RUnlock()
+	return len(fake.cacheArgsForCall)
+}
+
+func (fake *Manager) CacheCalls(stub func() map[protocol.DeviceID]discover.CacheEntry) {
+	fake.cacheMutex.Lock()
+	defer fake.cacheMutex.Unlock()
+	fake.CacheStub = stub
+}
+
+func (fake *Manager) CacheReturns(result1 map[protocol.DeviceID]discover.CacheEntry) {
+	fake.cacheMutex.Lock()
+	defer fake.cacheMutex.Unlock()
+	fake.CacheStub = nil
+	fake.cacheReturns = struct {
+		result1 map[protocol.DeviceID]discover.CacheEntry
+	}{result1}
+}
+
+func (fake *Manager) CacheReturnsOnCall(i int, result1 map[protocol.DeviceID]discover.CacheEntry) {
+	fake.cacheMutex.Lock()
+	defer fake.cacheMutex.Unlock()
+	fake.CacheStub = nil
+	if fake.cacheReturnsOnCall == nil {
+		fake.cacheReturnsOnCall = make(map[int]struct {
+			result1 map[protocol.DeviceID]discover.CacheEntry
+		})
+	}
+	fake.cacheReturnsOnCall[i] = struct {
+		result1 map[protocol.DeviceID]discover.CacheEntry
+	}{result1}
+}
+
+func (fake *Manager) ChildErrors() map[string]error {
+	fake.childErrorsMutex.Lock()
+	ret, specificReturn := fake.childErrorsReturnsOnCall[len(fake.childErrorsArgsForCall)]
+	fake.childErrorsArgsForCall = append(fake.childErrorsArgsForCall, struct {
+	}{})
+	stub := fake.ChildErrorsStub
+	fakeReturns := fake.childErrorsReturns
+	fake.recordInvocation("ChildErrors", []interface{}{})
+	fake.childErrorsMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) ChildErrorsCallCount() int {
+	fake.childErrorsMutex.RLock()
+	defer fake.childErrorsMutex.RUnlock()
+	return len(fake.childErrorsArgsForCall)
+}
+
+func (fake *Manager) ChildErrorsCalls(stub func() map[string]error) {
+	fake.childErrorsMutex.Lock()
+	defer fake.childErrorsMutex.Unlock()
+	fake.ChildErrorsStub = stub
+}
+
+func (fake *Manager) ChildErrorsReturns(result1 map[string]error) {
+	fake.childErrorsMutex.Lock()
+	defer fake.childErrorsMutex.Unlock()
+	fake.ChildErrorsStub = nil
+	fake.childErrorsReturns = struct {
+		result1 map[string]error
+	}{result1}
+}
+
+func (fake *Manager) ChildErrorsReturnsOnCall(i int, result1 map[string]error) {
+	fake.childErrorsMutex.Lock()
+	defer fake.childErrorsMutex.Unlock()
+	fake.ChildErrorsStub = nil
+	if fake.childErrorsReturnsOnCall == nil {
+		fake.childErrorsReturnsOnCall = make(map[int]struct {
+			result1 map[string]error
+		})
+	}
+	fake.childErrorsReturnsOnCall[i] = struct {
+		result1 map[string]error
+	}{result1}
+}
+
+func (fake *Manager) Error() error {
+	fake.errorMutex.Lock()
+	ret, specificReturn := fake.errorReturnsOnCall[len(fake.errorArgsForCall)]
+	fake.errorArgsForCall = append(fake.errorArgsForCall, struct {
+	}{})
+	stub := fake.ErrorStub
+	fakeReturns := fake.errorReturns
+	fake.recordInvocation("Error", []interface{}{})
+	fake.errorMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) ErrorCallCount() int {
+	fake.errorMutex.RLock()
+	defer fake.errorMutex.RUnlock()
+	return len(fake.errorArgsForCall)
+}
+
+func (fake *Manager) ErrorCalls(stub func() error) {
+	fake.errorMutex.Lock()
+	defer fake.errorMutex.Unlock()
+	fake.ErrorStub = stub
+}
+
+func (fake *Manager) ErrorReturns(result1 error) {
+	fake.errorMutex.Lock()
+	defer fake.errorMutex.Unlock()
+	fake.ErrorStub = nil
+	fake.errorReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) ErrorReturnsOnCall(i int, result1 error) {
+	fake.errorMutex.Lock()
+	defer fake.errorMutex.Unlock()
+	fake.ErrorStub = nil
+	if fake.errorReturnsOnCall == nil {
+		fake.errorReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.errorReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) Lookup(arg1 context.Context, arg2 protocol.DeviceID) ([]string, error) {
+	fake.lookupMutex.Lock()
+	ret, specificReturn := fake.lookupReturnsOnCall[len(fake.lookupArgsForCall)]
+	fake.lookupArgsForCall = append(fake.lookupArgsForCall, struct {
+		arg1 context.Context
+		arg2 protocol.DeviceID
+	}{arg1, arg2})
+	stub := fake.LookupStub
+	fakeReturns := fake.lookupReturns
+	fake.recordInvocation("Lookup", []interface{}{arg1, arg2})
+	fake.lookupMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Manager) LookupCallCount() int {
+	fake.lookupMutex.RLock()
+	defer fake.lookupMutex.RUnlock()
+	return len(fake.lookupArgsForCall)
+}
+
+func (fake *Manager) LookupCalls(stub func(context.Context, protocol.DeviceID) ([]string, error)) {
+	fake.lookupMutex.Lock()
+	defer fake.lookupMutex.Unlock()
+	fake.LookupStub = stub
+}
+
+func (fake *Manager) LookupArgsForCall(i int) (context.Context, protocol.DeviceID) {
+	fake.lookupMutex.RLock()
+	defer fake.lookupMutex.RUnlock()
+	argsForCall := fake.lookupArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Manager) LookupReturns(result1 []string, result2 error) {
+	fake.lookupMutex.Lock()
+	defer fake.lookupMutex.Unlock()
+	fake.LookupStub = nil
+	fake.lookupReturns = struct {
+		result1 []string
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Manager) LookupReturnsOnCall(i int, result1 []string, result2 error) {
+	fake.lookupMutex.Lock()
+	defer fake.lookupMutex.Unlock()
+	fake.LookupStub = nil
+	if fake.lookupReturnsOnCall == nil {
+		fake.lookupReturnsOnCall = make(map[int]struct {
+			result1 []string
+			result2 error
+		})
+	}
+	fake.lookupReturnsOnCall[i] = struct {
+		result1 []string
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Manager) Serve(arg1 context.Context) error {
+	fake.serveMutex.Lock()
+	ret, specificReturn := fake.serveReturnsOnCall[len(fake.serveArgsForCall)]
+	fake.serveArgsForCall = append(fake.serveArgsForCall, struct {
+		arg1 context.Context
+	}{arg1})
+	stub := fake.ServeStub
+	fakeReturns := fake.serveReturns
+	fake.recordInvocation("Serve", []interface{}{arg1})
+	fake.serveMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) ServeCallCount() int {
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	return len(fake.serveArgsForCall)
+}
+
+func (fake *Manager) ServeCalls(stub func(context.Context) error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = stub
+}
+
+func (fake *Manager) ServeArgsForCall(i int) context.Context {
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	argsForCall := fake.serveArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Manager) ServeReturns(result1 error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = nil
+	fake.serveReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) ServeReturnsOnCall(i int, result1 error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = nil
+	if fake.serveReturnsOnCall == nil {
+		fake.serveReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.serveReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Manager) String() string {
+	fake.stringMutex.Lock()
+	ret, specificReturn := fake.stringReturnsOnCall[len(fake.stringArgsForCall)]
+	fake.stringArgsForCall = append(fake.stringArgsForCall, struct {
+	}{})
+	stub := fake.StringStub
+	fakeReturns := fake.stringReturns
+	fake.recordInvocation("String", []interface{}{})
+	fake.stringMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Manager) StringCallCount() int {
+	fake.stringMutex.RLock()
+	defer fake.stringMutex.RUnlock()
+	return len(fake.stringArgsForCall)
+}
+
+func (fake *Manager) StringCalls(stub func() string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = stub
+}
+
+func (fake *Manager) StringReturns(result1 string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = nil
+	fake.stringReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Manager) StringReturnsOnCall(i int, result1 string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = nil
+	if fake.stringReturnsOnCall == nil {
+		fake.stringReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.stringReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Manager) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.cacheMutex.RLock()
+	defer fake.cacheMutex.RUnlock()
+	fake.childErrorsMutex.RLock()
+	defer fake.childErrorsMutex.RUnlock()
+	fake.errorMutex.RLock()
+	defer fake.errorMutex.RUnlock()
+	fake.lookupMutex.RLock()
+	defer fake.lookupMutex.RUnlock()
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	fake.stringMutex.RLock()
+	defer fake.stringMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *Manager) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ discover.Manager = new(Manager)

+ 2 - 0
lib/events/events.go

@@ -4,6 +4,8 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // You can obtain one at https://mozilla.org/MPL/2.0/.
 
+//go:generate counterfeiter -o mocks/buffered_subscription.go --fake-name BufferedSubscription . BufferedSubscription
+
 // Package events provides event subscription and polling functionality.
 package events
 

+ 186 - 0
lib/events/mocks/buffered_subscription.go

@@ -0,0 +1,186 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"sync"
+	"time"
+
+	"github.com/syncthing/syncthing/lib/events"
+)
+
+type BufferedSubscription struct {
+	MaskStub        func() events.EventType
+	maskMutex       sync.RWMutex
+	maskArgsForCall []struct {
+	}
+	maskReturns struct {
+		result1 events.EventType
+	}
+	maskReturnsOnCall map[int]struct {
+		result1 events.EventType
+	}
+	SinceStub        func(int, []events.Event, time.Duration) []events.Event
+	sinceMutex       sync.RWMutex
+	sinceArgsForCall []struct {
+		arg1 int
+		arg2 []events.Event
+		arg3 time.Duration
+	}
+	sinceReturns struct {
+		result1 []events.Event
+	}
+	sinceReturnsOnCall map[int]struct {
+		result1 []events.Event
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *BufferedSubscription) Mask() events.EventType {
+	fake.maskMutex.Lock()
+	ret, specificReturn := fake.maskReturnsOnCall[len(fake.maskArgsForCall)]
+	fake.maskArgsForCall = append(fake.maskArgsForCall, struct {
+	}{})
+	stub := fake.MaskStub
+	fakeReturns := fake.maskReturns
+	fake.recordInvocation("Mask", []interface{}{})
+	fake.maskMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *BufferedSubscription) MaskCallCount() int {
+	fake.maskMutex.RLock()
+	defer fake.maskMutex.RUnlock()
+	return len(fake.maskArgsForCall)
+}
+
+func (fake *BufferedSubscription) MaskCalls(stub func() events.EventType) {
+	fake.maskMutex.Lock()
+	defer fake.maskMutex.Unlock()
+	fake.MaskStub = stub
+}
+
+func (fake *BufferedSubscription) MaskReturns(result1 events.EventType) {
+	fake.maskMutex.Lock()
+	defer fake.maskMutex.Unlock()
+	fake.MaskStub = nil
+	fake.maskReturns = struct {
+		result1 events.EventType
+	}{result1}
+}
+
+func (fake *BufferedSubscription) MaskReturnsOnCall(i int, result1 events.EventType) {
+	fake.maskMutex.Lock()
+	defer fake.maskMutex.Unlock()
+	fake.MaskStub = nil
+	if fake.maskReturnsOnCall == nil {
+		fake.maskReturnsOnCall = make(map[int]struct {
+			result1 events.EventType
+		})
+	}
+	fake.maskReturnsOnCall[i] = struct {
+		result1 events.EventType
+	}{result1}
+}
+
+func (fake *BufferedSubscription) Since(arg1 int, arg2 []events.Event, arg3 time.Duration) []events.Event {
+	var arg2Copy []events.Event
+	if arg2 != nil {
+		arg2Copy = make([]events.Event, len(arg2))
+		copy(arg2Copy, arg2)
+	}
+	fake.sinceMutex.Lock()
+	ret, specificReturn := fake.sinceReturnsOnCall[len(fake.sinceArgsForCall)]
+	fake.sinceArgsForCall = append(fake.sinceArgsForCall, struct {
+		arg1 int
+		arg2 []events.Event
+		arg3 time.Duration
+	}{arg1, arg2Copy, arg3})
+	stub := fake.SinceStub
+	fakeReturns := fake.sinceReturns
+	fake.recordInvocation("Since", []interface{}{arg1, arg2Copy, arg3})
+	fake.sinceMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *BufferedSubscription) SinceCallCount() int {
+	fake.sinceMutex.RLock()
+	defer fake.sinceMutex.RUnlock()
+	return len(fake.sinceArgsForCall)
+}
+
+func (fake *BufferedSubscription) SinceCalls(stub func(int, []events.Event, time.Duration) []events.Event) {
+	fake.sinceMutex.Lock()
+	defer fake.sinceMutex.Unlock()
+	fake.SinceStub = stub
+}
+
+func (fake *BufferedSubscription) SinceArgsForCall(i int) (int, []events.Event, time.Duration) {
+	fake.sinceMutex.RLock()
+	defer fake.sinceMutex.RUnlock()
+	argsForCall := fake.sinceArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *BufferedSubscription) SinceReturns(result1 []events.Event) {
+	fake.sinceMutex.Lock()
+	defer fake.sinceMutex.Unlock()
+	fake.SinceStub = nil
+	fake.sinceReturns = struct {
+		result1 []events.Event
+	}{result1}
+}
+
+func (fake *BufferedSubscription) SinceReturnsOnCall(i int, result1 []events.Event) {
+	fake.sinceMutex.Lock()
+	defer fake.sinceMutex.Unlock()
+	fake.SinceStub = nil
+	if fake.sinceReturnsOnCall == nil {
+		fake.sinceReturnsOnCall = make(map[int]struct {
+			result1 []events.Event
+		})
+	}
+	fake.sinceReturnsOnCall[i] = struct {
+		result1 []events.Event
+	}{result1}
+}
+
+func (fake *BufferedSubscription) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.maskMutex.RLock()
+	defer fake.maskMutex.RUnlock()
+	fake.sinceMutex.RLock()
+	defer fake.sinceMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *BufferedSubscription) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ events.BufferedSubscription = new(BufferedSubscription)

+ 2 - 0
lib/logger/logger.go

@@ -1,6 +1,8 @@
 // Copyright (C) 2014 Jakob Borg. All rights reserved. Use of this source code
 // is governed by an MIT-style license that can be found in the LICENSE file.
 
+//go:generate counterfeiter -o mocks/logger.go --fake-name Recorder . Recorder
+
 // Package logger implements a standardized logger with callback functionality
 package logger
 

+ 142 - 0
lib/logger/mocks/logger.go

@@ -0,0 +1,142 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"sync"
+	"time"
+
+	"github.com/syncthing/syncthing/lib/logger"
+)
+
+type Recorder struct {
+	ClearStub        func()
+	clearMutex       sync.RWMutex
+	clearArgsForCall []struct {
+	}
+	SinceStub        func(time.Time) []logger.Line
+	sinceMutex       sync.RWMutex
+	sinceArgsForCall []struct {
+		arg1 time.Time
+	}
+	sinceReturns struct {
+		result1 []logger.Line
+	}
+	sinceReturnsOnCall map[int]struct {
+		result1 []logger.Line
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *Recorder) Clear() {
+	fake.clearMutex.Lock()
+	fake.clearArgsForCall = append(fake.clearArgsForCall, struct {
+	}{})
+	stub := fake.ClearStub
+	fake.recordInvocation("Clear", []interface{}{})
+	fake.clearMutex.Unlock()
+	if stub != nil {
+		fake.ClearStub()
+	}
+}
+
+func (fake *Recorder) ClearCallCount() int {
+	fake.clearMutex.RLock()
+	defer fake.clearMutex.RUnlock()
+	return len(fake.clearArgsForCall)
+}
+
+func (fake *Recorder) ClearCalls(stub func()) {
+	fake.clearMutex.Lock()
+	defer fake.clearMutex.Unlock()
+	fake.ClearStub = stub
+}
+
+func (fake *Recorder) Since(arg1 time.Time) []logger.Line {
+	fake.sinceMutex.Lock()
+	ret, specificReturn := fake.sinceReturnsOnCall[len(fake.sinceArgsForCall)]
+	fake.sinceArgsForCall = append(fake.sinceArgsForCall, struct {
+		arg1 time.Time
+	}{arg1})
+	stub := fake.SinceStub
+	fakeReturns := fake.sinceReturns
+	fake.recordInvocation("Since", []interface{}{arg1})
+	fake.sinceMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Recorder) SinceCallCount() int {
+	fake.sinceMutex.RLock()
+	defer fake.sinceMutex.RUnlock()
+	return len(fake.sinceArgsForCall)
+}
+
+func (fake *Recorder) SinceCalls(stub func(time.Time) []logger.Line) {
+	fake.sinceMutex.Lock()
+	defer fake.sinceMutex.Unlock()
+	fake.SinceStub = stub
+}
+
+func (fake *Recorder) SinceArgsForCall(i int) time.Time {
+	fake.sinceMutex.RLock()
+	defer fake.sinceMutex.RUnlock()
+	argsForCall := fake.sinceArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Recorder) SinceReturns(result1 []logger.Line) {
+	fake.sinceMutex.Lock()
+	defer fake.sinceMutex.Unlock()
+	fake.SinceStub = nil
+	fake.sinceReturns = struct {
+		result1 []logger.Line
+	}{result1}
+}
+
+func (fake *Recorder) SinceReturnsOnCall(i int, result1 []logger.Line) {
+	fake.sinceMutex.Lock()
+	defer fake.sinceMutex.Unlock()
+	fake.SinceStub = nil
+	if fake.sinceReturnsOnCall == nil {
+		fake.sinceReturnsOnCall = make(map[int]struct {
+			result1 []logger.Line
+		})
+	}
+	fake.sinceReturnsOnCall[i] = struct {
+		result1 []logger.Line
+	}{result1}
+}
+
+func (fake *Recorder) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.clearMutex.RLock()
+	defer fake.clearMutex.RUnlock()
+	fake.sinceMutex.RLock()
+	defer fake.sinceMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *Recorder) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ logger.Recorder = new(Recorder)

+ 24 - 84
lib/model/fakeconns_test.go

@@ -13,8 +13,8 @@ import (
 	"time"
 
 	"github.com/syncthing/syncthing/lib/protocol"
+	protocolmocks "github.com/syncthing/syncthing/lib/protocol/mocks"
 	"github.com/syncthing/syncthing/lib/scanner"
-	"github.com/syncthing/syncthing/lib/testutils"
 )
 
 type downloadProgressMessage struct {
@@ -22,97 +22,37 @@ type downloadProgressMessage struct {
 	updates []protocol.FileDownloadProgressUpdate
 }
 
+func newFakeConnection(id protocol.DeviceID, model Model) *fakeConnection {
+	f := &fakeConnection{
+		Connection: new(protocolmocks.Connection),
+		id:         id,
+		model:      model,
+	}
+	f.RequestCalls(func(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
+		return f.fileData[name], nil
+	})
+	f.IDReturns(id)
+	f.CloseCalls(func(err error) {
+		model.Closed(f, err)
+		f.ClosedReturns(true)
+	})
+	return f
+}
+
 type fakeConnection struct {
-	testutils.FakeConnectionInfo
+	*protocolmocks.Connection
 	id                       protocol.DeviceID
 	downloadProgressMessages []downloadProgressMessage
-	closed                   bool
 	files                    []protocol.FileInfo
 	fileData                 map[string][]byte
 	folder                   string
-	model                    *testModel
-	indexFn                  func(context.Context, string, []protocol.FileInfo)
-	requestFn                func(ctx context.Context, folder, name string, offset int64, size int, hash []byte, fromTemporary bool) ([]byte, error)
-	closeFn                  func(error)
-	clusterConfigFn          func(protocol.ClusterConfig)
+	model                    Model
 	mut                      sync.Mutex
 }
 
-func (f *fakeConnection) Close(err error) {
-	f.mut.Lock()
-	defer f.mut.Unlock()
-	if f.closeFn != nil {
-		f.closeFn(err)
-		return
-	}
-	f.closed = true
-	f.model.Closed(f, err)
-}
-
-func (f *fakeConnection) Start() {
-}
-
-func (f *fakeConnection) ID() protocol.DeviceID {
-	return f.id
-}
-
-func (f *fakeConnection) Name() string {
-	return ""
-}
-
-func (f *fakeConnection) Option(string) string {
-	return ""
-}
-
-func (f *fakeConnection) Index(ctx context.Context, folder string, fs []protocol.FileInfo) error {
-	f.mut.Lock()
-	defer f.mut.Unlock()
-	if f.indexFn != nil {
-		f.indexFn(ctx, folder, fs)
-	}
-	return nil
-}
-
-func (f *fakeConnection) IndexUpdate(ctx context.Context, folder string, fs []protocol.FileInfo) error {
-	f.mut.Lock()
-	defer f.mut.Unlock()
-	if f.indexFn != nil {
-		f.indexFn(ctx, folder, fs)
-	}
-	return nil
-}
-
-func (f *fakeConnection) Request(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
-	f.mut.Lock()
-	defer f.mut.Unlock()
-	if f.requestFn != nil {
-		return f.requestFn(ctx, folder, name, offset, size, hash, fromTemporary)
-	}
-	return f.fileData[name], nil
-}
-
-func (f *fakeConnection) ClusterConfig(cc protocol.ClusterConfig) {
-	f.mut.Lock()
-	defer f.mut.Unlock()
-	if f.clusterConfigFn != nil {
-		f.clusterConfigFn(cc)
-	}
-}
-
-func (f *fakeConnection) Ping() bool {
-	f.mut.Lock()
-	defer f.mut.Unlock()
-	return f.closed
-}
-
-func (f *fakeConnection) Closed() bool {
-	f.mut.Lock()
-	defer f.mut.Unlock()
-	return f.closed
-}
-
-func (f *fakeConnection) Statistics() protocol.Statistics {
-	return protocol.Statistics{}
+func (f *fakeConnection) setIndexFn(fn func(_ context.Context, folder string, fs []protocol.FileInfo) error) {
+	f.IndexCalls(fn)
+	f.IndexUpdateCalls(fn)
 }
 
 func (f *fakeConnection) DownloadProgress(_ context.Context, folder string, updates []protocol.FileDownloadProgressUpdate) {
@@ -201,7 +141,7 @@ func (f *fakeConnection) sendIndexUpdate() {
 }
 
 func addFakeConn(m *testModel, dev protocol.DeviceID) *fakeConnection {
-	fc := &fakeConnection{id: dev, model: m}
+	fc := newFakeConnection(dev, m)
 	m.AddConnection(fc, protocol.Hello{})
 
 	m.ClusterConfig(dev, protocol.ClusterConfig{

+ 2 - 0
lib/model/folder_summary.go

@@ -4,6 +4,8 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // You can obtain one at https://mozilla.org/MPL/2.0/.
 
+//go:generate counterfeiter -o mocks/folderSummaryService.go --fake-name FolderSummaryService . FolderSummaryService
+
 package model
 
 import (

+ 221 - 0
lib/model/mocks/folderSummaryService.go

@@ -0,0 +1,221 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"context"
+	"sync"
+
+	"github.com/syncthing/syncthing/lib/model"
+)
+
+type FolderSummaryService struct {
+	OnEventRequestStub        func()
+	onEventRequestMutex       sync.RWMutex
+	onEventRequestArgsForCall []struct {
+	}
+	ServeStub        func(context.Context) error
+	serveMutex       sync.RWMutex
+	serveArgsForCall []struct {
+		arg1 context.Context
+	}
+	serveReturns struct {
+		result1 error
+	}
+	serveReturnsOnCall map[int]struct {
+		result1 error
+	}
+	SummaryStub        func(string) (map[string]interface{}, error)
+	summaryMutex       sync.RWMutex
+	summaryArgsForCall []struct {
+		arg1 string
+	}
+	summaryReturns struct {
+		result1 map[string]interface{}
+		result2 error
+	}
+	summaryReturnsOnCall map[int]struct {
+		result1 map[string]interface{}
+		result2 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *FolderSummaryService) OnEventRequest() {
+	fake.onEventRequestMutex.Lock()
+	fake.onEventRequestArgsForCall = append(fake.onEventRequestArgsForCall, struct {
+	}{})
+	stub := fake.OnEventRequestStub
+	fake.recordInvocation("OnEventRequest", []interface{}{})
+	fake.onEventRequestMutex.Unlock()
+	if stub != nil {
+		fake.OnEventRequestStub()
+	}
+}
+
+func (fake *FolderSummaryService) OnEventRequestCallCount() int {
+	fake.onEventRequestMutex.RLock()
+	defer fake.onEventRequestMutex.RUnlock()
+	return len(fake.onEventRequestArgsForCall)
+}
+
+func (fake *FolderSummaryService) OnEventRequestCalls(stub func()) {
+	fake.onEventRequestMutex.Lock()
+	defer fake.onEventRequestMutex.Unlock()
+	fake.OnEventRequestStub = stub
+}
+
+func (fake *FolderSummaryService) Serve(arg1 context.Context) error {
+	fake.serveMutex.Lock()
+	ret, specificReturn := fake.serveReturnsOnCall[len(fake.serveArgsForCall)]
+	fake.serveArgsForCall = append(fake.serveArgsForCall, struct {
+		arg1 context.Context
+	}{arg1})
+	stub := fake.ServeStub
+	fakeReturns := fake.serveReturns
+	fake.recordInvocation("Serve", []interface{}{arg1})
+	fake.serveMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *FolderSummaryService) ServeCallCount() int {
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	return len(fake.serveArgsForCall)
+}
+
+func (fake *FolderSummaryService) ServeCalls(stub func(context.Context) error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = stub
+}
+
+func (fake *FolderSummaryService) ServeArgsForCall(i int) context.Context {
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	argsForCall := fake.serveArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *FolderSummaryService) ServeReturns(result1 error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = nil
+	fake.serveReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *FolderSummaryService) ServeReturnsOnCall(i int, result1 error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = nil
+	if fake.serveReturnsOnCall == nil {
+		fake.serveReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.serveReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *FolderSummaryService) Summary(arg1 string) (map[string]interface{}, error) {
+	fake.summaryMutex.Lock()
+	ret, specificReturn := fake.summaryReturnsOnCall[len(fake.summaryArgsForCall)]
+	fake.summaryArgsForCall = append(fake.summaryArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.SummaryStub
+	fakeReturns := fake.summaryReturns
+	fake.recordInvocation("Summary", []interface{}{arg1})
+	fake.summaryMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *FolderSummaryService) SummaryCallCount() int {
+	fake.summaryMutex.RLock()
+	defer fake.summaryMutex.RUnlock()
+	return len(fake.summaryArgsForCall)
+}
+
+func (fake *FolderSummaryService) SummaryCalls(stub func(string) (map[string]interface{}, error)) {
+	fake.summaryMutex.Lock()
+	defer fake.summaryMutex.Unlock()
+	fake.SummaryStub = stub
+}
+
+func (fake *FolderSummaryService) SummaryArgsForCall(i int) string {
+	fake.summaryMutex.RLock()
+	defer fake.summaryMutex.RUnlock()
+	argsForCall := fake.summaryArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *FolderSummaryService) SummaryReturns(result1 map[string]interface{}, result2 error) {
+	fake.summaryMutex.Lock()
+	defer fake.summaryMutex.Unlock()
+	fake.SummaryStub = nil
+	fake.summaryReturns = struct {
+		result1 map[string]interface{}
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FolderSummaryService) SummaryReturnsOnCall(i int, result1 map[string]interface{}, result2 error) {
+	fake.summaryMutex.Lock()
+	defer fake.summaryMutex.Unlock()
+	fake.SummaryStub = nil
+	if fake.summaryReturnsOnCall == nil {
+		fake.summaryReturnsOnCall = make(map[int]struct {
+			result1 map[string]interface{}
+			result2 error
+		})
+	}
+	fake.summaryReturnsOnCall[i] = struct {
+		result1 map[string]interface{}
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *FolderSummaryService) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.onEventRequestMutex.RLock()
+	defer fake.onEventRequestMutex.RUnlock()
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	fake.summaryMutex.RLock()
+	defer fake.summaryMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *FolderSummaryService) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ model.FolderSummaryService = new(FolderSummaryService)

+ 3238 - 0
lib/model/mocks/model.go

@@ -0,0 +1,3238 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"context"
+	"net"
+	"sync"
+	"time"
+
+	"github.com/syncthing/syncthing/lib/db"
+	"github.com/syncthing/syncthing/lib/model"
+	"github.com/syncthing/syncthing/lib/protocol"
+	"github.com/syncthing/syncthing/lib/stats"
+	"github.com/syncthing/syncthing/lib/ur/contract"
+	"github.com/syncthing/syncthing/lib/versioner"
+)
+
+type Model struct {
+	AddConnectionStub        func(protocol.Connection, protocol.Hello)
+	addConnectionMutex       sync.RWMutex
+	addConnectionArgsForCall []struct {
+		arg1 protocol.Connection
+		arg2 protocol.Hello
+	}
+	AvailabilityStub        func(string, protocol.FileInfo, protocol.BlockInfo) []model.Availability
+	availabilityMutex       sync.RWMutex
+	availabilityArgsForCall []struct {
+		arg1 string
+		arg2 protocol.FileInfo
+		arg3 protocol.BlockInfo
+	}
+	availabilityReturns struct {
+		result1 []model.Availability
+	}
+	availabilityReturnsOnCall map[int]struct {
+		result1 []model.Availability
+	}
+	BringToFrontStub        func(string, string)
+	bringToFrontMutex       sync.RWMutex
+	bringToFrontArgsForCall []struct {
+		arg1 string
+		arg2 string
+	}
+	ClosedStub        func(protocol.Connection, error)
+	closedMutex       sync.RWMutex
+	closedArgsForCall []struct {
+		arg1 protocol.Connection
+		arg2 error
+	}
+	ClusterConfigStub        func(protocol.DeviceID, protocol.ClusterConfig) error
+	clusterConfigMutex       sync.RWMutex
+	clusterConfigArgsForCall []struct {
+		arg1 protocol.DeviceID
+		arg2 protocol.ClusterConfig
+	}
+	clusterConfigReturns struct {
+		result1 error
+	}
+	clusterConfigReturnsOnCall map[int]struct {
+		result1 error
+	}
+	CompletionStub        func(protocol.DeviceID, string) model.FolderCompletion
+	completionMutex       sync.RWMutex
+	completionArgsForCall []struct {
+		arg1 protocol.DeviceID
+		arg2 string
+	}
+	completionReturns struct {
+		result1 model.FolderCompletion
+	}
+	completionReturnsOnCall map[int]struct {
+		result1 model.FolderCompletion
+	}
+	ConnectionStub        func(protocol.DeviceID) (protocol.Connection, bool)
+	connectionMutex       sync.RWMutex
+	connectionArgsForCall []struct {
+		arg1 protocol.DeviceID
+	}
+	connectionReturns struct {
+		result1 protocol.Connection
+		result2 bool
+	}
+	connectionReturnsOnCall map[int]struct {
+		result1 protocol.Connection
+		result2 bool
+	}
+	ConnectionStatsStub        func() map[string]interface{}
+	connectionStatsMutex       sync.RWMutex
+	connectionStatsArgsForCall []struct {
+	}
+	connectionStatsReturns struct {
+		result1 map[string]interface{}
+	}
+	connectionStatsReturnsOnCall map[int]struct {
+		result1 map[string]interface{}
+	}
+	CurrentFolderFileStub        func(string, string) (protocol.FileInfo, bool)
+	currentFolderFileMutex       sync.RWMutex
+	currentFolderFileArgsForCall []struct {
+		arg1 string
+		arg2 string
+	}
+	currentFolderFileReturns struct {
+		result1 protocol.FileInfo
+		result2 bool
+	}
+	currentFolderFileReturnsOnCall map[int]struct {
+		result1 protocol.FileInfo
+		result2 bool
+	}
+	CurrentGlobalFileStub        func(string, string) (protocol.FileInfo, bool)
+	currentGlobalFileMutex       sync.RWMutex
+	currentGlobalFileArgsForCall []struct {
+		arg1 string
+		arg2 string
+	}
+	currentGlobalFileReturns struct {
+		result1 protocol.FileInfo
+		result2 bool
+	}
+	currentGlobalFileReturnsOnCall map[int]struct {
+		result1 protocol.FileInfo
+		result2 bool
+	}
+	CurrentIgnoresStub        func(string) ([]string, []string, error)
+	currentIgnoresMutex       sync.RWMutex
+	currentIgnoresArgsForCall []struct {
+		arg1 string
+	}
+	currentIgnoresReturns struct {
+		result1 []string
+		result2 []string
+		result3 error
+	}
+	currentIgnoresReturnsOnCall map[int]struct {
+		result1 []string
+		result2 []string
+		result3 error
+	}
+	DBSnapshotStub        func(string) (*db.Snapshot, error)
+	dBSnapshotMutex       sync.RWMutex
+	dBSnapshotArgsForCall []struct {
+		arg1 string
+	}
+	dBSnapshotReturns struct {
+		result1 *db.Snapshot
+		result2 error
+	}
+	dBSnapshotReturnsOnCall map[int]struct {
+		result1 *db.Snapshot
+		result2 error
+	}
+	DelayScanStub        func(string, time.Duration)
+	delayScanMutex       sync.RWMutex
+	delayScanArgsForCall []struct {
+		arg1 string
+		arg2 time.Duration
+	}
+	DeviceStatisticsStub        func() (map[protocol.DeviceID]stats.DeviceStatistics, error)
+	deviceStatisticsMutex       sync.RWMutex
+	deviceStatisticsArgsForCall []struct {
+	}
+	deviceStatisticsReturns struct {
+		result1 map[protocol.DeviceID]stats.DeviceStatistics
+		result2 error
+	}
+	deviceStatisticsReturnsOnCall map[int]struct {
+		result1 map[protocol.DeviceID]stats.DeviceStatistics
+		result2 error
+	}
+	DownloadProgressStub        func(protocol.DeviceID, string, []protocol.FileDownloadProgressUpdate) error
+	downloadProgressMutex       sync.RWMutex
+	downloadProgressArgsForCall []struct {
+		arg1 protocol.DeviceID
+		arg2 string
+		arg3 []protocol.FileDownloadProgressUpdate
+	}
+	downloadProgressReturns struct {
+		result1 error
+	}
+	downloadProgressReturnsOnCall map[int]struct {
+		result1 error
+	}
+	FolderErrorsStub        func(string) ([]model.FileError, error)
+	folderErrorsMutex       sync.RWMutex
+	folderErrorsArgsForCall []struct {
+		arg1 string
+	}
+	folderErrorsReturns struct {
+		result1 []model.FileError
+		result2 error
+	}
+	folderErrorsReturnsOnCall map[int]struct {
+		result1 []model.FileError
+		result2 error
+	}
+	FolderProgressBytesCompletedStub        func(string) int64
+	folderProgressBytesCompletedMutex       sync.RWMutex
+	folderProgressBytesCompletedArgsForCall []struct {
+		arg1 string
+	}
+	folderProgressBytesCompletedReturns struct {
+		result1 int64
+	}
+	folderProgressBytesCompletedReturnsOnCall map[int]struct {
+		result1 int64
+	}
+	FolderStatisticsStub        func() (map[string]stats.FolderStatistics, error)
+	folderStatisticsMutex       sync.RWMutex
+	folderStatisticsArgsForCall []struct {
+	}
+	folderStatisticsReturns struct {
+		result1 map[string]stats.FolderStatistics
+		result2 error
+	}
+	folderStatisticsReturnsOnCall map[int]struct {
+		result1 map[string]stats.FolderStatistics
+		result2 error
+	}
+	GetFolderVersionsStub        func(string) (map[string][]versioner.FileVersion, error)
+	getFolderVersionsMutex       sync.RWMutex
+	getFolderVersionsArgsForCall []struct {
+		arg1 string
+	}
+	getFolderVersionsReturns struct {
+		result1 map[string][]versioner.FileVersion
+		result2 error
+	}
+	getFolderVersionsReturnsOnCall map[int]struct {
+		result1 map[string][]versioner.FileVersion
+		result2 error
+	}
+	GetHelloStub        func(protocol.DeviceID) protocol.HelloIntf
+	getHelloMutex       sync.RWMutex
+	getHelloArgsForCall []struct {
+		arg1 protocol.DeviceID
+	}
+	getHelloReturns struct {
+		result1 protocol.HelloIntf
+	}
+	getHelloReturnsOnCall map[int]struct {
+		result1 protocol.HelloIntf
+	}
+	GlobalDirectoryTreeStub        func(string, string, int, bool) ([]*model.TreeEntry, error)
+	globalDirectoryTreeMutex       sync.RWMutex
+	globalDirectoryTreeArgsForCall []struct {
+		arg1 string
+		arg2 string
+		arg3 int
+		arg4 bool
+	}
+	globalDirectoryTreeReturns struct {
+		result1 []*model.TreeEntry
+		result2 error
+	}
+	globalDirectoryTreeReturnsOnCall map[int]struct {
+		result1 []*model.TreeEntry
+		result2 error
+	}
+	IndexStub        func(protocol.DeviceID, string, []protocol.FileInfo) error
+	indexMutex       sync.RWMutex
+	indexArgsForCall []struct {
+		arg1 protocol.DeviceID
+		arg2 string
+		arg3 []protocol.FileInfo
+	}
+	indexReturns struct {
+		result1 error
+	}
+	indexReturnsOnCall map[int]struct {
+		result1 error
+	}
+	IndexUpdateStub        func(protocol.DeviceID, string, []protocol.FileInfo) error
+	indexUpdateMutex       sync.RWMutex
+	indexUpdateArgsForCall []struct {
+		arg1 protocol.DeviceID
+		arg2 string
+		arg3 []protocol.FileInfo
+	}
+	indexUpdateReturns struct {
+		result1 error
+	}
+	indexUpdateReturnsOnCall map[int]struct {
+		result1 error
+	}
+	LoadIgnoresStub        func(string) ([]string, []string, error)
+	loadIgnoresMutex       sync.RWMutex
+	loadIgnoresArgsForCall []struct {
+		arg1 string
+	}
+	loadIgnoresReturns struct {
+		result1 []string
+		result2 []string
+		result3 error
+	}
+	loadIgnoresReturnsOnCall map[int]struct {
+		result1 []string
+		result2 []string
+		result3 error
+	}
+	LocalChangedFolderFilesStub        func(string, int, int) ([]db.FileInfoTruncated, error)
+	localChangedFolderFilesMutex       sync.RWMutex
+	localChangedFolderFilesArgsForCall []struct {
+		arg1 string
+		arg2 int
+		arg3 int
+	}
+	localChangedFolderFilesReturns struct {
+		result1 []db.FileInfoTruncated
+		result2 error
+	}
+	localChangedFolderFilesReturnsOnCall map[int]struct {
+		result1 []db.FileInfoTruncated
+		result2 error
+	}
+	NeedFolderFilesStub        func(string, int, int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, error)
+	needFolderFilesMutex       sync.RWMutex
+	needFolderFilesArgsForCall []struct {
+		arg1 string
+		arg2 int
+		arg3 int
+	}
+	needFolderFilesReturns struct {
+		result1 []db.FileInfoTruncated
+		result2 []db.FileInfoTruncated
+		result3 []db.FileInfoTruncated
+		result4 error
+	}
+	needFolderFilesReturnsOnCall map[int]struct {
+		result1 []db.FileInfoTruncated
+		result2 []db.FileInfoTruncated
+		result3 []db.FileInfoTruncated
+		result4 error
+	}
+	NumConnectionsStub        func() int
+	numConnectionsMutex       sync.RWMutex
+	numConnectionsArgsForCall []struct {
+	}
+	numConnectionsReturns struct {
+		result1 int
+	}
+	numConnectionsReturnsOnCall map[int]struct {
+		result1 int
+	}
+	OnHelloStub        func(protocol.DeviceID, net.Addr, protocol.Hello) error
+	onHelloMutex       sync.RWMutex
+	onHelloArgsForCall []struct {
+		arg1 protocol.DeviceID
+		arg2 net.Addr
+		arg3 protocol.Hello
+	}
+	onHelloReturns struct {
+		result1 error
+	}
+	onHelloReturnsOnCall map[int]struct {
+		result1 error
+	}
+	OverrideStub        func(string)
+	overrideMutex       sync.RWMutex
+	overrideArgsForCall []struct {
+		arg1 string
+	}
+	PendingDevicesStub        func() (map[protocol.DeviceID]db.ObservedDevice, error)
+	pendingDevicesMutex       sync.RWMutex
+	pendingDevicesArgsForCall []struct {
+	}
+	pendingDevicesReturns struct {
+		result1 map[protocol.DeviceID]db.ObservedDevice
+		result2 error
+	}
+	pendingDevicesReturnsOnCall map[int]struct {
+		result1 map[protocol.DeviceID]db.ObservedDevice
+		result2 error
+	}
+	PendingFoldersStub        func(protocol.DeviceID) (map[string]db.PendingFolder, error)
+	pendingFoldersMutex       sync.RWMutex
+	pendingFoldersArgsForCall []struct {
+		arg1 protocol.DeviceID
+	}
+	pendingFoldersReturns struct {
+		result1 map[string]db.PendingFolder
+		result2 error
+	}
+	pendingFoldersReturnsOnCall map[int]struct {
+		result1 map[string]db.PendingFolder
+		result2 error
+	}
+	RemoteNeedFolderFilesStub        func(string, protocol.DeviceID, int, int) ([]db.FileInfoTruncated, error)
+	remoteNeedFolderFilesMutex       sync.RWMutex
+	remoteNeedFolderFilesArgsForCall []struct {
+		arg1 string
+		arg2 protocol.DeviceID
+		arg3 int
+		arg4 int
+	}
+	remoteNeedFolderFilesReturns struct {
+		result1 []db.FileInfoTruncated
+		result2 error
+	}
+	remoteNeedFolderFilesReturnsOnCall map[int]struct {
+		result1 []db.FileInfoTruncated
+		result2 error
+	}
+	RequestStub        func(protocol.DeviceID, string, string, int32, int32, int64, []byte, uint32, bool) (protocol.RequestResponse, error)
+	requestMutex       sync.RWMutex
+	requestArgsForCall []struct {
+		arg1 protocol.DeviceID
+		arg2 string
+		arg3 string
+		arg4 int32
+		arg5 int32
+		arg6 int64
+		arg7 []byte
+		arg8 uint32
+		arg9 bool
+	}
+	requestReturns struct {
+		result1 protocol.RequestResponse
+		result2 error
+	}
+	requestReturnsOnCall map[int]struct {
+		result1 protocol.RequestResponse
+		result2 error
+	}
+	ResetFolderStub        func(string)
+	resetFolderMutex       sync.RWMutex
+	resetFolderArgsForCall []struct {
+		arg1 string
+	}
+	RestoreFolderVersionsStub        func(string, map[string]time.Time) (map[string]error, error)
+	restoreFolderVersionsMutex       sync.RWMutex
+	restoreFolderVersionsArgsForCall []struct {
+		arg1 string
+		arg2 map[string]time.Time
+	}
+	restoreFolderVersionsReturns struct {
+		result1 map[string]error
+		result2 error
+	}
+	restoreFolderVersionsReturnsOnCall map[int]struct {
+		result1 map[string]error
+		result2 error
+	}
+	RevertStub        func(string)
+	revertMutex       sync.RWMutex
+	revertArgsForCall []struct {
+		arg1 string
+	}
+	ScanFolderStub        func(string) error
+	scanFolderMutex       sync.RWMutex
+	scanFolderArgsForCall []struct {
+		arg1 string
+	}
+	scanFolderReturns struct {
+		result1 error
+	}
+	scanFolderReturnsOnCall map[int]struct {
+		result1 error
+	}
+	ScanFolderSubdirsStub        func(string, []string) error
+	scanFolderSubdirsMutex       sync.RWMutex
+	scanFolderSubdirsArgsForCall []struct {
+		arg1 string
+		arg2 []string
+	}
+	scanFolderSubdirsReturns struct {
+		result1 error
+	}
+	scanFolderSubdirsReturnsOnCall map[int]struct {
+		result1 error
+	}
+	ScanFoldersStub        func() map[string]error
+	scanFoldersMutex       sync.RWMutex
+	scanFoldersArgsForCall []struct {
+	}
+	scanFoldersReturns struct {
+		result1 map[string]error
+	}
+	scanFoldersReturnsOnCall map[int]struct {
+		result1 map[string]error
+	}
+	ServeStub        func(context.Context) error
+	serveMutex       sync.RWMutex
+	serveArgsForCall []struct {
+		arg1 context.Context
+	}
+	serveReturns struct {
+		result1 error
+	}
+	serveReturnsOnCall map[int]struct {
+		result1 error
+	}
+	SetIgnoresStub        func(string, []string) error
+	setIgnoresMutex       sync.RWMutex
+	setIgnoresArgsForCall []struct {
+		arg1 string
+		arg2 []string
+	}
+	setIgnoresReturns struct {
+		result1 error
+	}
+	setIgnoresReturnsOnCall map[int]struct {
+		result1 error
+	}
+	StartDeadlockDetectorStub        func(time.Duration)
+	startDeadlockDetectorMutex       sync.RWMutex
+	startDeadlockDetectorArgsForCall []struct {
+		arg1 time.Duration
+	}
+	StateStub        func(string) (string, time.Time, error)
+	stateMutex       sync.RWMutex
+	stateArgsForCall []struct {
+		arg1 string
+	}
+	stateReturns struct {
+		result1 string
+		result2 time.Time
+		result3 error
+	}
+	stateReturnsOnCall map[int]struct {
+		result1 string
+		result2 time.Time
+		result3 error
+	}
+	UsageReportingStatsStub        func(*contract.Report, int, bool)
+	usageReportingStatsMutex       sync.RWMutex
+	usageReportingStatsArgsForCall []struct {
+		arg1 *contract.Report
+		arg2 int
+		arg3 bool
+	}
+	WatchErrorStub        func(string) error
+	watchErrorMutex       sync.RWMutex
+	watchErrorArgsForCall []struct {
+		arg1 string
+	}
+	watchErrorReturns struct {
+		result1 error
+	}
+	watchErrorReturnsOnCall map[int]struct {
+		result1 error
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *Model) AddConnection(arg1 protocol.Connection, arg2 protocol.Hello) {
+	fake.addConnectionMutex.Lock()
+	fake.addConnectionArgsForCall = append(fake.addConnectionArgsForCall, struct {
+		arg1 protocol.Connection
+		arg2 protocol.Hello
+	}{arg1, arg2})
+	stub := fake.AddConnectionStub
+	fake.recordInvocation("AddConnection", []interface{}{arg1, arg2})
+	fake.addConnectionMutex.Unlock()
+	if stub != nil {
+		fake.AddConnectionStub(arg1, arg2)
+	}
+}
+
+func (fake *Model) AddConnectionCallCount() int {
+	fake.addConnectionMutex.RLock()
+	defer fake.addConnectionMutex.RUnlock()
+	return len(fake.addConnectionArgsForCall)
+}
+
+func (fake *Model) AddConnectionCalls(stub func(protocol.Connection, protocol.Hello)) {
+	fake.addConnectionMutex.Lock()
+	defer fake.addConnectionMutex.Unlock()
+	fake.AddConnectionStub = stub
+}
+
+func (fake *Model) AddConnectionArgsForCall(i int) (protocol.Connection, protocol.Hello) {
+	fake.addConnectionMutex.RLock()
+	defer fake.addConnectionMutex.RUnlock()
+	argsForCall := fake.addConnectionArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) Availability(arg1 string, arg2 protocol.FileInfo, arg3 protocol.BlockInfo) []model.Availability {
+	fake.availabilityMutex.Lock()
+	ret, specificReturn := fake.availabilityReturnsOnCall[len(fake.availabilityArgsForCall)]
+	fake.availabilityArgsForCall = append(fake.availabilityArgsForCall, struct {
+		arg1 string
+		arg2 protocol.FileInfo
+		arg3 protocol.BlockInfo
+	}{arg1, arg2, arg3})
+	stub := fake.AvailabilityStub
+	fakeReturns := fake.availabilityReturns
+	fake.recordInvocation("Availability", []interface{}{arg1, arg2, arg3})
+	fake.availabilityMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) AvailabilityCallCount() int {
+	fake.availabilityMutex.RLock()
+	defer fake.availabilityMutex.RUnlock()
+	return len(fake.availabilityArgsForCall)
+}
+
+func (fake *Model) AvailabilityCalls(stub func(string, protocol.FileInfo, protocol.BlockInfo) []model.Availability) {
+	fake.availabilityMutex.Lock()
+	defer fake.availabilityMutex.Unlock()
+	fake.AvailabilityStub = stub
+}
+
+func (fake *Model) AvailabilityArgsForCall(i int) (string, protocol.FileInfo, protocol.BlockInfo) {
+	fake.availabilityMutex.RLock()
+	defer fake.availabilityMutex.RUnlock()
+	argsForCall := fake.availabilityArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Model) AvailabilityReturns(result1 []model.Availability) {
+	fake.availabilityMutex.Lock()
+	defer fake.availabilityMutex.Unlock()
+	fake.AvailabilityStub = nil
+	fake.availabilityReturns = struct {
+		result1 []model.Availability
+	}{result1}
+}
+
+func (fake *Model) AvailabilityReturnsOnCall(i int, result1 []model.Availability) {
+	fake.availabilityMutex.Lock()
+	defer fake.availabilityMutex.Unlock()
+	fake.AvailabilityStub = nil
+	if fake.availabilityReturnsOnCall == nil {
+		fake.availabilityReturnsOnCall = make(map[int]struct {
+			result1 []model.Availability
+		})
+	}
+	fake.availabilityReturnsOnCall[i] = struct {
+		result1 []model.Availability
+	}{result1}
+}
+
+func (fake *Model) BringToFront(arg1 string, arg2 string) {
+	fake.bringToFrontMutex.Lock()
+	fake.bringToFrontArgsForCall = append(fake.bringToFrontArgsForCall, struct {
+		arg1 string
+		arg2 string
+	}{arg1, arg2})
+	stub := fake.BringToFrontStub
+	fake.recordInvocation("BringToFront", []interface{}{arg1, arg2})
+	fake.bringToFrontMutex.Unlock()
+	if stub != nil {
+		fake.BringToFrontStub(arg1, arg2)
+	}
+}
+
+func (fake *Model) BringToFrontCallCount() int {
+	fake.bringToFrontMutex.RLock()
+	defer fake.bringToFrontMutex.RUnlock()
+	return len(fake.bringToFrontArgsForCall)
+}
+
+func (fake *Model) BringToFrontCalls(stub func(string, string)) {
+	fake.bringToFrontMutex.Lock()
+	defer fake.bringToFrontMutex.Unlock()
+	fake.BringToFrontStub = stub
+}
+
+func (fake *Model) BringToFrontArgsForCall(i int) (string, string) {
+	fake.bringToFrontMutex.RLock()
+	defer fake.bringToFrontMutex.RUnlock()
+	argsForCall := fake.bringToFrontArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) Closed(arg1 protocol.Connection, arg2 error) {
+	fake.closedMutex.Lock()
+	fake.closedArgsForCall = append(fake.closedArgsForCall, struct {
+		arg1 protocol.Connection
+		arg2 error
+	}{arg1, arg2})
+	stub := fake.ClosedStub
+	fake.recordInvocation("Closed", []interface{}{arg1, arg2})
+	fake.closedMutex.Unlock()
+	if stub != nil {
+		fake.ClosedStub(arg1, arg2)
+	}
+}
+
+func (fake *Model) ClosedCallCount() int {
+	fake.closedMutex.RLock()
+	defer fake.closedMutex.RUnlock()
+	return len(fake.closedArgsForCall)
+}
+
+func (fake *Model) ClosedCalls(stub func(protocol.Connection, error)) {
+	fake.closedMutex.Lock()
+	defer fake.closedMutex.Unlock()
+	fake.ClosedStub = stub
+}
+
+func (fake *Model) ClosedArgsForCall(i int) (protocol.Connection, error) {
+	fake.closedMutex.RLock()
+	defer fake.closedMutex.RUnlock()
+	argsForCall := fake.closedArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) ClusterConfig(arg1 protocol.DeviceID, arg2 protocol.ClusterConfig) error {
+	fake.clusterConfigMutex.Lock()
+	ret, specificReturn := fake.clusterConfigReturnsOnCall[len(fake.clusterConfigArgsForCall)]
+	fake.clusterConfigArgsForCall = append(fake.clusterConfigArgsForCall, struct {
+		arg1 protocol.DeviceID
+		arg2 protocol.ClusterConfig
+	}{arg1, arg2})
+	stub := fake.ClusterConfigStub
+	fakeReturns := fake.clusterConfigReturns
+	fake.recordInvocation("ClusterConfig", []interface{}{arg1, arg2})
+	fake.clusterConfigMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) ClusterConfigCallCount() int {
+	fake.clusterConfigMutex.RLock()
+	defer fake.clusterConfigMutex.RUnlock()
+	return len(fake.clusterConfigArgsForCall)
+}
+
+func (fake *Model) ClusterConfigCalls(stub func(protocol.DeviceID, protocol.ClusterConfig) error) {
+	fake.clusterConfigMutex.Lock()
+	defer fake.clusterConfigMutex.Unlock()
+	fake.ClusterConfigStub = stub
+}
+
+func (fake *Model) ClusterConfigArgsForCall(i int) (protocol.DeviceID, protocol.ClusterConfig) {
+	fake.clusterConfigMutex.RLock()
+	defer fake.clusterConfigMutex.RUnlock()
+	argsForCall := fake.clusterConfigArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) ClusterConfigReturns(result1 error) {
+	fake.clusterConfigMutex.Lock()
+	defer fake.clusterConfigMutex.Unlock()
+	fake.ClusterConfigStub = nil
+	fake.clusterConfigReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) ClusterConfigReturnsOnCall(i int, result1 error) {
+	fake.clusterConfigMutex.Lock()
+	defer fake.clusterConfigMutex.Unlock()
+	fake.ClusterConfigStub = nil
+	if fake.clusterConfigReturnsOnCall == nil {
+		fake.clusterConfigReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.clusterConfigReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) Completion(arg1 protocol.DeviceID, arg2 string) model.FolderCompletion {
+	fake.completionMutex.Lock()
+	ret, specificReturn := fake.completionReturnsOnCall[len(fake.completionArgsForCall)]
+	fake.completionArgsForCall = append(fake.completionArgsForCall, struct {
+		arg1 protocol.DeviceID
+		arg2 string
+	}{arg1, arg2})
+	stub := fake.CompletionStub
+	fakeReturns := fake.completionReturns
+	fake.recordInvocation("Completion", []interface{}{arg1, arg2})
+	fake.completionMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) CompletionCallCount() int {
+	fake.completionMutex.RLock()
+	defer fake.completionMutex.RUnlock()
+	return len(fake.completionArgsForCall)
+}
+
+func (fake *Model) CompletionCalls(stub func(protocol.DeviceID, string) model.FolderCompletion) {
+	fake.completionMutex.Lock()
+	defer fake.completionMutex.Unlock()
+	fake.CompletionStub = stub
+}
+
+func (fake *Model) CompletionArgsForCall(i int) (protocol.DeviceID, string) {
+	fake.completionMutex.RLock()
+	defer fake.completionMutex.RUnlock()
+	argsForCall := fake.completionArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) CompletionReturns(result1 model.FolderCompletion) {
+	fake.completionMutex.Lock()
+	defer fake.completionMutex.Unlock()
+	fake.CompletionStub = nil
+	fake.completionReturns = struct {
+		result1 model.FolderCompletion
+	}{result1}
+}
+
+func (fake *Model) CompletionReturnsOnCall(i int, result1 model.FolderCompletion) {
+	fake.completionMutex.Lock()
+	defer fake.completionMutex.Unlock()
+	fake.CompletionStub = nil
+	if fake.completionReturnsOnCall == nil {
+		fake.completionReturnsOnCall = make(map[int]struct {
+			result1 model.FolderCompletion
+		})
+	}
+	fake.completionReturnsOnCall[i] = struct {
+		result1 model.FolderCompletion
+	}{result1}
+}
+
+func (fake *Model) Connection(arg1 protocol.DeviceID) (protocol.Connection, bool) {
+	fake.connectionMutex.Lock()
+	ret, specificReturn := fake.connectionReturnsOnCall[len(fake.connectionArgsForCall)]
+	fake.connectionArgsForCall = append(fake.connectionArgsForCall, struct {
+		arg1 protocol.DeviceID
+	}{arg1})
+	stub := fake.ConnectionStub
+	fakeReturns := fake.connectionReturns
+	fake.recordInvocation("Connection", []interface{}{arg1})
+	fake.connectionMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) ConnectionCallCount() int {
+	fake.connectionMutex.RLock()
+	defer fake.connectionMutex.RUnlock()
+	return len(fake.connectionArgsForCall)
+}
+
+func (fake *Model) ConnectionCalls(stub func(protocol.DeviceID) (protocol.Connection, bool)) {
+	fake.connectionMutex.Lock()
+	defer fake.connectionMutex.Unlock()
+	fake.ConnectionStub = stub
+}
+
+func (fake *Model) ConnectionArgsForCall(i int) protocol.DeviceID {
+	fake.connectionMutex.RLock()
+	defer fake.connectionMutex.RUnlock()
+	argsForCall := fake.connectionArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) ConnectionReturns(result1 protocol.Connection, result2 bool) {
+	fake.connectionMutex.Lock()
+	defer fake.connectionMutex.Unlock()
+	fake.ConnectionStub = nil
+	fake.connectionReturns = struct {
+		result1 protocol.Connection
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Model) ConnectionReturnsOnCall(i int, result1 protocol.Connection, result2 bool) {
+	fake.connectionMutex.Lock()
+	defer fake.connectionMutex.Unlock()
+	fake.ConnectionStub = nil
+	if fake.connectionReturnsOnCall == nil {
+		fake.connectionReturnsOnCall = make(map[int]struct {
+			result1 protocol.Connection
+			result2 bool
+		})
+	}
+	fake.connectionReturnsOnCall[i] = struct {
+		result1 protocol.Connection
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Model) ConnectionStats() map[string]interface{} {
+	fake.connectionStatsMutex.Lock()
+	ret, specificReturn := fake.connectionStatsReturnsOnCall[len(fake.connectionStatsArgsForCall)]
+	fake.connectionStatsArgsForCall = append(fake.connectionStatsArgsForCall, struct {
+	}{})
+	stub := fake.ConnectionStatsStub
+	fakeReturns := fake.connectionStatsReturns
+	fake.recordInvocation("ConnectionStats", []interface{}{})
+	fake.connectionStatsMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) ConnectionStatsCallCount() int {
+	fake.connectionStatsMutex.RLock()
+	defer fake.connectionStatsMutex.RUnlock()
+	return len(fake.connectionStatsArgsForCall)
+}
+
+func (fake *Model) ConnectionStatsCalls(stub func() map[string]interface{}) {
+	fake.connectionStatsMutex.Lock()
+	defer fake.connectionStatsMutex.Unlock()
+	fake.ConnectionStatsStub = stub
+}
+
+func (fake *Model) ConnectionStatsReturns(result1 map[string]interface{}) {
+	fake.connectionStatsMutex.Lock()
+	defer fake.connectionStatsMutex.Unlock()
+	fake.ConnectionStatsStub = nil
+	fake.connectionStatsReturns = struct {
+		result1 map[string]interface{}
+	}{result1}
+}
+
+func (fake *Model) ConnectionStatsReturnsOnCall(i int, result1 map[string]interface{}) {
+	fake.connectionStatsMutex.Lock()
+	defer fake.connectionStatsMutex.Unlock()
+	fake.ConnectionStatsStub = nil
+	if fake.connectionStatsReturnsOnCall == nil {
+		fake.connectionStatsReturnsOnCall = make(map[int]struct {
+			result1 map[string]interface{}
+		})
+	}
+	fake.connectionStatsReturnsOnCall[i] = struct {
+		result1 map[string]interface{}
+	}{result1}
+}
+
+func (fake *Model) CurrentFolderFile(arg1 string, arg2 string) (protocol.FileInfo, bool) {
+	fake.currentFolderFileMutex.Lock()
+	ret, specificReturn := fake.currentFolderFileReturnsOnCall[len(fake.currentFolderFileArgsForCall)]
+	fake.currentFolderFileArgsForCall = append(fake.currentFolderFileArgsForCall, struct {
+		arg1 string
+		arg2 string
+	}{arg1, arg2})
+	stub := fake.CurrentFolderFileStub
+	fakeReturns := fake.currentFolderFileReturns
+	fake.recordInvocation("CurrentFolderFile", []interface{}{arg1, arg2})
+	fake.currentFolderFileMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) CurrentFolderFileCallCount() int {
+	fake.currentFolderFileMutex.RLock()
+	defer fake.currentFolderFileMutex.RUnlock()
+	return len(fake.currentFolderFileArgsForCall)
+}
+
+func (fake *Model) CurrentFolderFileCalls(stub func(string, string) (protocol.FileInfo, bool)) {
+	fake.currentFolderFileMutex.Lock()
+	defer fake.currentFolderFileMutex.Unlock()
+	fake.CurrentFolderFileStub = stub
+}
+
+func (fake *Model) CurrentFolderFileArgsForCall(i int) (string, string) {
+	fake.currentFolderFileMutex.RLock()
+	defer fake.currentFolderFileMutex.RUnlock()
+	argsForCall := fake.currentFolderFileArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) CurrentFolderFileReturns(result1 protocol.FileInfo, result2 bool) {
+	fake.currentFolderFileMutex.Lock()
+	defer fake.currentFolderFileMutex.Unlock()
+	fake.CurrentFolderFileStub = nil
+	fake.currentFolderFileReturns = struct {
+		result1 protocol.FileInfo
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Model) CurrentFolderFileReturnsOnCall(i int, result1 protocol.FileInfo, result2 bool) {
+	fake.currentFolderFileMutex.Lock()
+	defer fake.currentFolderFileMutex.Unlock()
+	fake.CurrentFolderFileStub = nil
+	if fake.currentFolderFileReturnsOnCall == nil {
+		fake.currentFolderFileReturnsOnCall = make(map[int]struct {
+			result1 protocol.FileInfo
+			result2 bool
+		})
+	}
+	fake.currentFolderFileReturnsOnCall[i] = struct {
+		result1 protocol.FileInfo
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Model) CurrentGlobalFile(arg1 string, arg2 string) (protocol.FileInfo, bool) {
+	fake.currentGlobalFileMutex.Lock()
+	ret, specificReturn := fake.currentGlobalFileReturnsOnCall[len(fake.currentGlobalFileArgsForCall)]
+	fake.currentGlobalFileArgsForCall = append(fake.currentGlobalFileArgsForCall, struct {
+		arg1 string
+		arg2 string
+	}{arg1, arg2})
+	stub := fake.CurrentGlobalFileStub
+	fakeReturns := fake.currentGlobalFileReturns
+	fake.recordInvocation("CurrentGlobalFile", []interface{}{arg1, arg2})
+	fake.currentGlobalFileMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) CurrentGlobalFileCallCount() int {
+	fake.currentGlobalFileMutex.RLock()
+	defer fake.currentGlobalFileMutex.RUnlock()
+	return len(fake.currentGlobalFileArgsForCall)
+}
+
+func (fake *Model) CurrentGlobalFileCalls(stub func(string, string) (protocol.FileInfo, bool)) {
+	fake.currentGlobalFileMutex.Lock()
+	defer fake.currentGlobalFileMutex.Unlock()
+	fake.CurrentGlobalFileStub = stub
+}
+
+func (fake *Model) CurrentGlobalFileArgsForCall(i int) (string, string) {
+	fake.currentGlobalFileMutex.RLock()
+	defer fake.currentGlobalFileMutex.RUnlock()
+	argsForCall := fake.currentGlobalFileArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) CurrentGlobalFileReturns(result1 protocol.FileInfo, result2 bool) {
+	fake.currentGlobalFileMutex.Lock()
+	defer fake.currentGlobalFileMutex.Unlock()
+	fake.CurrentGlobalFileStub = nil
+	fake.currentGlobalFileReturns = struct {
+		result1 protocol.FileInfo
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Model) CurrentGlobalFileReturnsOnCall(i int, result1 protocol.FileInfo, result2 bool) {
+	fake.currentGlobalFileMutex.Lock()
+	defer fake.currentGlobalFileMutex.Unlock()
+	fake.CurrentGlobalFileStub = nil
+	if fake.currentGlobalFileReturnsOnCall == nil {
+		fake.currentGlobalFileReturnsOnCall = make(map[int]struct {
+			result1 protocol.FileInfo
+			result2 bool
+		})
+	}
+	fake.currentGlobalFileReturnsOnCall[i] = struct {
+		result1 protocol.FileInfo
+		result2 bool
+	}{result1, result2}
+}
+
+func (fake *Model) CurrentIgnores(arg1 string) ([]string, []string, error) {
+	fake.currentIgnoresMutex.Lock()
+	ret, specificReturn := fake.currentIgnoresReturnsOnCall[len(fake.currentIgnoresArgsForCall)]
+	fake.currentIgnoresArgsForCall = append(fake.currentIgnoresArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.CurrentIgnoresStub
+	fakeReturns := fake.currentIgnoresReturns
+	fake.recordInvocation("CurrentIgnores", []interface{}{arg1})
+	fake.currentIgnoresMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2, ret.result3
+	}
+	return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
+}
+
+func (fake *Model) CurrentIgnoresCallCount() int {
+	fake.currentIgnoresMutex.RLock()
+	defer fake.currentIgnoresMutex.RUnlock()
+	return len(fake.currentIgnoresArgsForCall)
+}
+
+func (fake *Model) CurrentIgnoresCalls(stub func(string) ([]string, []string, error)) {
+	fake.currentIgnoresMutex.Lock()
+	defer fake.currentIgnoresMutex.Unlock()
+	fake.CurrentIgnoresStub = stub
+}
+
+func (fake *Model) CurrentIgnoresArgsForCall(i int) string {
+	fake.currentIgnoresMutex.RLock()
+	defer fake.currentIgnoresMutex.RUnlock()
+	argsForCall := fake.currentIgnoresArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) CurrentIgnoresReturns(result1 []string, result2 []string, result3 error) {
+	fake.currentIgnoresMutex.Lock()
+	defer fake.currentIgnoresMutex.Unlock()
+	fake.CurrentIgnoresStub = nil
+	fake.currentIgnoresReturns = struct {
+		result1 []string
+		result2 []string
+		result3 error
+	}{result1, result2, result3}
+}
+
+func (fake *Model) CurrentIgnoresReturnsOnCall(i int, result1 []string, result2 []string, result3 error) {
+	fake.currentIgnoresMutex.Lock()
+	defer fake.currentIgnoresMutex.Unlock()
+	fake.CurrentIgnoresStub = nil
+	if fake.currentIgnoresReturnsOnCall == nil {
+		fake.currentIgnoresReturnsOnCall = make(map[int]struct {
+			result1 []string
+			result2 []string
+			result3 error
+		})
+	}
+	fake.currentIgnoresReturnsOnCall[i] = struct {
+		result1 []string
+		result2 []string
+		result3 error
+	}{result1, result2, result3}
+}
+
+func (fake *Model) DBSnapshot(arg1 string) (*db.Snapshot, error) {
+	fake.dBSnapshotMutex.Lock()
+	ret, specificReturn := fake.dBSnapshotReturnsOnCall[len(fake.dBSnapshotArgsForCall)]
+	fake.dBSnapshotArgsForCall = append(fake.dBSnapshotArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.DBSnapshotStub
+	fakeReturns := fake.dBSnapshotReturns
+	fake.recordInvocation("DBSnapshot", []interface{}{arg1})
+	fake.dBSnapshotMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) DBSnapshotCallCount() int {
+	fake.dBSnapshotMutex.RLock()
+	defer fake.dBSnapshotMutex.RUnlock()
+	return len(fake.dBSnapshotArgsForCall)
+}
+
+func (fake *Model) DBSnapshotCalls(stub func(string) (*db.Snapshot, error)) {
+	fake.dBSnapshotMutex.Lock()
+	defer fake.dBSnapshotMutex.Unlock()
+	fake.DBSnapshotStub = stub
+}
+
+func (fake *Model) DBSnapshotArgsForCall(i int) string {
+	fake.dBSnapshotMutex.RLock()
+	defer fake.dBSnapshotMutex.RUnlock()
+	argsForCall := fake.dBSnapshotArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) DBSnapshotReturns(result1 *db.Snapshot, result2 error) {
+	fake.dBSnapshotMutex.Lock()
+	defer fake.dBSnapshotMutex.Unlock()
+	fake.DBSnapshotStub = nil
+	fake.dBSnapshotReturns = struct {
+		result1 *db.Snapshot
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) DBSnapshotReturnsOnCall(i int, result1 *db.Snapshot, result2 error) {
+	fake.dBSnapshotMutex.Lock()
+	defer fake.dBSnapshotMutex.Unlock()
+	fake.DBSnapshotStub = nil
+	if fake.dBSnapshotReturnsOnCall == nil {
+		fake.dBSnapshotReturnsOnCall = make(map[int]struct {
+			result1 *db.Snapshot
+			result2 error
+		})
+	}
+	fake.dBSnapshotReturnsOnCall[i] = struct {
+		result1 *db.Snapshot
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) DelayScan(arg1 string, arg2 time.Duration) {
+	fake.delayScanMutex.Lock()
+	fake.delayScanArgsForCall = append(fake.delayScanArgsForCall, struct {
+		arg1 string
+		arg2 time.Duration
+	}{arg1, arg2})
+	stub := fake.DelayScanStub
+	fake.recordInvocation("DelayScan", []interface{}{arg1, arg2})
+	fake.delayScanMutex.Unlock()
+	if stub != nil {
+		fake.DelayScanStub(arg1, arg2)
+	}
+}
+
+func (fake *Model) DelayScanCallCount() int {
+	fake.delayScanMutex.RLock()
+	defer fake.delayScanMutex.RUnlock()
+	return len(fake.delayScanArgsForCall)
+}
+
+func (fake *Model) DelayScanCalls(stub func(string, time.Duration)) {
+	fake.delayScanMutex.Lock()
+	defer fake.delayScanMutex.Unlock()
+	fake.DelayScanStub = stub
+}
+
+func (fake *Model) DelayScanArgsForCall(i int) (string, time.Duration) {
+	fake.delayScanMutex.RLock()
+	defer fake.delayScanMutex.RUnlock()
+	argsForCall := fake.delayScanArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) DeviceStatistics() (map[protocol.DeviceID]stats.DeviceStatistics, error) {
+	fake.deviceStatisticsMutex.Lock()
+	ret, specificReturn := fake.deviceStatisticsReturnsOnCall[len(fake.deviceStatisticsArgsForCall)]
+	fake.deviceStatisticsArgsForCall = append(fake.deviceStatisticsArgsForCall, struct {
+	}{})
+	stub := fake.DeviceStatisticsStub
+	fakeReturns := fake.deviceStatisticsReturns
+	fake.recordInvocation("DeviceStatistics", []interface{}{})
+	fake.deviceStatisticsMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) DeviceStatisticsCallCount() int {
+	fake.deviceStatisticsMutex.RLock()
+	defer fake.deviceStatisticsMutex.RUnlock()
+	return len(fake.deviceStatisticsArgsForCall)
+}
+
+func (fake *Model) DeviceStatisticsCalls(stub func() (map[protocol.DeviceID]stats.DeviceStatistics, error)) {
+	fake.deviceStatisticsMutex.Lock()
+	defer fake.deviceStatisticsMutex.Unlock()
+	fake.DeviceStatisticsStub = stub
+}
+
+func (fake *Model) DeviceStatisticsReturns(result1 map[protocol.DeviceID]stats.DeviceStatistics, result2 error) {
+	fake.deviceStatisticsMutex.Lock()
+	defer fake.deviceStatisticsMutex.Unlock()
+	fake.DeviceStatisticsStub = nil
+	fake.deviceStatisticsReturns = struct {
+		result1 map[protocol.DeviceID]stats.DeviceStatistics
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) DeviceStatisticsReturnsOnCall(i int, result1 map[protocol.DeviceID]stats.DeviceStatistics, result2 error) {
+	fake.deviceStatisticsMutex.Lock()
+	defer fake.deviceStatisticsMutex.Unlock()
+	fake.DeviceStatisticsStub = nil
+	if fake.deviceStatisticsReturnsOnCall == nil {
+		fake.deviceStatisticsReturnsOnCall = make(map[int]struct {
+			result1 map[protocol.DeviceID]stats.DeviceStatistics
+			result2 error
+		})
+	}
+	fake.deviceStatisticsReturnsOnCall[i] = struct {
+		result1 map[protocol.DeviceID]stats.DeviceStatistics
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) DownloadProgress(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.FileDownloadProgressUpdate) error {
+	var arg3Copy []protocol.FileDownloadProgressUpdate
+	if arg3 != nil {
+		arg3Copy = make([]protocol.FileDownloadProgressUpdate, len(arg3))
+		copy(arg3Copy, arg3)
+	}
+	fake.downloadProgressMutex.Lock()
+	ret, specificReturn := fake.downloadProgressReturnsOnCall[len(fake.downloadProgressArgsForCall)]
+	fake.downloadProgressArgsForCall = append(fake.downloadProgressArgsForCall, struct {
+		arg1 protocol.DeviceID
+		arg2 string
+		arg3 []protocol.FileDownloadProgressUpdate
+	}{arg1, arg2, arg3Copy})
+	stub := fake.DownloadProgressStub
+	fakeReturns := fake.downloadProgressReturns
+	fake.recordInvocation("DownloadProgress", []interface{}{arg1, arg2, arg3Copy})
+	fake.downloadProgressMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) DownloadProgressCallCount() int {
+	fake.downloadProgressMutex.RLock()
+	defer fake.downloadProgressMutex.RUnlock()
+	return len(fake.downloadProgressArgsForCall)
+}
+
+func (fake *Model) DownloadProgressCalls(stub func(protocol.DeviceID, string, []protocol.FileDownloadProgressUpdate) error) {
+	fake.downloadProgressMutex.Lock()
+	defer fake.downloadProgressMutex.Unlock()
+	fake.DownloadProgressStub = stub
+}
+
+func (fake *Model) DownloadProgressArgsForCall(i int) (protocol.DeviceID, string, []protocol.FileDownloadProgressUpdate) {
+	fake.downloadProgressMutex.RLock()
+	defer fake.downloadProgressMutex.RUnlock()
+	argsForCall := fake.downloadProgressArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Model) DownloadProgressReturns(result1 error) {
+	fake.downloadProgressMutex.Lock()
+	defer fake.downloadProgressMutex.Unlock()
+	fake.DownloadProgressStub = nil
+	fake.downloadProgressReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) DownloadProgressReturnsOnCall(i int, result1 error) {
+	fake.downloadProgressMutex.Lock()
+	defer fake.downloadProgressMutex.Unlock()
+	fake.DownloadProgressStub = nil
+	if fake.downloadProgressReturnsOnCall == nil {
+		fake.downloadProgressReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.downloadProgressReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) FolderErrors(arg1 string) ([]model.FileError, error) {
+	fake.folderErrorsMutex.Lock()
+	ret, specificReturn := fake.folderErrorsReturnsOnCall[len(fake.folderErrorsArgsForCall)]
+	fake.folderErrorsArgsForCall = append(fake.folderErrorsArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.FolderErrorsStub
+	fakeReturns := fake.folderErrorsReturns
+	fake.recordInvocation("FolderErrors", []interface{}{arg1})
+	fake.folderErrorsMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) FolderErrorsCallCount() int {
+	fake.folderErrorsMutex.RLock()
+	defer fake.folderErrorsMutex.RUnlock()
+	return len(fake.folderErrorsArgsForCall)
+}
+
+func (fake *Model) FolderErrorsCalls(stub func(string) ([]model.FileError, error)) {
+	fake.folderErrorsMutex.Lock()
+	defer fake.folderErrorsMutex.Unlock()
+	fake.FolderErrorsStub = stub
+}
+
+func (fake *Model) FolderErrorsArgsForCall(i int) string {
+	fake.folderErrorsMutex.RLock()
+	defer fake.folderErrorsMutex.RUnlock()
+	argsForCall := fake.folderErrorsArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) FolderErrorsReturns(result1 []model.FileError, result2 error) {
+	fake.folderErrorsMutex.Lock()
+	defer fake.folderErrorsMutex.Unlock()
+	fake.FolderErrorsStub = nil
+	fake.folderErrorsReturns = struct {
+		result1 []model.FileError
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) FolderErrorsReturnsOnCall(i int, result1 []model.FileError, result2 error) {
+	fake.folderErrorsMutex.Lock()
+	defer fake.folderErrorsMutex.Unlock()
+	fake.FolderErrorsStub = nil
+	if fake.folderErrorsReturnsOnCall == nil {
+		fake.folderErrorsReturnsOnCall = make(map[int]struct {
+			result1 []model.FileError
+			result2 error
+		})
+	}
+	fake.folderErrorsReturnsOnCall[i] = struct {
+		result1 []model.FileError
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) FolderProgressBytesCompleted(arg1 string) int64 {
+	fake.folderProgressBytesCompletedMutex.Lock()
+	ret, specificReturn := fake.folderProgressBytesCompletedReturnsOnCall[len(fake.folderProgressBytesCompletedArgsForCall)]
+	fake.folderProgressBytesCompletedArgsForCall = append(fake.folderProgressBytesCompletedArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.FolderProgressBytesCompletedStub
+	fakeReturns := fake.folderProgressBytesCompletedReturns
+	fake.recordInvocation("FolderProgressBytesCompleted", []interface{}{arg1})
+	fake.folderProgressBytesCompletedMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) FolderProgressBytesCompletedCallCount() int {
+	fake.folderProgressBytesCompletedMutex.RLock()
+	defer fake.folderProgressBytesCompletedMutex.RUnlock()
+	return len(fake.folderProgressBytesCompletedArgsForCall)
+}
+
+func (fake *Model) FolderProgressBytesCompletedCalls(stub func(string) int64) {
+	fake.folderProgressBytesCompletedMutex.Lock()
+	defer fake.folderProgressBytesCompletedMutex.Unlock()
+	fake.FolderProgressBytesCompletedStub = stub
+}
+
+func (fake *Model) FolderProgressBytesCompletedArgsForCall(i int) string {
+	fake.folderProgressBytesCompletedMutex.RLock()
+	defer fake.folderProgressBytesCompletedMutex.RUnlock()
+	argsForCall := fake.folderProgressBytesCompletedArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) FolderProgressBytesCompletedReturns(result1 int64) {
+	fake.folderProgressBytesCompletedMutex.Lock()
+	defer fake.folderProgressBytesCompletedMutex.Unlock()
+	fake.FolderProgressBytesCompletedStub = nil
+	fake.folderProgressBytesCompletedReturns = struct {
+		result1 int64
+	}{result1}
+}
+
+func (fake *Model) FolderProgressBytesCompletedReturnsOnCall(i int, result1 int64) {
+	fake.folderProgressBytesCompletedMutex.Lock()
+	defer fake.folderProgressBytesCompletedMutex.Unlock()
+	fake.FolderProgressBytesCompletedStub = nil
+	if fake.folderProgressBytesCompletedReturnsOnCall == nil {
+		fake.folderProgressBytesCompletedReturnsOnCall = make(map[int]struct {
+			result1 int64
+		})
+	}
+	fake.folderProgressBytesCompletedReturnsOnCall[i] = struct {
+		result1 int64
+	}{result1}
+}
+
+func (fake *Model) FolderStatistics() (map[string]stats.FolderStatistics, error) {
+	fake.folderStatisticsMutex.Lock()
+	ret, specificReturn := fake.folderStatisticsReturnsOnCall[len(fake.folderStatisticsArgsForCall)]
+	fake.folderStatisticsArgsForCall = append(fake.folderStatisticsArgsForCall, struct {
+	}{})
+	stub := fake.FolderStatisticsStub
+	fakeReturns := fake.folderStatisticsReturns
+	fake.recordInvocation("FolderStatistics", []interface{}{})
+	fake.folderStatisticsMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) FolderStatisticsCallCount() int {
+	fake.folderStatisticsMutex.RLock()
+	defer fake.folderStatisticsMutex.RUnlock()
+	return len(fake.folderStatisticsArgsForCall)
+}
+
+func (fake *Model) FolderStatisticsCalls(stub func() (map[string]stats.FolderStatistics, error)) {
+	fake.folderStatisticsMutex.Lock()
+	defer fake.folderStatisticsMutex.Unlock()
+	fake.FolderStatisticsStub = stub
+}
+
+func (fake *Model) FolderStatisticsReturns(result1 map[string]stats.FolderStatistics, result2 error) {
+	fake.folderStatisticsMutex.Lock()
+	defer fake.folderStatisticsMutex.Unlock()
+	fake.FolderStatisticsStub = nil
+	fake.folderStatisticsReturns = struct {
+		result1 map[string]stats.FolderStatistics
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) FolderStatisticsReturnsOnCall(i int, result1 map[string]stats.FolderStatistics, result2 error) {
+	fake.folderStatisticsMutex.Lock()
+	defer fake.folderStatisticsMutex.Unlock()
+	fake.FolderStatisticsStub = nil
+	if fake.folderStatisticsReturnsOnCall == nil {
+		fake.folderStatisticsReturnsOnCall = make(map[int]struct {
+			result1 map[string]stats.FolderStatistics
+			result2 error
+		})
+	}
+	fake.folderStatisticsReturnsOnCall[i] = struct {
+		result1 map[string]stats.FolderStatistics
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) GetFolderVersions(arg1 string) (map[string][]versioner.FileVersion, error) {
+	fake.getFolderVersionsMutex.Lock()
+	ret, specificReturn := fake.getFolderVersionsReturnsOnCall[len(fake.getFolderVersionsArgsForCall)]
+	fake.getFolderVersionsArgsForCall = append(fake.getFolderVersionsArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.GetFolderVersionsStub
+	fakeReturns := fake.getFolderVersionsReturns
+	fake.recordInvocation("GetFolderVersions", []interface{}{arg1})
+	fake.getFolderVersionsMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) GetFolderVersionsCallCount() int {
+	fake.getFolderVersionsMutex.RLock()
+	defer fake.getFolderVersionsMutex.RUnlock()
+	return len(fake.getFolderVersionsArgsForCall)
+}
+
+func (fake *Model) GetFolderVersionsCalls(stub func(string) (map[string][]versioner.FileVersion, error)) {
+	fake.getFolderVersionsMutex.Lock()
+	defer fake.getFolderVersionsMutex.Unlock()
+	fake.GetFolderVersionsStub = stub
+}
+
+func (fake *Model) GetFolderVersionsArgsForCall(i int) string {
+	fake.getFolderVersionsMutex.RLock()
+	defer fake.getFolderVersionsMutex.RUnlock()
+	argsForCall := fake.getFolderVersionsArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) GetFolderVersionsReturns(result1 map[string][]versioner.FileVersion, result2 error) {
+	fake.getFolderVersionsMutex.Lock()
+	defer fake.getFolderVersionsMutex.Unlock()
+	fake.GetFolderVersionsStub = nil
+	fake.getFolderVersionsReturns = struct {
+		result1 map[string][]versioner.FileVersion
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) GetFolderVersionsReturnsOnCall(i int, result1 map[string][]versioner.FileVersion, result2 error) {
+	fake.getFolderVersionsMutex.Lock()
+	defer fake.getFolderVersionsMutex.Unlock()
+	fake.GetFolderVersionsStub = nil
+	if fake.getFolderVersionsReturnsOnCall == nil {
+		fake.getFolderVersionsReturnsOnCall = make(map[int]struct {
+			result1 map[string][]versioner.FileVersion
+			result2 error
+		})
+	}
+	fake.getFolderVersionsReturnsOnCall[i] = struct {
+		result1 map[string][]versioner.FileVersion
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) GetHello(arg1 protocol.DeviceID) protocol.HelloIntf {
+	fake.getHelloMutex.Lock()
+	ret, specificReturn := fake.getHelloReturnsOnCall[len(fake.getHelloArgsForCall)]
+	fake.getHelloArgsForCall = append(fake.getHelloArgsForCall, struct {
+		arg1 protocol.DeviceID
+	}{arg1})
+	stub := fake.GetHelloStub
+	fakeReturns := fake.getHelloReturns
+	fake.recordInvocation("GetHello", []interface{}{arg1})
+	fake.getHelloMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) GetHelloCallCount() int {
+	fake.getHelloMutex.RLock()
+	defer fake.getHelloMutex.RUnlock()
+	return len(fake.getHelloArgsForCall)
+}
+
+func (fake *Model) GetHelloCalls(stub func(protocol.DeviceID) protocol.HelloIntf) {
+	fake.getHelloMutex.Lock()
+	defer fake.getHelloMutex.Unlock()
+	fake.GetHelloStub = stub
+}
+
+func (fake *Model) GetHelloArgsForCall(i int) protocol.DeviceID {
+	fake.getHelloMutex.RLock()
+	defer fake.getHelloMutex.RUnlock()
+	argsForCall := fake.getHelloArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) GetHelloReturns(result1 protocol.HelloIntf) {
+	fake.getHelloMutex.Lock()
+	defer fake.getHelloMutex.Unlock()
+	fake.GetHelloStub = nil
+	fake.getHelloReturns = struct {
+		result1 protocol.HelloIntf
+	}{result1}
+}
+
+func (fake *Model) GetHelloReturnsOnCall(i int, result1 protocol.HelloIntf) {
+	fake.getHelloMutex.Lock()
+	defer fake.getHelloMutex.Unlock()
+	fake.GetHelloStub = nil
+	if fake.getHelloReturnsOnCall == nil {
+		fake.getHelloReturnsOnCall = make(map[int]struct {
+			result1 protocol.HelloIntf
+		})
+	}
+	fake.getHelloReturnsOnCall[i] = struct {
+		result1 protocol.HelloIntf
+	}{result1}
+}
+
+func (fake *Model) GlobalDirectoryTree(arg1 string, arg2 string, arg3 int, arg4 bool) ([]*model.TreeEntry, error) {
+	fake.globalDirectoryTreeMutex.Lock()
+	ret, specificReturn := fake.globalDirectoryTreeReturnsOnCall[len(fake.globalDirectoryTreeArgsForCall)]
+	fake.globalDirectoryTreeArgsForCall = append(fake.globalDirectoryTreeArgsForCall, struct {
+		arg1 string
+		arg2 string
+		arg3 int
+		arg4 bool
+	}{arg1, arg2, arg3, arg4})
+	stub := fake.GlobalDirectoryTreeStub
+	fakeReturns := fake.globalDirectoryTreeReturns
+	fake.recordInvocation("GlobalDirectoryTree", []interface{}{arg1, arg2, arg3, arg4})
+	fake.globalDirectoryTreeMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3, arg4)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) GlobalDirectoryTreeCallCount() int {
+	fake.globalDirectoryTreeMutex.RLock()
+	defer fake.globalDirectoryTreeMutex.RUnlock()
+	return len(fake.globalDirectoryTreeArgsForCall)
+}
+
+func (fake *Model) GlobalDirectoryTreeCalls(stub func(string, string, int, bool) ([]*model.TreeEntry, error)) {
+	fake.globalDirectoryTreeMutex.Lock()
+	defer fake.globalDirectoryTreeMutex.Unlock()
+	fake.GlobalDirectoryTreeStub = stub
+}
+
+func (fake *Model) GlobalDirectoryTreeArgsForCall(i int) (string, string, int, bool) {
+	fake.globalDirectoryTreeMutex.RLock()
+	defer fake.globalDirectoryTreeMutex.RUnlock()
+	argsForCall := fake.globalDirectoryTreeArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
+}
+
+func (fake *Model) GlobalDirectoryTreeReturns(result1 []*model.TreeEntry, result2 error) {
+	fake.globalDirectoryTreeMutex.Lock()
+	defer fake.globalDirectoryTreeMutex.Unlock()
+	fake.GlobalDirectoryTreeStub = nil
+	fake.globalDirectoryTreeReturns = struct {
+		result1 []*model.TreeEntry
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) GlobalDirectoryTreeReturnsOnCall(i int, result1 []*model.TreeEntry, result2 error) {
+	fake.globalDirectoryTreeMutex.Lock()
+	defer fake.globalDirectoryTreeMutex.Unlock()
+	fake.GlobalDirectoryTreeStub = nil
+	if fake.globalDirectoryTreeReturnsOnCall == nil {
+		fake.globalDirectoryTreeReturnsOnCall = make(map[int]struct {
+			result1 []*model.TreeEntry
+			result2 error
+		})
+	}
+	fake.globalDirectoryTreeReturnsOnCall[i] = struct {
+		result1 []*model.TreeEntry
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) Index(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.FileInfo) error {
+	var arg3Copy []protocol.FileInfo
+	if arg3 != nil {
+		arg3Copy = make([]protocol.FileInfo, len(arg3))
+		copy(arg3Copy, arg3)
+	}
+	fake.indexMutex.Lock()
+	ret, specificReturn := fake.indexReturnsOnCall[len(fake.indexArgsForCall)]
+	fake.indexArgsForCall = append(fake.indexArgsForCall, struct {
+		arg1 protocol.DeviceID
+		arg2 string
+		arg3 []protocol.FileInfo
+	}{arg1, arg2, arg3Copy})
+	stub := fake.IndexStub
+	fakeReturns := fake.indexReturns
+	fake.recordInvocation("Index", []interface{}{arg1, arg2, arg3Copy})
+	fake.indexMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) IndexCallCount() int {
+	fake.indexMutex.RLock()
+	defer fake.indexMutex.RUnlock()
+	return len(fake.indexArgsForCall)
+}
+
+func (fake *Model) IndexCalls(stub func(protocol.DeviceID, string, []protocol.FileInfo) error) {
+	fake.indexMutex.Lock()
+	defer fake.indexMutex.Unlock()
+	fake.IndexStub = stub
+}
+
+func (fake *Model) IndexArgsForCall(i int) (protocol.DeviceID, string, []protocol.FileInfo) {
+	fake.indexMutex.RLock()
+	defer fake.indexMutex.RUnlock()
+	argsForCall := fake.indexArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Model) IndexReturns(result1 error) {
+	fake.indexMutex.Lock()
+	defer fake.indexMutex.Unlock()
+	fake.IndexStub = nil
+	fake.indexReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) IndexReturnsOnCall(i int, result1 error) {
+	fake.indexMutex.Lock()
+	defer fake.indexMutex.Unlock()
+	fake.IndexStub = nil
+	if fake.indexReturnsOnCall == nil {
+		fake.indexReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.indexReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) IndexUpdate(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.FileInfo) error {
+	var arg3Copy []protocol.FileInfo
+	if arg3 != nil {
+		arg3Copy = make([]protocol.FileInfo, len(arg3))
+		copy(arg3Copy, arg3)
+	}
+	fake.indexUpdateMutex.Lock()
+	ret, specificReturn := fake.indexUpdateReturnsOnCall[len(fake.indexUpdateArgsForCall)]
+	fake.indexUpdateArgsForCall = append(fake.indexUpdateArgsForCall, struct {
+		arg1 protocol.DeviceID
+		arg2 string
+		arg3 []protocol.FileInfo
+	}{arg1, arg2, arg3Copy})
+	stub := fake.IndexUpdateStub
+	fakeReturns := fake.indexUpdateReturns
+	fake.recordInvocation("IndexUpdate", []interface{}{arg1, arg2, arg3Copy})
+	fake.indexUpdateMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) IndexUpdateCallCount() int {
+	fake.indexUpdateMutex.RLock()
+	defer fake.indexUpdateMutex.RUnlock()
+	return len(fake.indexUpdateArgsForCall)
+}
+
+func (fake *Model) IndexUpdateCalls(stub func(protocol.DeviceID, string, []protocol.FileInfo) error) {
+	fake.indexUpdateMutex.Lock()
+	defer fake.indexUpdateMutex.Unlock()
+	fake.IndexUpdateStub = stub
+}
+
+func (fake *Model) IndexUpdateArgsForCall(i int) (protocol.DeviceID, string, []protocol.FileInfo) {
+	fake.indexUpdateMutex.RLock()
+	defer fake.indexUpdateMutex.RUnlock()
+	argsForCall := fake.indexUpdateArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Model) IndexUpdateReturns(result1 error) {
+	fake.indexUpdateMutex.Lock()
+	defer fake.indexUpdateMutex.Unlock()
+	fake.IndexUpdateStub = nil
+	fake.indexUpdateReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) IndexUpdateReturnsOnCall(i int, result1 error) {
+	fake.indexUpdateMutex.Lock()
+	defer fake.indexUpdateMutex.Unlock()
+	fake.IndexUpdateStub = nil
+	if fake.indexUpdateReturnsOnCall == nil {
+		fake.indexUpdateReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.indexUpdateReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) LoadIgnores(arg1 string) ([]string, []string, error) {
+	fake.loadIgnoresMutex.Lock()
+	ret, specificReturn := fake.loadIgnoresReturnsOnCall[len(fake.loadIgnoresArgsForCall)]
+	fake.loadIgnoresArgsForCall = append(fake.loadIgnoresArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.LoadIgnoresStub
+	fakeReturns := fake.loadIgnoresReturns
+	fake.recordInvocation("LoadIgnores", []interface{}{arg1})
+	fake.loadIgnoresMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2, ret.result3
+	}
+	return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
+}
+
+func (fake *Model) LoadIgnoresCallCount() int {
+	fake.loadIgnoresMutex.RLock()
+	defer fake.loadIgnoresMutex.RUnlock()
+	return len(fake.loadIgnoresArgsForCall)
+}
+
+func (fake *Model) LoadIgnoresCalls(stub func(string) ([]string, []string, error)) {
+	fake.loadIgnoresMutex.Lock()
+	defer fake.loadIgnoresMutex.Unlock()
+	fake.LoadIgnoresStub = stub
+}
+
+func (fake *Model) LoadIgnoresArgsForCall(i int) string {
+	fake.loadIgnoresMutex.RLock()
+	defer fake.loadIgnoresMutex.RUnlock()
+	argsForCall := fake.loadIgnoresArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) LoadIgnoresReturns(result1 []string, result2 []string, result3 error) {
+	fake.loadIgnoresMutex.Lock()
+	defer fake.loadIgnoresMutex.Unlock()
+	fake.LoadIgnoresStub = nil
+	fake.loadIgnoresReturns = struct {
+		result1 []string
+		result2 []string
+		result3 error
+	}{result1, result2, result3}
+}
+
+func (fake *Model) LoadIgnoresReturnsOnCall(i int, result1 []string, result2 []string, result3 error) {
+	fake.loadIgnoresMutex.Lock()
+	defer fake.loadIgnoresMutex.Unlock()
+	fake.LoadIgnoresStub = nil
+	if fake.loadIgnoresReturnsOnCall == nil {
+		fake.loadIgnoresReturnsOnCall = make(map[int]struct {
+			result1 []string
+			result2 []string
+			result3 error
+		})
+	}
+	fake.loadIgnoresReturnsOnCall[i] = struct {
+		result1 []string
+		result2 []string
+		result3 error
+	}{result1, result2, result3}
+}
+
+func (fake *Model) LocalChangedFolderFiles(arg1 string, arg2 int, arg3 int) ([]db.FileInfoTruncated, error) {
+	fake.localChangedFolderFilesMutex.Lock()
+	ret, specificReturn := fake.localChangedFolderFilesReturnsOnCall[len(fake.localChangedFolderFilesArgsForCall)]
+	fake.localChangedFolderFilesArgsForCall = append(fake.localChangedFolderFilesArgsForCall, struct {
+		arg1 string
+		arg2 int
+		arg3 int
+	}{arg1, arg2, arg3})
+	stub := fake.LocalChangedFolderFilesStub
+	fakeReturns := fake.localChangedFolderFilesReturns
+	fake.recordInvocation("LocalChangedFolderFiles", []interface{}{arg1, arg2, arg3})
+	fake.localChangedFolderFilesMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) LocalChangedFolderFilesCallCount() int {
+	fake.localChangedFolderFilesMutex.RLock()
+	defer fake.localChangedFolderFilesMutex.RUnlock()
+	return len(fake.localChangedFolderFilesArgsForCall)
+}
+
+func (fake *Model) LocalChangedFolderFilesCalls(stub func(string, int, int) ([]db.FileInfoTruncated, error)) {
+	fake.localChangedFolderFilesMutex.Lock()
+	defer fake.localChangedFolderFilesMutex.Unlock()
+	fake.LocalChangedFolderFilesStub = stub
+}
+
+func (fake *Model) LocalChangedFolderFilesArgsForCall(i int) (string, int, int) {
+	fake.localChangedFolderFilesMutex.RLock()
+	defer fake.localChangedFolderFilesMutex.RUnlock()
+	argsForCall := fake.localChangedFolderFilesArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Model) LocalChangedFolderFilesReturns(result1 []db.FileInfoTruncated, result2 error) {
+	fake.localChangedFolderFilesMutex.Lock()
+	defer fake.localChangedFolderFilesMutex.Unlock()
+	fake.LocalChangedFolderFilesStub = nil
+	fake.localChangedFolderFilesReturns = struct {
+		result1 []db.FileInfoTruncated
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) LocalChangedFolderFilesReturnsOnCall(i int, result1 []db.FileInfoTruncated, result2 error) {
+	fake.localChangedFolderFilesMutex.Lock()
+	defer fake.localChangedFolderFilesMutex.Unlock()
+	fake.LocalChangedFolderFilesStub = nil
+	if fake.localChangedFolderFilesReturnsOnCall == nil {
+		fake.localChangedFolderFilesReturnsOnCall = make(map[int]struct {
+			result1 []db.FileInfoTruncated
+			result2 error
+		})
+	}
+	fake.localChangedFolderFilesReturnsOnCall[i] = struct {
+		result1 []db.FileInfoTruncated
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) NeedFolderFiles(arg1 string, arg2 int, arg3 int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, error) {
+	fake.needFolderFilesMutex.Lock()
+	ret, specificReturn := fake.needFolderFilesReturnsOnCall[len(fake.needFolderFilesArgsForCall)]
+	fake.needFolderFilesArgsForCall = append(fake.needFolderFilesArgsForCall, struct {
+		arg1 string
+		arg2 int
+		arg3 int
+	}{arg1, arg2, arg3})
+	stub := fake.NeedFolderFilesStub
+	fakeReturns := fake.needFolderFilesReturns
+	fake.recordInvocation("NeedFolderFiles", []interface{}{arg1, arg2, arg3})
+	fake.needFolderFilesMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2, ret.result3, ret.result4
+	}
+	return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3, fakeReturns.result4
+}
+
+func (fake *Model) NeedFolderFilesCallCount() int {
+	fake.needFolderFilesMutex.RLock()
+	defer fake.needFolderFilesMutex.RUnlock()
+	return len(fake.needFolderFilesArgsForCall)
+}
+
+func (fake *Model) NeedFolderFilesCalls(stub func(string, int, int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, error)) {
+	fake.needFolderFilesMutex.Lock()
+	defer fake.needFolderFilesMutex.Unlock()
+	fake.NeedFolderFilesStub = stub
+}
+
+func (fake *Model) NeedFolderFilesArgsForCall(i int) (string, int, int) {
+	fake.needFolderFilesMutex.RLock()
+	defer fake.needFolderFilesMutex.RUnlock()
+	argsForCall := fake.needFolderFilesArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Model) NeedFolderFilesReturns(result1 []db.FileInfoTruncated, result2 []db.FileInfoTruncated, result3 []db.FileInfoTruncated, result4 error) {
+	fake.needFolderFilesMutex.Lock()
+	defer fake.needFolderFilesMutex.Unlock()
+	fake.NeedFolderFilesStub = nil
+	fake.needFolderFilesReturns = struct {
+		result1 []db.FileInfoTruncated
+		result2 []db.FileInfoTruncated
+		result3 []db.FileInfoTruncated
+		result4 error
+	}{result1, result2, result3, result4}
+}
+
+func (fake *Model) NeedFolderFilesReturnsOnCall(i int, result1 []db.FileInfoTruncated, result2 []db.FileInfoTruncated, result3 []db.FileInfoTruncated, result4 error) {
+	fake.needFolderFilesMutex.Lock()
+	defer fake.needFolderFilesMutex.Unlock()
+	fake.NeedFolderFilesStub = nil
+	if fake.needFolderFilesReturnsOnCall == nil {
+		fake.needFolderFilesReturnsOnCall = make(map[int]struct {
+			result1 []db.FileInfoTruncated
+			result2 []db.FileInfoTruncated
+			result3 []db.FileInfoTruncated
+			result4 error
+		})
+	}
+	fake.needFolderFilesReturnsOnCall[i] = struct {
+		result1 []db.FileInfoTruncated
+		result2 []db.FileInfoTruncated
+		result3 []db.FileInfoTruncated
+		result4 error
+	}{result1, result2, result3, result4}
+}
+
+func (fake *Model) NumConnections() int {
+	fake.numConnectionsMutex.Lock()
+	ret, specificReturn := fake.numConnectionsReturnsOnCall[len(fake.numConnectionsArgsForCall)]
+	fake.numConnectionsArgsForCall = append(fake.numConnectionsArgsForCall, struct {
+	}{})
+	stub := fake.NumConnectionsStub
+	fakeReturns := fake.numConnectionsReturns
+	fake.recordInvocation("NumConnections", []interface{}{})
+	fake.numConnectionsMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) NumConnectionsCallCount() int {
+	fake.numConnectionsMutex.RLock()
+	defer fake.numConnectionsMutex.RUnlock()
+	return len(fake.numConnectionsArgsForCall)
+}
+
+func (fake *Model) NumConnectionsCalls(stub func() int) {
+	fake.numConnectionsMutex.Lock()
+	defer fake.numConnectionsMutex.Unlock()
+	fake.NumConnectionsStub = stub
+}
+
+func (fake *Model) NumConnectionsReturns(result1 int) {
+	fake.numConnectionsMutex.Lock()
+	defer fake.numConnectionsMutex.Unlock()
+	fake.NumConnectionsStub = nil
+	fake.numConnectionsReturns = struct {
+		result1 int
+	}{result1}
+}
+
+func (fake *Model) NumConnectionsReturnsOnCall(i int, result1 int) {
+	fake.numConnectionsMutex.Lock()
+	defer fake.numConnectionsMutex.Unlock()
+	fake.NumConnectionsStub = nil
+	if fake.numConnectionsReturnsOnCall == nil {
+		fake.numConnectionsReturnsOnCall = make(map[int]struct {
+			result1 int
+		})
+	}
+	fake.numConnectionsReturnsOnCall[i] = struct {
+		result1 int
+	}{result1}
+}
+
+func (fake *Model) OnHello(arg1 protocol.DeviceID, arg2 net.Addr, arg3 protocol.Hello) error {
+	fake.onHelloMutex.Lock()
+	ret, specificReturn := fake.onHelloReturnsOnCall[len(fake.onHelloArgsForCall)]
+	fake.onHelloArgsForCall = append(fake.onHelloArgsForCall, struct {
+		arg1 protocol.DeviceID
+		arg2 net.Addr
+		arg3 protocol.Hello
+	}{arg1, arg2, arg3})
+	stub := fake.OnHelloStub
+	fakeReturns := fake.onHelloReturns
+	fake.recordInvocation("OnHello", []interface{}{arg1, arg2, arg3})
+	fake.onHelloMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) OnHelloCallCount() int {
+	fake.onHelloMutex.RLock()
+	defer fake.onHelloMutex.RUnlock()
+	return len(fake.onHelloArgsForCall)
+}
+
+func (fake *Model) OnHelloCalls(stub func(protocol.DeviceID, net.Addr, protocol.Hello) error) {
+	fake.onHelloMutex.Lock()
+	defer fake.onHelloMutex.Unlock()
+	fake.OnHelloStub = stub
+}
+
+func (fake *Model) OnHelloArgsForCall(i int) (protocol.DeviceID, net.Addr, protocol.Hello) {
+	fake.onHelloMutex.RLock()
+	defer fake.onHelloMutex.RUnlock()
+	argsForCall := fake.onHelloArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Model) OnHelloReturns(result1 error) {
+	fake.onHelloMutex.Lock()
+	defer fake.onHelloMutex.Unlock()
+	fake.OnHelloStub = nil
+	fake.onHelloReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) OnHelloReturnsOnCall(i int, result1 error) {
+	fake.onHelloMutex.Lock()
+	defer fake.onHelloMutex.Unlock()
+	fake.OnHelloStub = nil
+	if fake.onHelloReturnsOnCall == nil {
+		fake.onHelloReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.onHelloReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) Override(arg1 string) {
+	fake.overrideMutex.Lock()
+	fake.overrideArgsForCall = append(fake.overrideArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.OverrideStub
+	fake.recordInvocation("Override", []interface{}{arg1})
+	fake.overrideMutex.Unlock()
+	if stub != nil {
+		fake.OverrideStub(arg1)
+	}
+}
+
+func (fake *Model) OverrideCallCount() int {
+	fake.overrideMutex.RLock()
+	defer fake.overrideMutex.RUnlock()
+	return len(fake.overrideArgsForCall)
+}
+
+func (fake *Model) OverrideCalls(stub func(string)) {
+	fake.overrideMutex.Lock()
+	defer fake.overrideMutex.Unlock()
+	fake.OverrideStub = stub
+}
+
+func (fake *Model) OverrideArgsForCall(i int) string {
+	fake.overrideMutex.RLock()
+	defer fake.overrideMutex.RUnlock()
+	argsForCall := fake.overrideArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) PendingDevices() (map[protocol.DeviceID]db.ObservedDevice, error) {
+	fake.pendingDevicesMutex.Lock()
+	ret, specificReturn := fake.pendingDevicesReturnsOnCall[len(fake.pendingDevicesArgsForCall)]
+	fake.pendingDevicesArgsForCall = append(fake.pendingDevicesArgsForCall, struct {
+	}{})
+	stub := fake.PendingDevicesStub
+	fakeReturns := fake.pendingDevicesReturns
+	fake.recordInvocation("PendingDevices", []interface{}{})
+	fake.pendingDevicesMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) PendingDevicesCallCount() int {
+	fake.pendingDevicesMutex.RLock()
+	defer fake.pendingDevicesMutex.RUnlock()
+	return len(fake.pendingDevicesArgsForCall)
+}
+
+func (fake *Model) PendingDevicesCalls(stub func() (map[protocol.DeviceID]db.ObservedDevice, error)) {
+	fake.pendingDevicesMutex.Lock()
+	defer fake.pendingDevicesMutex.Unlock()
+	fake.PendingDevicesStub = stub
+}
+
+func (fake *Model) PendingDevicesReturns(result1 map[protocol.DeviceID]db.ObservedDevice, result2 error) {
+	fake.pendingDevicesMutex.Lock()
+	defer fake.pendingDevicesMutex.Unlock()
+	fake.PendingDevicesStub = nil
+	fake.pendingDevicesReturns = struct {
+		result1 map[protocol.DeviceID]db.ObservedDevice
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) PendingDevicesReturnsOnCall(i int, result1 map[protocol.DeviceID]db.ObservedDevice, result2 error) {
+	fake.pendingDevicesMutex.Lock()
+	defer fake.pendingDevicesMutex.Unlock()
+	fake.PendingDevicesStub = nil
+	if fake.pendingDevicesReturnsOnCall == nil {
+		fake.pendingDevicesReturnsOnCall = make(map[int]struct {
+			result1 map[protocol.DeviceID]db.ObservedDevice
+			result2 error
+		})
+	}
+	fake.pendingDevicesReturnsOnCall[i] = struct {
+		result1 map[protocol.DeviceID]db.ObservedDevice
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) PendingFolders(arg1 protocol.DeviceID) (map[string]db.PendingFolder, error) {
+	fake.pendingFoldersMutex.Lock()
+	ret, specificReturn := fake.pendingFoldersReturnsOnCall[len(fake.pendingFoldersArgsForCall)]
+	fake.pendingFoldersArgsForCall = append(fake.pendingFoldersArgsForCall, struct {
+		arg1 protocol.DeviceID
+	}{arg1})
+	stub := fake.PendingFoldersStub
+	fakeReturns := fake.pendingFoldersReturns
+	fake.recordInvocation("PendingFolders", []interface{}{arg1})
+	fake.pendingFoldersMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) PendingFoldersCallCount() int {
+	fake.pendingFoldersMutex.RLock()
+	defer fake.pendingFoldersMutex.RUnlock()
+	return len(fake.pendingFoldersArgsForCall)
+}
+
+func (fake *Model) PendingFoldersCalls(stub func(protocol.DeviceID) (map[string]db.PendingFolder, error)) {
+	fake.pendingFoldersMutex.Lock()
+	defer fake.pendingFoldersMutex.Unlock()
+	fake.PendingFoldersStub = stub
+}
+
+func (fake *Model) PendingFoldersArgsForCall(i int) protocol.DeviceID {
+	fake.pendingFoldersMutex.RLock()
+	defer fake.pendingFoldersMutex.RUnlock()
+	argsForCall := fake.pendingFoldersArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) PendingFoldersReturns(result1 map[string]db.PendingFolder, result2 error) {
+	fake.pendingFoldersMutex.Lock()
+	defer fake.pendingFoldersMutex.Unlock()
+	fake.PendingFoldersStub = nil
+	fake.pendingFoldersReturns = struct {
+		result1 map[string]db.PendingFolder
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) PendingFoldersReturnsOnCall(i int, result1 map[string]db.PendingFolder, result2 error) {
+	fake.pendingFoldersMutex.Lock()
+	defer fake.pendingFoldersMutex.Unlock()
+	fake.PendingFoldersStub = nil
+	if fake.pendingFoldersReturnsOnCall == nil {
+		fake.pendingFoldersReturnsOnCall = make(map[int]struct {
+			result1 map[string]db.PendingFolder
+			result2 error
+		})
+	}
+	fake.pendingFoldersReturnsOnCall[i] = struct {
+		result1 map[string]db.PendingFolder
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) RemoteNeedFolderFiles(arg1 string, arg2 protocol.DeviceID, arg3 int, arg4 int) ([]db.FileInfoTruncated, error) {
+	fake.remoteNeedFolderFilesMutex.Lock()
+	ret, specificReturn := fake.remoteNeedFolderFilesReturnsOnCall[len(fake.remoteNeedFolderFilesArgsForCall)]
+	fake.remoteNeedFolderFilesArgsForCall = append(fake.remoteNeedFolderFilesArgsForCall, struct {
+		arg1 string
+		arg2 protocol.DeviceID
+		arg3 int
+		arg4 int
+	}{arg1, arg2, arg3, arg4})
+	stub := fake.RemoteNeedFolderFilesStub
+	fakeReturns := fake.remoteNeedFolderFilesReturns
+	fake.recordInvocation("RemoteNeedFolderFiles", []interface{}{arg1, arg2, arg3, arg4})
+	fake.remoteNeedFolderFilesMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3, arg4)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) RemoteNeedFolderFilesCallCount() int {
+	fake.remoteNeedFolderFilesMutex.RLock()
+	defer fake.remoteNeedFolderFilesMutex.RUnlock()
+	return len(fake.remoteNeedFolderFilesArgsForCall)
+}
+
+func (fake *Model) RemoteNeedFolderFilesCalls(stub func(string, protocol.DeviceID, int, int) ([]db.FileInfoTruncated, error)) {
+	fake.remoteNeedFolderFilesMutex.Lock()
+	defer fake.remoteNeedFolderFilesMutex.Unlock()
+	fake.RemoteNeedFolderFilesStub = stub
+}
+
+func (fake *Model) RemoteNeedFolderFilesArgsForCall(i int) (string, protocol.DeviceID, int, int) {
+	fake.remoteNeedFolderFilesMutex.RLock()
+	defer fake.remoteNeedFolderFilesMutex.RUnlock()
+	argsForCall := fake.remoteNeedFolderFilesArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
+}
+
+func (fake *Model) RemoteNeedFolderFilesReturns(result1 []db.FileInfoTruncated, result2 error) {
+	fake.remoteNeedFolderFilesMutex.Lock()
+	defer fake.remoteNeedFolderFilesMutex.Unlock()
+	fake.RemoteNeedFolderFilesStub = nil
+	fake.remoteNeedFolderFilesReturns = struct {
+		result1 []db.FileInfoTruncated
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) RemoteNeedFolderFilesReturnsOnCall(i int, result1 []db.FileInfoTruncated, result2 error) {
+	fake.remoteNeedFolderFilesMutex.Lock()
+	defer fake.remoteNeedFolderFilesMutex.Unlock()
+	fake.RemoteNeedFolderFilesStub = nil
+	if fake.remoteNeedFolderFilesReturnsOnCall == nil {
+		fake.remoteNeedFolderFilesReturnsOnCall = make(map[int]struct {
+			result1 []db.FileInfoTruncated
+			result2 error
+		})
+	}
+	fake.remoteNeedFolderFilesReturnsOnCall[i] = struct {
+		result1 []db.FileInfoTruncated
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) Request(arg1 protocol.DeviceID, arg2 string, arg3 string, arg4 int32, arg5 int32, arg6 int64, arg7 []byte, arg8 uint32, arg9 bool) (protocol.RequestResponse, error) {
+	var arg7Copy []byte
+	if arg7 != nil {
+		arg7Copy = make([]byte, len(arg7))
+		copy(arg7Copy, arg7)
+	}
+	fake.requestMutex.Lock()
+	ret, specificReturn := fake.requestReturnsOnCall[len(fake.requestArgsForCall)]
+	fake.requestArgsForCall = append(fake.requestArgsForCall, struct {
+		arg1 protocol.DeviceID
+		arg2 string
+		arg3 string
+		arg4 int32
+		arg5 int32
+		arg6 int64
+		arg7 []byte
+		arg8 uint32
+		arg9 bool
+	}{arg1, arg2, arg3, arg4, arg5, arg6, arg7Copy, arg8, arg9})
+	stub := fake.RequestStub
+	fakeReturns := fake.requestReturns
+	fake.recordInvocation("Request", []interface{}{arg1, arg2, arg3, arg4, arg5, arg6, arg7Copy, arg8, arg9})
+	fake.requestMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) RequestCallCount() int {
+	fake.requestMutex.RLock()
+	defer fake.requestMutex.RUnlock()
+	return len(fake.requestArgsForCall)
+}
+
+func (fake *Model) RequestCalls(stub func(protocol.DeviceID, string, string, int32, int32, int64, []byte, uint32, bool) (protocol.RequestResponse, error)) {
+	fake.requestMutex.Lock()
+	defer fake.requestMutex.Unlock()
+	fake.RequestStub = stub
+}
+
+func (fake *Model) RequestArgsForCall(i int) (protocol.DeviceID, string, string, int32, int32, int64, []byte, uint32, bool) {
+	fake.requestMutex.RLock()
+	defer fake.requestMutex.RUnlock()
+	argsForCall := fake.requestArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5, argsForCall.arg6, argsForCall.arg7, argsForCall.arg8, argsForCall.arg9
+}
+
+func (fake *Model) RequestReturns(result1 protocol.RequestResponse, result2 error) {
+	fake.requestMutex.Lock()
+	defer fake.requestMutex.Unlock()
+	fake.RequestStub = nil
+	fake.requestReturns = struct {
+		result1 protocol.RequestResponse
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) RequestReturnsOnCall(i int, result1 protocol.RequestResponse, result2 error) {
+	fake.requestMutex.Lock()
+	defer fake.requestMutex.Unlock()
+	fake.RequestStub = nil
+	if fake.requestReturnsOnCall == nil {
+		fake.requestReturnsOnCall = make(map[int]struct {
+			result1 protocol.RequestResponse
+			result2 error
+		})
+	}
+	fake.requestReturnsOnCall[i] = struct {
+		result1 protocol.RequestResponse
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) ResetFolder(arg1 string) {
+	fake.resetFolderMutex.Lock()
+	fake.resetFolderArgsForCall = append(fake.resetFolderArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.ResetFolderStub
+	fake.recordInvocation("ResetFolder", []interface{}{arg1})
+	fake.resetFolderMutex.Unlock()
+	if stub != nil {
+		fake.ResetFolderStub(arg1)
+	}
+}
+
+func (fake *Model) ResetFolderCallCount() int {
+	fake.resetFolderMutex.RLock()
+	defer fake.resetFolderMutex.RUnlock()
+	return len(fake.resetFolderArgsForCall)
+}
+
+func (fake *Model) ResetFolderCalls(stub func(string)) {
+	fake.resetFolderMutex.Lock()
+	defer fake.resetFolderMutex.Unlock()
+	fake.ResetFolderStub = stub
+}
+
+func (fake *Model) ResetFolderArgsForCall(i int) string {
+	fake.resetFolderMutex.RLock()
+	defer fake.resetFolderMutex.RUnlock()
+	argsForCall := fake.resetFolderArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) RestoreFolderVersions(arg1 string, arg2 map[string]time.Time) (map[string]error, error) {
+	fake.restoreFolderVersionsMutex.Lock()
+	ret, specificReturn := fake.restoreFolderVersionsReturnsOnCall[len(fake.restoreFolderVersionsArgsForCall)]
+	fake.restoreFolderVersionsArgsForCall = append(fake.restoreFolderVersionsArgsForCall, struct {
+		arg1 string
+		arg2 map[string]time.Time
+	}{arg1, arg2})
+	stub := fake.RestoreFolderVersionsStub
+	fakeReturns := fake.restoreFolderVersionsReturns
+	fake.recordInvocation("RestoreFolderVersions", []interface{}{arg1, arg2})
+	fake.restoreFolderVersionsMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Model) RestoreFolderVersionsCallCount() int {
+	fake.restoreFolderVersionsMutex.RLock()
+	defer fake.restoreFolderVersionsMutex.RUnlock()
+	return len(fake.restoreFolderVersionsArgsForCall)
+}
+
+func (fake *Model) RestoreFolderVersionsCalls(stub func(string, map[string]time.Time) (map[string]error, error)) {
+	fake.restoreFolderVersionsMutex.Lock()
+	defer fake.restoreFolderVersionsMutex.Unlock()
+	fake.RestoreFolderVersionsStub = stub
+}
+
+func (fake *Model) RestoreFolderVersionsArgsForCall(i int) (string, map[string]time.Time) {
+	fake.restoreFolderVersionsMutex.RLock()
+	defer fake.restoreFolderVersionsMutex.RUnlock()
+	argsForCall := fake.restoreFolderVersionsArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) RestoreFolderVersionsReturns(result1 map[string]error, result2 error) {
+	fake.restoreFolderVersionsMutex.Lock()
+	defer fake.restoreFolderVersionsMutex.Unlock()
+	fake.RestoreFolderVersionsStub = nil
+	fake.restoreFolderVersionsReturns = struct {
+		result1 map[string]error
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) RestoreFolderVersionsReturnsOnCall(i int, result1 map[string]error, result2 error) {
+	fake.restoreFolderVersionsMutex.Lock()
+	defer fake.restoreFolderVersionsMutex.Unlock()
+	fake.RestoreFolderVersionsStub = nil
+	if fake.restoreFolderVersionsReturnsOnCall == nil {
+		fake.restoreFolderVersionsReturnsOnCall = make(map[int]struct {
+			result1 map[string]error
+			result2 error
+		})
+	}
+	fake.restoreFolderVersionsReturnsOnCall[i] = struct {
+		result1 map[string]error
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Model) Revert(arg1 string) {
+	fake.revertMutex.Lock()
+	fake.revertArgsForCall = append(fake.revertArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.RevertStub
+	fake.recordInvocation("Revert", []interface{}{arg1})
+	fake.revertMutex.Unlock()
+	if stub != nil {
+		fake.RevertStub(arg1)
+	}
+}
+
+func (fake *Model) RevertCallCount() int {
+	fake.revertMutex.RLock()
+	defer fake.revertMutex.RUnlock()
+	return len(fake.revertArgsForCall)
+}
+
+func (fake *Model) RevertCalls(stub func(string)) {
+	fake.revertMutex.Lock()
+	defer fake.revertMutex.Unlock()
+	fake.RevertStub = stub
+}
+
+func (fake *Model) RevertArgsForCall(i int) string {
+	fake.revertMutex.RLock()
+	defer fake.revertMutex.RUnlock()
+	argsForCall := fake.revertArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) ScanFolder(arg1 string) error {
+	fake.scanFolderMutex.Lock()
+	ret, specificReturn := fake.scanFolderReturnsOnCall[len(fake.scanFolderArgsForCall)]
+	fake.scanFolderArgsForCall = append(fake.scanFolderArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.ScanFolderStub
+	fakeReturns := fake.scanFolderReturns
+	fake.recordInvocation("ScanFolder", []interface{}{arg1})
+	fake.scanFolderMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) ScanFolderCallCount() int {
+	fake.scanFolderMutex.RLock()
+	defer fake.scanFolderMutex.RUnlock()
+	return len(fake.scanFolderArgsForCall)
+}
+
+func (fake *Model) ScanFolderCalls(stub func(string) error) {
+	fake.scanFolderMutex.Lock()
+	defer fake.scanFolderMutex.Unlock()
+	fake.ScanFolderStub = stub
+}
+
+func (fake *Model) ScanFolderArgsForCall(i int) string {
+	fake.scanFolderMutex.RLock()
+	defer fake.scanFolderMutex.RUnlock()
+	argsForCall := fake.scanFolderArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) ScanFolderReturns(result1 error) {
+	fake.scanFolderMutex.Lock()
+	defer fake.scanFolderMutex.Unlock()
+	fake.ScanFolderStub = nil
+	fake.scanFolderReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) ScanFolderReturnsOnCall(i int, result1 error) {
+	fake.scanFolderMutex.Lock()
+	defer fake.scanFolderMutex.Unlock()
+	fake.ScanFolderStub = nil
+	if fake.scanFolderReturnsOnCall == nil {
+		fake.scanFolderReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.scanFolderReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) ScanFolderSubdirs(arg1 string, arg2 []string) error {
+	var arg2Copy []string
+	if arg2 != nil {
+		arg2Copy = make([]string, len(arg2))
+		copy(arg2Copy, arg2)
+	}
+	fake.scanFolderSubdirsMutex.Lock()
+	ret, specificReturn := fake.scanFolderSubdirsReturnsOnCall[len(fake.scanFolderSubdirsArgsForCall)]
+	fake.scanFolderSubdirsArgsForCall = append(fake.scanFolderSubdirsArgsForCall, struct {
+		arg1 string
+		arg2 []string
+	}{arg1, arg2Copy})
+	stub := fake.ScanFolderSubdirsStub
+	fakeReturns := fake.scanFolderSubdirsReturns
+	fake.recordInvocation("ScanFolderSubdirs", []interface{}{arg1, arg2Copy})
+	fake.scanFolderSubdirsMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) ScanFolderSubdirsCallCount() int {
+	fake.scanFolderSubdirsMutex.RLock()
+	defer fake.scanFolderSubdirsMutex.RUnlock()
+	return len(fake.scanFolderSubdirsArgsForCall)
+}
+
+func (fake *Model) ScanFolderSubdirsCalls(stub func(string, []string) error) {
+	fake.scanFolderSubdirsMutex.Lock()
+	defer fake.scanFolderSubdirsMutex.Unlock()
+	fake.ScanFolderSubdirsStub = stub
+}
+
+func (fake *Model) ScanFolderSubdirsArgsForCall(i int) (string, []string) {
+	fake.scanFolderSubdirsMutex.RLock()
+	defer fake.scanFolderSubdirsMutex.RUnlock()
+	argsForCall := fake.scanFolderSubdirsArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) ScanFolderSubdirsReturns(result1 error) {
+	fake.scanFolderSubdirsMutex.Lock()
+	defer fake.scanFolderSubdirsMutex.Unlock()
+	fake.ScanFolderSubdirsStub = nil
+	fake.scanFolderSubdirsReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) ScanFolderSubdirsReturnsOnCall(i int, result1 error) {
+	fake.scanFolderSubdirsMutex.Lock()
+	defer fake.scanFolderSubdirsMutex.Unlock()
+	fake.ScanFolderSubdirsStub = nil
+	if fake.scanFolderSubdirsReturnsOnCall == nil {
+		fake.scanFolderSubdirsReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.scanFolderSubdirsReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) ScanFolders() map[string]error {
+	fake.scanFoldersMutex.Lock()
+	ret, specificReturn := fake.scanFoldersReturnsOnCall[len(fake.scanFoldersArgsForCall)]
+	fake.scanFoldersArgsForCall = append(fake.scanFoldersArgsForCall, struct {
+	}{})
+	stub := fake.ScanFoldersStub
+	fakeReturns := fake.scanFoldersReturns
+	fake.recordInvocation("ScanFolders", []interface{}{})
+	fake.scanFoldersMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) ScanFoldersCallCount() int {
+	fake.scanFoldersMutex.RLock()
+	defer fake.scanFoldersMutex.RUnlock()
+	return len(fake.scanFoldersArgsForCall)
+}
+
+func (fake *Model) ScanFoldersCalls(stub func() map[string]error) {
+	fake.scanFoldersMutex.Lock()
+	defer fake.scanFoldersMutex.Unlock()
+	fake.ScanFoldersStub = stub
+}
+
+func (fake *Model) ScanFoldersReturns(result1 map[string]error) {
+	fake.scanFoldersMutex.Lock()
+	defer fake.scanFoldersMutex.Unlock()
+	fake.ScanFoldersStub = nil
+	fake.scanFoldersReturns = struct {
+		result1 map[string]error
+	}{result1}
+}
+
+func (fake *Model) ScanFoldersReturnsOnCall(i int, result1 map[string]error) {
+	fake.scanFoldersMutex.Lock()
+	defer fake.scanFoldersMutex.Unlock()
+	fake.ScanFoldersStub = nil
+	if fake.scanFoldersReturnsOnCall == nil {
+		fake.scanFoldersReturnsOnCall = make(map[int]struct {
+			result1 map[string]error
+		})
+	}
+	fake.scanFoldersReturnsOnCall[i] = struct {
+		result1 map[string]error
+	}{result1}
+}
+
+func (fake *Model) Serve(arg1 context.Context) error {
+	fake.serveMutex.Lock()
+	ret, specificReturn := fake.serveReturnsOnCall[len(fake.serveArgsForCall)]
+	fake.serveArgsForCall = append(fake.serveArgsForCall, struct {
+		arg1 context.Context
+	}{arg1})
+	stub := fake.ServeStub
+	fakeReturns := fake.serveReturns
+	fake.recordInvocation("Serve", []interface{}{arg1})
+	fake.serveMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) ServeCallCount() int {
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	return len(fake.serveArgsForCall)
+}
+
+func (fake *Model) ServeCalls(stub func(context.Context) error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = stub
+}
+
+func (fake *Model) ServeArgsForCall(i int) context.Context {
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	argsForCall := fake.serveArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) ServeReturns(result1 error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = nil
+	fake.serveReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) ServeReturnsOnCall(i int, result1 error) {
+	fake.serveMutex.Lock()
+	defer fake.serveMutex.Unlock()
+	fake.ServeStub = nil
+	if fake.serveReturnsOnCall == nil {
+		fake.serveReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.serveReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) SetIgnores(arg1 string, arg2 []string) error {
+	var arg2Copy []string
+	if arg2 != nil {
+		arg2Copy = make([]string, len(arg2))
+		copy(arg2Copy, arg2)
+	}
+	fake.setIgnoresMutex.Lock()
+	ret, specificReturn := fake.setIgnoresReturnsOnCall[len(fake.setIgnoresArgsForCall)]
+	fake.setIgnoresArgsForCall = append(fake.setIgnoresArgsForCall, struct {
+		arg1 string
+		arg2 []string
+	}{arg1, arg2Copy})
+	stub := fake.SetIgnoresStub
+	fakeReturns := fake.setIgnoresReturns
+	fake.recordInvocation("SetIgnores", []interface{}{arg1, arg2Copy})
+	fake.setIgnoresMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) SetIgnoresCallCount() int {
+	fake.setIgnoresMutex.RLock()
+	defer fake.setIgnoresMutex.RUnlock()
+	return len(fake.setIgnoresArgsForCall)
+}
+
+func (fake *Model) SetIgnoresCalls(stub func(string, []string) error) {
+	fake.setIgnoresMutex.Lock()
+	defer fake.setIgnoresMutex.Unlock()
+	fake.SetIgnoresStub = stub
+}
+
+func (fake *Model) SetIgnoresArgsForCall(i int) (string, []string) {
+	fake.setIgnoresMutex.RLock()
+	defer fake.setIgnoresMutex.RUnlock()
+	argsForCall := fake.setIgnoresArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2
+}
+
+func (fake *Model) SetIgnoresReturns(result1 error) {
+	fake.setIgnoresMutex.Lock()
+	defer fake.setIgnoresMutex.Unlock()
+	fake.SetIgnoresStub = nil
+	fake.setIgnoresReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) SetIgnoresReturnsOnCall(i int, result1 error) {
+	fake.setIgnoresMutex.Lock()
+	defer fake.setIgnoresMutex.Unlock()
+	fake.SetIgnoresStub = nil
+	if fake.setIgnoresReturnsOnCall == nil {
+		fake.setIgnoresReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.setIgnoresReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) StartDeadlockDetector(arg1 time.Duration) {
+	fake.startDeadlockDetectorMutex.Lock()
+	fake.startDeadlockDetectorArgsForCall = append(fake.startDeadlockDetectorArgsForCall, struct {
+		arg1 time.Duration
+	}{arg1})
+	stub := fake.StartDeadlockDetectorStub
+	fake.recordInvocation("StartDeadlockDetector", []interface{}{arg1})
+	fake.startDeadlockDetectorMutex.Unlock()
+	if stub != nil {
+		fake.StartDeadlockDetectorStub(arg1)
+	}
+}
+
+func (fake *Model) StartDeadlockDetectorCallCount() int {
+	fake.startDeadlockDetectorMutex.RLock()
+	defer fake.startDeadlockDetectorMutex.RUnlock()
+	return len(fake.startDeadlockDetectorArgsForCall)
+}
+
+func (fake *Model) StartDeadlockDetectorCalls(stub func(time.Duration)) {
+	fake.startDeadlockDetectorMutex.Lock()
+	defer fake.startDeadlockDetectorMutex.Unlock()
+	fake.StartDeadlockDetectorStub = stub
+}
+
+func (fake *Model) StartDeadlockDetectorArgsForCall(i int) time.Duration {
+	fake.startDeadlockDetectorMutex.RLock()
+	defer fake.startDeadlockDetectorMutex.RUnlock()
+	argsForCall := fake.startDeadlockDetectorArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) State(arg1 string) (string, time.Time, error) {
+	fake.stateMutex.Lock()
+	ret, specificReturn := fake.stateReturnsOnCall[len(fake.stateArgsForCall)]
+	fake.stateArgsForCall = append(fake.stateArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.StateStub
+	fakeReturns := fake.stateReturns
+	fake.recordInvocation("State", []interface{}{arg1})
+	fake.stateMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2, ret.result3
+	}
+	return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
+}
+
+func (fake *Model) StateCallCount() int {
+	fake.stateMutex.RLock()
+	defer fake.stateMutex.RUnlock()
+	return len(fake.stateArgsForCall)
+}
+
+func (fake *Model) StateCalls(stub func(string) (string, time.Time, error)) {
+	fake.stateMutex.Lock()
+	defer fake.stateMutex.Unlock()
+	fake.StateStub = stub
+}
+
+func (fake *Model) StateArgsForCall(i int) string {
+	fake.stateMutex.RLock()
+	defer fake.stateMutex.RUnlock()
+	argsForCall := fake.stateArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) StateReturns(result1 string, result2 time.Time, result3 error) {
+	fake.stateMutex.Lock()
+	defer fake.stateMutex.Unlock()
+	fake.StateStub = nil
+	fake.stateReturns = struct {
+		result1 string
+		result2 time.Time
+		result3 error
+	}{result1, result2, result3}
+}
+
+func (fake *Model) StateReturnsOnCall(i int, result1 string, result2 time.Time, result3 error) {
+	fake.stateMutex.Lock()
+	defer fake.stateMutex.Unlock()
+	fake.StateStub = nil
+	if fake.stateReturnsOnCall == nil {
+		fake.stateReturnsOnCall = make(map[int]struct {
+			result1 string
+			result2 time.Time
+			result3 error
+		})
+	}
+	fake.stateReturnsOnCall[i] = struct {
+		result1 string
+		result2 time.Time
+		result3 error
+	}{result1, result2, result3}
+}
+
+func (fake *Model) UsageReportingStats(arg1 *contract.Report, arg2 int, arg3 bool) {
+	fake.usageReportingStatsMutex.Lock()
+	fake.usageReportingStatsArgsForCall = append(fake.usageReportingStatsArgsForCall, struct {
+		arg1 *contract.Report
+		arg2 int
+		arg3 bool
+	}{arg1, arg2, arg3})
+	stub := fake.UsageReportingStatsStub
+	fake.recordInvocation("UsageReportingStats", []interface{}{arg1, arg2, arg3})
+	fake.usageReportingStatsMutex.Unlock()
+	if stub != nil {
+		fake.UsageReportingStatsStub(arg1, arg2, arg3)
+	}
+}
+
+func (fake *Model) UsageReportingStatsCallCount() int {
+	fake.usageReportingStatsMutex.RLock()
+	defer fake.usageReportingStatsMutex.RUnlock()
+	return len(fake.usageReportingStatsArgsForCall)
+}
+
+func (fake *Model) UsageReportingStatsCalls(stub func(*contract.Report, int, bool)) {
+	fake.usageReportingStatsMutex.Lock()
+	defer fake.usageReportingStatsMutex.Unlock()
+	fake.UsageReportingStatsStub = stub
+}
+
+func (fake *Model) UsageReportingStatsArgsForCall(i int) (*contract.Report, int, bool) {
+	fake.usageReportingStatsMutex.RLock()
+	defer fake.usageReportingStatsMutex.RUnlock()
+	argsForCall := fake.usageReportingStatsArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Model) WatchError(arg1 string) error {
+	fake.watchErrorMutex.Lock()
+	ret, specificReturn := fake.watchErrorReturnsOnCall[len(fake.watchErrorArgsForCall)]
+	fake.watchErrorArgsForCall = append(fake.watchErrorArgsForCall, struct {
+		arg1 string
+	}{arg1})
+	stub := fake.WatchErrorStub
+	fakeReturns := fake.watchErrorReturns
+	fake.recordInvocation("WatchError", []interface{}{arg1})
+	fake.watchErrorMutex.Unlock()
+	if stub != nil {
+		return stub(arg1)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Model) WatchErrorCallCount() int {
+	fake.watchErrorMutex.RLock()
+	defer fake.watchErrorMutex.RUnlock()
+	return len(fake.watchErrorArgsForCall)
+}
+
+func (fake *Model) WatchErrorCalls(stub func(string) error) {
+	fake.watchErrorMutex.Lock()
+	defer fake.watchErrorMutex.Unlock()
+	fake.WatchErrorStub = stub
+}
+
+func (fake *Model) WatchErrorArgsForCall(i int) string {
+	fake.watchErrorMutex.RLock()
+	defer fake.watchErrorMutex.RUnlock()
+	argsForCall := fake.watchErrorArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Model) WatchErrorReturns(result1 error) {
+	fake.watchErrorMutex.Lock()
+	defer fake.watchErrorMutex.Unlock()
+	fake.WatchErrorStub = nil
+	fake.watchErrorReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) WatchErrorReturnsOnCall(i int, result1 error) {
+	fake.watchErrorMutex.Lock()
+	defer fake.watchErrorMutex.Unlock()
+	fake.WatchErrorStub = nil
+	if fake.watchErrorReturnsOnCall == nil {
+		fake.watchErrorReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.watchErrorReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Model) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.addConnectionMutex.RLock()
+	defer fake.addConnectionMutex.RUnlock()
+	fake.availabilityMutex.RLock()
+	defer fake.availabilityMutex.RUnlock()
+	fake.bringToFrontMutex.RLock()
+	defer fake.bringToFrontMutex.RUnlock()
+	fake.closedMutex.RLock()
+	defer fake.closedMutex.RUnlock()
+	fake.clusterConfigMutex.RLock()
+	defer fake.clusterConfigMutex.RUnlock()
+	fake.completionMutex.RLock()
+	defer fake.completionMutex.RUnlock()
+	fake.connectionMutex.RLock()
+	defer fake.connectionMutex.RUnlock()
+	fake.connectionStatsMutex.RLock()
+	defer fake.connectionStatsMutex.RUnlock()
+	fake.currentFolderFileMutex.RLock()
+	defer fake.currentFolderFileMutex.RUnlock()
+	fake.currentGlobalFileMutex.RLock()
+	defer fake.currentGlobalFileMutex.RUnlock()
+	fake.currentIgnoresMutex.RLock()
+	defer fake.currentIgnoresMutex.RUnlock()
+	fake.dBSnapshotMutex.RLock()
+	defer fake.dBSnapshotMutex.RUnlock()
+	fake.delayScanMutex.RLock()
+	defer fake.delayScanMutex.RUnlock()
+	fake.deviceStatisticsMutex.RLock()
+	defer fake.deviceStatisticsMutex.RUnlock()
+	fake.downloadProgressMutex.RLock()
+	defer fake.downloadProgressMutex.RUnlock()
+	fake.folderErrorsMutex.RLock()
+	defer fake.folderErrorsMutex.RUnlock()
+	fake.folderProgressBytesCompletedMutex.RLock()
+	defer fake.folderProgressBytesCompletedMutex.RUnlock()
+	fake.folderStatisticsMutex.RLock()
+	defer fake.folderStatisticsMutex.RUnlock()
+	fake.getFolderVersionsMutex.RLock()
+	defer fake.getFolderVersionsMutex.RUnlock()
+	fake.getHelloMutex.RLock()
+	defer fake.getHelloMutex.RUnlock()
+	fake.globalDirectoryTreeMutex.RLock()
+	defer fake.globalDirectoryTreeMutex.RUnlock()
+	fake.indexMutex.RLock()
+	defer fake.indexMutex.RUnlock()
+	fake.indexUpdateMutex.RLock()
+	defer fake.indexUpdateMutex.RUnlock()
+	fake.loadIgnoresMutex.RLock()
+	defer fake.loadIgnoresMutex.RUnlock()
+	fake.localChangedFolderFilesMutex.RLock()
+	defer fake.localChangedFolderFilesMutex.RUnlock()
+	fake.needFolderFilesMutex.RLock()
+	defer fake.needFolderFilesMutex.RUnlock()
+	fake.numConnectionsMutex.RLock()
+	defer fake.numConnectionsMutex.RUnlock()
+	fake.onHelloMutex.RLock()
+	defer fake.onHelloMutex.RUnlock()
+	fake.overrideMutex.RLock()
+	defer fake.overrideMutex.RUnlock()
+	fake.pendingDevicesMutex.RLock()
+	defer fake.pendingDevicesMutex.RUnlock()
+	fake.pendingFoldersMutex.RLock()
+	defer fake.pendingFoldersMutex.RUnlock()
+	fake.remoteNeedFolderFilesMutex.RLock()
+	defer fake.remoteNeedFolderFilesMutex.RUnlock()
+	fake.requestMutex.RLock()
+	defer fake.requestMutex.RUnlock()
+	fake.resetFolderMutex.RLock()
+	defer fake.resetFolderMutex.RUnlock()
+	fake.restoreFolderVersionsMutex.RLock()
+	defer fake.restoreFolderVersionsMutex.RUnlock()
+	fake.revertMutex.RLock()
+	defer fake.revertMutex.RUnlock()
+	fake.scanFolderMutex.RLock()
+	defer fake.scanFolderMutex.RUnlock()
+	fake.scanFolderSubdirsMutex.RLock()
+	defer fake.scanFolderSubdirsMutex.RUnlock()
+	fake.scanFoldersMutex.RLock()
+	defer fake.scanFoldersMutex.RUnlock()
+	fake.serveMutex.RLock()
+	defer fake.serveMutex.RUnlock()
+	fake.setIgnoresMutex.RLock()
+	defer fake.setIgnoresMutex.RUnlock()
+	fake.startDeadlockDetectorMutex.RLock()
+	defer fake.startDeadlockDetectorMutex.RUnlock()
+	fake.stateMutex.RLock()
+	defer fake.stateMutex.RUnlock()
+	fake.usageReportingStatsMutex.RLock()
+	defer fake.usageReportingStatsMutex.RUnlock()
+	fake.watchErrorMutex.RLock()
+	defer fake.watchErrorMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *Model) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ model.Model = new(Model)

+ 2 - 0
lib/model/model.go

@@ -4,6 +4,8 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // You can obtain one at https://mozilla.org/MPL/2.0/.
 
+//go:generate counterfeiter -o mocks/model.go --fake-name Model . Model
+
 package model
 
 import (

+ 19 - 26
lib/model/model_test.go

@@ -35,6 +35,7 @@ import (
 	"github.com/syncthing/syncthing/lib/ignore"
 	"github.com/syncthing/syncthing/lib/osutil"
 	"github.com/syncthing/syncthing/lib/protocol"
+	protocolmocks "github.com/syncthing/syncthing/lib/protocol/mocks"
 	srand "github.com/syncthing/syncthing/lib/rand"
 	"github.com/syncthing/syncthing/lib/testutils"
 	"github.com/syncthing/syncthing/lib/versioner"
@@ -116,7 +117,7 @@ func newState(t testing.TB, cfg config.Configuration) (*testModel, context.Cance
 	m := setupModel(t, wcfg)
 
 	for _, dev := range cfg.Devices {
-		m.AddConnection(&fakeConnection{id: dev.DeviceID, model: m}, protocol.Hello{})
+		m.AddConnection(newFakeConnection(dev.DeviceID, m), protocol.Hello{})
 	}
 
 	return m, cancel
@@ -267,7 +268,7 @@ func BenchmarkRequestOut(b *testing.B) {
 	const n = 1000
 	files := genFiles(n)
 
-	fc := &fakeConnection{id: device1, model: m}
+	fc := newFakeConnection(device1, m)
 	for _, f := range files {
 		fc.addFile(f.Name, 0644, protocol.FileInfoTypeFile, []byte("some data to return"))
 	}
@@ -329,7 +330,7 @@ func TestDeviceRename(t *testing.T) {
 		t.Errorf("Device already has a name")
 	}
 
-	conn := &fakeConnection{id: device1, model: m}
+	conn := newFakeConnection(device1, m)
 
 	m.AddConnection(conn, hello)
 
@@ -871,9 +872,7 @@ func TestIssue5063(t *testing.T) {
 	m.pmut.Lock()
 	for _, c := range m.conn {
 		conn := c.(*fakeConnection)
-		conn.mut.Lock()
-		conn.closeFn = func(_ error) {}
-		conn.mut.Unlock()
+		conn.CloseCalls(func(_ error) {})
 		defer m.Closed(c, errStopped) // to unblock deferred m.Stop()
 	}
 	m.pmut.Unlock()
@@ -1324,7 +1323,7 @@ func TestAutoAcceptEnc(t *testing.T) {
 	// Earlier tests might cause the connection to get closed, thus ClusterConfig
 	// would panic.
 	clusterConfig := func(deviceID protocol.DeviceID, cm protocol.ClusterConfig) {
-		m.AddConnection(&fakeConnection{id: deviceID, model: m}, protocol.Hello{})
+		m.AddConnection(newFakeConnection(deviceID, m), protocol.Hello{})
 		m.ClusterConfig(deviceID, cm)
 	}
 
@@ -2196,9 +2195,9 @@ func TestSharedWithClearedOnDisconnect(t *testing.T) {
 	m := setupModel(t, wcfg)
 	defer cleanupModel(m)
 
-	conn1 := &fakeConnection{id: device1, model: m}
+	conn1 := newFakeConnection(device1, m)
 	m.AddConnection(conn1, protocol.Hello{})
-	conn2 := &fakeConnection{id: device2, model: m}
+	conn2 := newFakeConnection(device2, m)
 	m.AddConnection(conn2, protocol.Hello{})
 
 	m.ClusterConfig(device1, protocol.ClusterConfig{
@@ -2429,8 +2428,8 @@ func TestNoRequestsFromPausedDevices(t *testing.T) {
 		t.Errorf("should have two available")
 	}
 
-	m.Closed(&fakeConnection{id: device1, model: m}, errDeviceUnknown)
-	m.Closed(&fakeConnection{id: device2, model: m}, errDeviceUnknown)
+	m.Closed(newFakeConnection(device1, m), errDeviceUnknown)
+	m.Closed(newFakeConnection(device2, m), errDeviceUnknown)
 
 	avail = m.Availability("default", file, file.Blocks[0])
 	if len(avail) != 0 {
@@ -3172,7 +3171,7 @@ func TestConnCloseOnRestart(t *testing.T) {
 
 	br := &testutils.BlockingRW{}
 	nw := &testutils.NoopRW{}
-	m.AddConnection(protocol.NewConnection(device1, br, nw, testutils.NoopCloser{}, m, &testutils.FakeConnectionInfo{"fc"}, protocol.CompressionNever), protocol.Hello{})
+	m.AddConnection(protocol.NewConnection(device1, br, nw, testutils.NoopCloser{}, m, new(protocolmocks.ConnectionInfo), protocol.CompressionNever), protocol.Hello{})
 	m.pmut.RLock()
 	if len(m.closed) != 1 {
 		t.Fatalf("Expected just one conn (len(m.conn) == %v)", len(m.conn))
@@ -3819,20 +3818,14 @@ func testConfigChangeTriggersClusterConfigs(t *testing.T, expectFirst, expectSec
 
 	cc1 := make(chan struct{}, 1)
 	cc2 := make(chan struct{}, 1)
-	fc1 := &fakeConnection{
-		id:    device1,
-		model: m,
-		clusterConfigFn: func(_ protocol.ClusterConfig) {
-			cc1 <- struct{}{}
-		},
-	}
-	fc2 := &fakeConnection{
-		id:    device2,
-		model: m,
-		clusterConfigFn: func(_ protocol.ClusterConfig) {
-			cc2 <- struct{}{}
-		},
-	}
+	fc1 := newFakeConnection(device1, m)
+	fc1.ClusterConfigCalls(func(_ protocol.ClusterConfig) {
+		cc1 <- struct{}{}
+	})
+	fc2 := newFakeConnection(device2, m)
+	fc2.ClusterConfigCalls(func(_ protocol.ClusterConfig) {
+		cc2 <- struct{}{}
+	})
 	m.AddConnection(fc1, protocol.Hello{})
 	m.AddConnection(fc2, protocol.Hello{})
 

+ 1 - 1
lib/model/progressemitter_test.go

@@ -126,7 +126,7 @@ func TestSendDownloadProgressMessages(t *testing.T) {
 	}
 	waiter.Wait()
 
-	fc := &fakeConnection{}
+	fc := newFakeConnection(protocol.DeviceID{}, nil)
 
 	ctx, cancel := context.WithCancel(context.Background())
 	evLogger := events.NewLogger()

+ 87 - 114
lib/model/requests_test.go

@@ -38,8 +38,7 @@ func TestRequestSimple(t *testing.T) {
 	// We listen for incoming index updates and trigger when we see one for
 	// the expected test file.
 	done := make(chan struct{})
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case <-done:
 			t.Error("More than one index update sent")
@@ -48,11 +47,11 @@ func TestRequestSimple(t *testing.T) {
 		for _, f := range fs {
 			if f.Name == "testfile" {
 				close(done)
-				return
+				return nil
 			}
 		}
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	// Send an update for the test file, wait for it to sync and be reported back.
 	contents := []byte("test file contents\n")
@@ -81,8 +80,7 @@ func TestSymlinkTraversalRead(t *testing.T) {
 	// We listen for incoming index updates and trigger when we see one for
 	// the expected test file.
 	done := make(chan struct{})
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case <-done:
 			t.Error("More than one index update sent")
@@ -91,11 +89,11 @@ func TestSymlinkTraversalRead(t *testing.T) {
 		for _, f := range fs {
 			if f.Name == "symlink" {
 				close(done)
-				return
+				return nil
 			}
 		}
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	// Send an update for the symlink, wait for it to sync and be reported back.
 	contents := []byte("..")
@@ -127,26 +125,25 @@ func TestSymlinkTraversalWrite(t *testing.T) {
 	done := make(chan struct{}, 1)
 	badReq := make(chan string, 1)
 	badIdx := make(chan string, 1)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		for _, f := range fs {
 			if f.Name == "symlink" {
 				done <- struct{}{}
-				return
+				return nil
 			}
 			if strings.HasPrefix(f.Name, "symlink") {
 				badIdx <- f.Name
-				return
+				return nil
 			}
 		}
-	}
-	fc.requestFn = func(_ context.Context, folder, name string, offset int64, size int, hash []byte, fromTemporary bool) ([]byte, error) {
+		return nil
+	})
+	fc.RequestCalls(func(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
 		if name != "symlink" && strings.HasPrefix(name, "symlink") {
 			badReq <- name
 		}
 		return fc.fileData[name], nil
-	}
-	fc.mut.Unlock()
+	})
 
 	// Send an update for the symlink, wait for it to sync and be reported back.
 	contents := []byte("..")
@@ -186,8 +183,7 @@ func TestRequestCreateTmpSymlink(t *testing.T) {
 	// the expected test file.
 	goodIdx := make(chan struct{})
 	name := fs.TempName("testlink")
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		for _, f := range fs {
 			if f.Name == name {
 				if f.IsInvalid() {
@@ -196,11 +192,11 @@ func TestRequestCreateTmpSymlink(t *testing.T) {
 					t.Error("Received index with non-invalid temporary file")
 					close(goodIdx)
 				}
-				return
+				return nil
 			}
 		}
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	// Send an update for the test file, wait for it to sync and be reported back.
 	fc.addFile(name, 0644, protocol.FileInfoTypeSymlink, []byte(".."))
@@ -244,11 +240,10 @@ func TestRequestVersioningSymlinkAttack(t *testing.T) {
 	// We listen for incoming index updates and trigger when we see one for
 	// the expected test file.
 	idx := make(chan int)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		idx <- len(fs)
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	waitForIdx := func() {
 		select {
@@ -335,8 +330,7 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) {
 	}
 
 	done := make(chan struct{})
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		expected := map[string]struct{}{invIgn: {}, ign: {}, ignExisting: {}}
 		for _, f := range fs {
 			if _, ok := expected[f.Name]; !ok {
@@ -351,8 +345,8 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) {
 			t.Errorf("File %v wasn't added to index", name)
 		}
 		close(done)
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	sub := m.evLogger.Subscribe(events.FolderErrors)
 	defer sub.Unsubscribe()
@@ -372,8 +366,7 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) {
 	var expectedMut sync.Mutex
 	// The indexes will normally arrive in one update, but it is possible
 	// that they arrive in separate ones.
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		expectedMut.Lock()
 		for _, f := range fs {
 			_, ok := expected[f.Name]
@@ -411,13 +404,13 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) {
 			close(done)
 		}
 		expectedMut.Unlock()
-	}
+		return nil
+	})
 	// Make sure pulling doesn't interfere, as index updates are racy and
 	// thus we cannot distinguish between scan and pull results.
-	fc.requestFn = func(_ context.Context, folder, name string, offset int64, size int, hash []byte, fromTemporary bool) ([]byte, error) {
+	fc.RequestCalls(func(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
 		return nil, nil
-	}
-	fc.mut.Unlock()
+	})
 
 	if err := m.SetIgnores("default", []string{"*:ignored*"}); err != nil {
 		panic(err)
@@ -438,11 +431,10 @@ func TestIssue4841(t *testing.T) {
 	defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
 
 	received := make(chan []protocol.FileInfo)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, _ string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, _ string, fs []protocol.FileInfo) error {
 		received <- fs
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 	checkReceived := func(fs []protocol.FileInfo) protocol.FileInfo {
 		t.Helper()
 		if len(fs) != 1 {
@@ -492,11 +484,10 @@ func TestRescanIfHaveInvalidContent(t *testing.T) {
 	must(t, writeFile(tfs, "foo", payload, 0777))
 
 	received := make(chan []protocol.FileInfo)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, _ string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, _ string, fs []protocol.FileInfo) error {
 		received <- fs
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 	checkReceived := func(fs []protocol.FileInfo) protocol.FileInfo {
 		t.Helper()
 		if len(fs) != 1 {
@@ -560,11 +551,10 @@ func TestParentDeletion(t *testing.T) {
 	received := make(chan []protocol.FileInfo)
 	fc.addFile(parent, 0777, protocol.FileInfoTypeDirectory, nil)
 	fc.addFile(child, 0777, protocol.FileInfoTypeDirectory, nil)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		received <- fs
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 	fc.sendIndexUpdate()
 
 	// Get back index from initial setup
@@ -634,16 +624,15 @@ func TestRequestSymlinkWindows(t *testing.T) {
 	defer cleanupModelAndRemoveDir(m, fcfg.Filesystem().URI())
 
 	received := make(chan []protocol.FileInfo)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case <-received:
 			t.Error("More than one index update sent")
 		default:
 		}
 		received <- fs
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	fc.addFile("link", 0644, protocol.FileInfoTypeSymlink, nil)
 	fc.sendIndexUpdate()
@@ -705,16 +694,15 @@ func TestRequestRemoteRenameChanged(t *testing.T) {
 	defer cleanupModelAndRemoveDir(m, tfs.URI())
 
 	received := make(chan []protocol.FileInfo)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case <-received:
 			t.Error("More than one index update sent")
 		default:
 		}
 		received <- fs
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	// setup
 	a := "a"
@@ -743,12 +731,11 @@ func TestRequestRemoteRenameChanged(t *testing.T) {
 
 	var gotA, gotB, gotConfl bool
 	done := make(chan struct{})
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case <-done:
 			t.Error("Received more index updates than expected")
-			return
+			return nil
 		default:
 		}
 		for _, f := range fs {
@@ -780,8 +767,8 @@ func TestRequestRemoteRenameChanged(t *testing.T) {
 		if gotA && gotB && gotConfl {
 			close(done)
 		}
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	fd, err := tfs.OpenFile(b, fs.OptReadWrite, 0644)
 	if err != nil {
@@ -841,11 +828,10 @@ func TestRequestRemoteRenameConflict(t *testing.T) {
 	defer cleanupModelAndRemoveDir(m, tmpDir)
 
 	recv := make(chan int)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		recv <- len(fs)
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	// setup
 	a := "a"
@@ -932,16 +918,15 @@ func TestRequestDeleteChanged(t *testing.T) {
 	defer cleanupModelAndRemoveDir(m, tfs.URI())
 
 	done := make(chan struct{})
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case <-done:
 			t.Error("More than one index update sent")
 		default:
 		}
 		close(done)
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	// setup
 	a := "a"
@@ -955,16 +940,15 @@ func TestRequestDeleteChanged(t *testing.T) {
 		t.Fatal("timed out")
 	}
 
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case <-done:
 			t.Error("More than one index update sent")
 		default:
 		}
 		close(done)
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	fd, err := tfs.OpenFile(a, fs.OptReadWrite, 0644)
 	if err != nil {
@@ -1006,11 +990,9 @@ func TestNeedFolderFiles(t *testing.T) {
 	defer sub.Unsubscribe()
 
 	errPreventSync := errors.New("you aren't getting any of this")
-	fc.mut.Lock()
-	fc.requestFn = func(context.Context, string, string, int64, int, []byte, bool) ([]byte, error) {
+	fc.RequestCalls(func(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
 		return nil, errPreventSync
-	}
-	fc.mut.Unlock()
+	})
 
 	data := []byte("foo")
 	num := 20
@@ -1073,12 +1055,11 @@ func TestIgnoreDeleteUnignore(t *testing.T) {
 	}
 
 	done := make(chan struct{})
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		basicCheck(fs)
 		close(done)
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	if err := writeFile(fss, file, contents, 0644); err != nil {
 		panic(err)
@@ -1092,16 +1073,15 @@ func TestIgnoreDeleteUnignore(t *testing.T) {
 	}
 
 	done = make(chan struct{})
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		basicCheck(fs)
 		f := fs[0]
 		if !f.IsInvalid() {
 			t.Errorf("Received non-invalid index update")
 		}
 		close(done)
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	if err := m.SetIgnores("default", []string{"foobar"}); err != nil {
 		panic(err)
@@ -1114,8 +1094,7 @@ func TestIgnoreDeleteUnignore(t *testing.T) {
 	}
 
 	done = make(chan struct{})
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		basicCheck(fs)
 		f := fs[0]
 		if f.IsInvalid() {
@@ -1126,8 +1105,8 @@ func TestIgnoreDeleteUnignore(t *testing.T) {
 		}
 		l.Infoln(f)
 		close(done)
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	if err := fss.Remove(file); err != nil {
 		t.Fatal(err)
@@ -1153,8 +1132,7 @@ func TestRequestLastFileProgress(t *testing.T) {
 
 	done := make(chan struct{})
 
-	fc.mut.Lock()
-	fc.requestFn = func(_ context.Context, folder, name string, _ int64, _ int, _ []byte, _ bool) ([]byte, error) {
+	fc.RequestCalls(func(ctx context.Context, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
 		defer close(done)
 		progress, queued, rest, err := m.NeedFolderFiles(folder, 1, 10)
 		must(t, err)
@@ -1165,8 +1143,7 @@ func TestRequestLastFileProgress(t *testing.T) {
 			t.Error("Expected exactly one item in progress.")
 		}
 		return fc.fileData[name], nil
-	}
-	fc.mut.Unlock()
+	})
 
 	contents := []byte("test file contents\n")
 	fc.addFile("testfile", 0644, protocol.FileInfoTypeFile, contents)
@@ -1189,15 +1166,14 @@ func TestRequestIndexSenderPause(t *testing.T) {
 	defer cleanupModelAndRemoveDir(m, tfs.URI())
 
 	indexChan := make(chan []protocol.FileInfo)
-	fc.mut.Lock()
-	fc.indexFn = func(ctx context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(ctx context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case indexChan <- fs:
 		case <-done:
 		case <-ctx.Done():
 		}
-	}
-	fc.mut.Unlock()
+		return nil
+	})
 
 	var seq int64 = 1
 	files := []protocol.FileInfo{{Name: "foo", Size: 10, Version: protocol.Vector{}.Update(myID.Short()), Sequence: seq}}
@@ -1324,20 +1300,19 @@ func TestRequestIndexSenderClusterConfigBeforeStart(t *testing.T) {
 	defer close(done) // Must be the last thing to be deferred, thus first to run.
 	indexChan := make(chan []protocol.FileInfo, 1)
 	ccChan := make(chan protocol.ClusterConfig, 1)
-	fc.mut.Lock()
-	fc.indexFn = func(_ context.Context, folder string, fs []protocol.FileInfo) {
+	fc.setIndexFn(func(_ context.Context, folder string, fs []protocol.FileInfo) error {
 		select {
 		case indexChan <- fs:
 		case <-done:
 		}
-	}
-	fc.clusterConfigFn = func(cc protocol.ClusterConfig) {
+		return nil
+	})
+	fc.ClusterConfigCalls(func(cc protocol.ClusterConfig) {
 		select {
 		case ccChan <- cc:
 		case <-done:
 		}
-	}
-	fc.mut.Unlock()
+	})
 
 	m.ServeBackground()
 
@@ -1388,16 +1363,14 @@ func TestRequestReceiveEncryptedLocalNoSend(t *testing.T) {
 	indexChan := make(chan []protocol.FileInfo, 1)
 	done := make(chan struct{})
 	defer close(done)
-	fc := &fakeConnection{
-		id:    device1,
-		model: m,
-		indexFn: func(_ context.Context, _ string, fs []protocol.FileInfo) {
-			select {
-			case indexChan <- fs:
-			case <-done:
-			}
-		},
-	}
+	fc := newFakeConnection(device1, m)
+	fc.setIndexFn(func(_ context.Context, _ string, fs []protocol.FileInfo) error {
+		select {
+		case indexChan <- fs:
+		case <-done:
+		}
+		return nil
+	})
 	m.AddConnection(fc, protocol.Hello{})
 	m.ClusterConfig(device1, protocol.ClusterConfig{
 		Folders: []protocol.Folder{

+ 2 - 2
lib/protocol/benchmark_test.go

@@ -60,9 +60,9 @@ func benchmarkRequestsTLS(b *testing.B, conn0, conn1 net.Conn) {
 
 func benchmarkRequestsConnPair(b *testing.B, conn0, conn1 net.Conn) {
 	// Start up Connections on them
-	c0 := NewConnection(LocalDeviceID, conn0, conn0, testutils.NoopCloser{}, new(fakeModel), &testutils.FakeConnectionInfo{"c0"}, CompressionMetadata)
+	c0 := NewConnection(LocalDeviceID, conn0, conn0, testutils.NoopCloser{}, new(fakeModel), new(mockedConnectionInfo), CompressionMetadata)
 	c0.Start()
-	c1 := NewConnection(LocalDeviceID, conn1, conn1, testutils.NoopCloser{}, new(fakeModel), &testutils.FakeConnectionInfo{"c1"}, CompressionMetadata)
+	c1 := NewConnection(LocalDeviceID, conn1, conn1, testutils.NoopCloser{}, new(fakeModel), new(mockedConnectionInfo), CompressionMetadata)
 	c1.Start()
 
 	// Satisfy the assertions in the protocol by sending an initial cluster config

+ 0 - 3
lib/protocol/deviceid_test.go

@@ -1,8 +1,5 @@
 // Copyright (C) 2014 The Protocol Authors.
 
-//go:generate go run ../../proto/scripts/protofmt.go deviceid_test.proto
-//go:generate protoc -I ../../ -I . --gogofast_out=. deviceid_test.proto
-
 package protocol
 
 import "testing"

+ 24 - 20
lib/protocol/deviceid_test.pb.go

@@ -1,5 +1,5 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
-// source: deviceid_test.proto
+// source: lib/protocol/deviceid_test.proto
 
 package protocol
 
@@ -7,6 +7,7 @@ import (
 	fmt "fmt"
 	_ "github.com/gogo/protobuf/gogoproto"
 	proto "github.com/gogo/protobuf/proto"
+	_ "github.com/syncthing/syncthing/proto/ext"
 	io "io"
 	math "math"
 	math_bits "math/bits"
@@ -24,14 +25,14 @@ var _ = math.Inf
 const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 
 type TestOldDeviceID struct {
-	Test []byte `protobuf:"bytes,1,opt,name=test,proto3" json:"test,omitempty"`
+	Test []byte `protobuf:"bytes,1,opt,name=test,proto3" json:"test" xml:"test"`
 }
 
 func (m *TestOldDeviceID) Reset()         { *m = TestOldDeviceID{} }
 func (m *TestOldDeviceID) String() string { return proto.CompactTextString(m) }
 func (*TestOldDeviceID) ProtoMessage()    {}
 func (*TestOldDeviceID) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a5b590761a4231d0, []int{0}
+	return fileDescriptor_f4a75253a19e48a2, []int{0}
 }
 func (m *TestOldDeviceID) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -61,14 +62,14 @@ func (m *TestOldDeviceID) XXX_DiscardUnknown() {
 var xxx_messageInfo_TestOldDeviceID proto.InternalMessageInfo
 
 type TestNewDeviceID struct {
-	Test DeviceID `protobuf:"bytes,1,opt,name=test,proto3,customtype=DeviceID" json:"test"`
+	Test DeviceID `protobuf:"bytes,1,opt,name=test,proto3,customtype=DeviceID" json:"test" xml:"test"`
 }
 
 func (m *TestNewDeviceID) Reset()         { *m = TestNewDeviceID{} }
 func (m *TestNewDeviceID) String() string { return proto.CompactTextString(m) }
 func (*TestNewDeviceID) ProtoMessage()    {}
 func (*TestNewDeviceID) Descriptor() ([]byte, []int) {
-	return fileDescriptor_a5b590761a4231d0, []int{1}
+	return fileDescriptor_f4a75253a19e48a2, []int{1}
 }
 func (m *TestNewDeviceID) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -102,22 +103,25 @@ func init() {
 	proto.RegisterType((*TestNewDeviceID)(nil), "protocol.TestNewDeviceID")
 }
 
-func init() { proto.RegisterFile("deviceid_test.proto", fileDescriptor_a5b590761a4231d0) }
+func init() { proto.RegisterFile("lib/protocol/deviceid_test.proto", fileDescriptor_f4a75253a19e48a2) }
 
-var fileDescriptor_a5b590761a4231d0 = []byte{
-	// 182 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0x49, 0x2d, 0xcb,
-	0x4c, 0x4e, 0xcd, 0x4c, 0x89, 0x2f, 0x49, 0x2d, 0x2e, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
-	0xe2, 0x00, 0x53, 0xc9, 0xf9, 0x39, 0x52, 0xca, 0x45, 0xa9, 0x05, 0xf9, 0xc5, 0xfa, 0x60, 0x7e,
-	0x52, 0x69, 0x9a, 0x7e, 0x7a, 0x7e, 0x7a, 0x3e, 0x98, 0x03, 0x66, 0x41, 0x94, 0x2b, 0xa9, 0x72,
-	0xf1, 0x87, 0xa4, 0x16, 0x97, 0xf8, 0xe7, 0xa4, 0xb8, 0x80, 0x0d, 0xf3, 0x74, 0x11, 0x12, 0xe2,
-	0x62, 0x01, 0x99, 0x27, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x13, 0x04, 0x66, 0x2b, 0x99, 0x43, 0x94,
-	0xf9, 0xa5, 0x96, 0xc3, 0x95, 0xa9, 0x20, 0x2b, 0x73, 0x12, 0x38, 0x71, 0x4f, 0x9e, 0xe1, 0xd6,
-	0x3d, 0x79, 0x0e, 0x98, 0x3c, 0x44, 0xa3, 0x93, 0xc6, 0x89, 0x87, 0x72, 0x0c, 0x17, 0x1e, 0xca,
-	0x31, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x0c, 0x2f, 0x1e,
-	0xc9, 0x31, 0x4c, 0x78, 0x2c, 0xc7, 0xb0, 0xe0, 0xb1, 0x1c, 0xe3, 0x85, 0xc7, 0x72, 0x0c, 0x37,
-	0x1e, 0xcb, 0x31, 0x24, 0xb1, 0x81, 0x1d, 0x64, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xe3, 0x96,
-	0x3e, 0xc0, 0xd6, 0x00, 0x00, 0x00,
+var fileDescriptor_f4a75253a19e48a2 = []byte{
+	// 237 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xc8, 0xc9, 0x4c, 0xd2,
+	0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0x4f, 0x49, 0x2d, 0xcb, 0x4c, 0x4e, 0xcd,
+	0x4c, 0x89, 0x2f, 0x49, 0x2d, 0x2e, 0xd1, 0x03, 0x0b, 0x0b, 0x71, 0xc0, 0x64, 0xa5, 0x38, 0x53,
+	0x2b, 0xa0, 0x82, 0x52, 0xca, 0x45, 0xa9, 0x05, 0xf9, 0xc5, 0x10, 0x8d, 0x49, 0xa5, 0x69, 0xfa,
+	0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0x0e, 0x98, 0x05, 0x51, 0xa4, 0x64, 0xcb, 0xc5, 0x1f, 0x92, 0x5a,
+	0x5c, 0xe2, 0x9f, 0x93, 0xe2, 0x02, 0x36, 0xd7, 0xd3, 0x45, 0x48, 0x8b, 0x8b, 0x05, 0x64, 0xb4,
+	0x04, 0xa3, 0x02, 0xa3, 0x06, 0x8f, 0x93, 0xd8, 0xab, 0x7b, 0xf2, 0x60, 0xfe, 0xa7, 0x7b, 0xf2,
+	0x5c, 0x15, 0xb9, 0x39, 0x56, 0x4a, 0x20, 0x8e, 0x52, 0x10, 0x58, 0x4c, 0x29, 0x10, 0xa2, 0xdd,
+	0x2f, 0xb5, 0x1c, 0xae, 0xdd, 0x0e, 0x45, 0xbb, 0xd6, 0x89, 0x7b, 0xf2, 0x0c, 0xb7, 0xee, 0xc9,
+	0x73, 0xc0, 0xe4, 0xb1, 0x1b, 0xd7, 0x71, 0x41, 0x85, 0x11, 0x62, 0xa4, 0x93, 0xef, 0x89, 0x87,
+	0x72, 0x0c, 0x17, 0x1e, 0xca, 0x31, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x84,
+	0xc7, 0x72, 0x0c, 0x0b, 0x1e, 0xcb, 0x31, 0x5e, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43,
+	0x94, 0x76, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x71, 0x65, 0x5e,
+	0x72, 0x49, 0x46, 0x66, 0x5e, 0x3a, 0x12, 0x0b, 0x39, 0xb8, 0x92, 0xd8, 0xc0, 0x2c, 0x63, 0x40,
+	0x00, 0x00, 0x00, 0xff, 0xff, 0x9a, 0x0a, 0x77, 0x43, 0x45, 0x01, 0x00, 0x00,
 }
 
 func (m *TestOldDeviceID) Marshal() (dAtA []byte, err error) {

+ 0 - 23
lib/protocol/deviceid_test.proto

@@ -1,23 +0,0 @@
-
-syntax = "proto3";
-
-package protocol;
-
-import "repos/protobuf/gogoproto/gogo.proto";
-
-option (gogoproto.goproto_getters_all) = false;
-option (gogoproto.sizer_all) = false;
-option (gogoproto.protosizer_all) = true;
-option (gogoproto.goproto_enum_stringer_all) = false;
-option (gogoproto.goproto_enum_prefix_all) = false;
-option (gogoproto.goproto_unkeyed_all) = false;
-option (gogoproto.goproto_unrecognized_all) = false;
-option (gogoproto.goproto_sizecache_all) = false;
-
-message TestOldDeviceID {
-    bytes test = 1;
-}
-
-message TestNewDeviceID {
-    bytes test = 1 [(gogoproto.customtype) = "DeviceID", (gogoproto.nullable) = false];
-}

+ 490 - 0
lib/protocol/mocked_connection_info_test.go

@@ -0,0 +1,490 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package protocol
+
+import (
+	"net"
+	"sync"
+	"time"
+)
+
+type mockedConnectionInfo struct {
+	CryptoStub        func() string
+	cryptoMutex       sync.RWMutex
+	cryptoArgsForCall []struct {
+	}
+	cryptoReturns struct {
+		result1 string
+	}
+	cryptoReturnsOnCall map[int]struct {
+		result1 string
+	}
+	EstablishedAtStub        func() time.Time
+	establishedAtMutex       sync.RWMutex
+	establishedAtArgsForCall []struct {
+	}
+	establishedAtReturns struct {
+		result1 time.Time
+	}
+	establishedAtReturnsOnCall map[int]struct {
+		result1 time.Time
+	}
+	PriorityStub        func() int
+	priorityMutex       sync.RWMutex
+	priorityArgsForCall []struct {
+	}
+	priorityReturns struct {
+		result1 int
+	}
+	priorityReturnsOnCall map[int]struct {
+		result1 int
+	}
+	RemoteAddrStub        func() net.Addr
+	remoteAddrMutex       sync.RWMutex
+	remoteAddrArgsForCall []struct {
+	}
+	remoteAddrReturns struct {
+		result1 net.Addr
+	}
+	remoteAddrReturnsOnCall map[int]struct {
+		result1 net.Addr
+	}
+	StringStub        func() string
+	stringMutex       sync.RWMutex
+	stringArgsForCall []struct {
+	}
+	stringReturns struct {
+		result1 string
+	}
+	stringReturnsOnCall map[int]struct {
+		result1 string
+	}
+	TransportStub        func() string
+	transportMutex       sync.RWMutex
+	transportArgsForCall []struct {
+	}
+	transportReturns struct {
+		result1 string
+	}
+	transportReturnsOnCall map[int]struct {
+		result1 string
+	}
+	TypeStub        func() string
+	typeMutex       sync.RWMutex
+	typeArgsForCall []struct {
+	}
+	typeReturns struct {
+		result1 string
+	}
+	typeReturnsOnCall map[int]struct {
+		result1 string
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *mockedConnectionInfo) Crypto() string {
+	fake.cryptoMutex.Lock()
+	ret, specificReturn := fake.cryptoReturnsOnCall[len(fake.cryptoArgsForCall)]
+	fake.cryptoArgsForCall = append(fake.cryptoArgsForCall, struct {
+	}{})
+	stub := fake.CryptoStub
+	fakeReturns := fake.cryptoReturns
+	fake.recordInvocation("Crypto", []interface{}{})
+	fake.cryptoMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *mockedConnectionInfo) CryptoCallCount() int {
+	fake.cryptoMutex.RLock()
+	defer fake.cryptoMutex.RUnlock()
+	return len(fake.cryptoArgsForCall)
+}
+
+func (fake *mockedConnectionInfo) CryptoCalls(stub func() string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = stub
+}
+
+func (fake *mockedConnectionInfo) CryptoReturns(result1 string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = nil
+	fake.cryptoReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) CryptoReturnsOnCall(i int, result1 string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = nil
+	if fake.cryptoReturnsOnCall == nil {
+		fake.cryptoReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.cryptoReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) EstablishedAt() time.Time {
+	fake.establishedAtMutex.Lock()
+	ret, specificReturn := fake.establishedAtReturnsOnCall[len(fake.establishedAtArgsForCall)]
+	fake.establishedAtArgsForCall = append(fake.establishedAtArgsForCall, struct {
+	}{})
+	stub := fake.EstablishedAtStub
+	fakeReturns := fake.establishedAtReturns
+	fake.recordInvocation("EstablishedAt", []interface{}{})
+	fake.establishedAtMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *mockedConnectionInfo) EstablishedAtCallCount() int {
+	fake.establishedAtMutex.RLock()
+	defer fake.establishedAtMutex.RUnlock()
+	return len(fake.establishedAtArgsForCall)
+}
+
+func (fake *mockedConnectionInfo) EstablishedAtCalls(stub func() time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = stub
+}
+
+func (fake *mockedConnectionInfo) EstablishedAtReturns(result1 time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = nil
+	fake.establishedAtReturns = struct {
+		result1 time.Time
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) EstablishedAtReturnsOnCall(i int, result1 time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = nil
+	if fake.establishedAtReturnsOnCall == nil {
+		fake.establishedAtReturnsOnCall = make(map[int]struct {
+			result1 time.Time
+		})
+	}
+	fake.establishedAtReturnsOnCall[i] = struct {
+		result1 time.Time
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) Priority() int {
+	fake.priorityMutex.Lock()
+	ret, specificReturn := fake.priorityReturnsOnCall[len(fake.priorityArgsForCall)]
+	fake.priorityArgsForCall = append(fake.priorityArgsForCall, struct {
+	}{})
+	stub := fake.PriorityStub
+	fakeReturns := fake.priorityReturns
+	fake.recordInvocation("Priority", []interface{}{})
+	fake.priorityMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *mockedConnectionInfo) PriorityCallCount() int {
+	fake.priorityMutex.RLock()
+	defer fake.priorityMutex.RUnlock()
+	return len(fake.priorityArgsForCall)
+}
+
+func (fake *mockedConnectionInfo) PriorityCalls(stub func() int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = stub
+}
+
+func (fake *mockedConnectionInfo) PriorityReturns(result1 int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = nil
+	fake.priorityReturns = struct {
+		result1 int
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) PriorityReturnsOnCall(i int, result1 int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = nil
+	if fake.priorityReturnsOnCall == nil {
+		fake.priorityReturnsOnCall = make(map[int]struct {
+			result1 int
+		})
+	}
+	fake.priorityReturnsOnCall[i] = struct {
+		result1 int
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) RemoteAddr() net.Addr {
+	fake.remoteAddrMutex.Lock()
+	ret, specificReturn := fake.remoteAddrReturnsOnCall[len(fake.remoteAddrArgsForCall)]
+	fake.remoteAddrArgsForCall = append(fake.remoteAddrArgsForCall, struct {
+	}{})
+	stub := fake.RemoteAddrStub
+	fakeReturns := fake.remoteAddrReturns
+	fake.recordInvocation("RemoteAddr", []interface{}{})
+	fake.remoteAddrMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *mockedConnectionInfo) RemoteAddrCallCount() int {
+	fake.remoteAddrMutex.RLock()
+	defer fake.remoteAddrMutex.RUnlock()
+	return len(fake.remoteAddrArgsForCall)
+}
+
+func (fake *mockedConnectionInfo) RemoteAddrCalls(stub func() net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = stub
+}
+
+func (fake *mockedConnectionInfo) RemoteAddrReturns(result1 net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = nil
+	fake.remoteAddrReturns = struct {
+		result1 net.Addr
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) RemoteAddrReturnsOnCall(i int, result1 net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = nil
+	if fake.remoteAddrReturnsOnCall == nil {
+		fake.remoteAddrReturnsOnCall = make(map[int]struct {
+			result1 net.Addr
+		})
+	}
+	fake.remoteAddrReturnsOnCall[i] = struct {
+		result1 net.Addr
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) String() string {
+	fake.stringMutex.Lock()
+	ret, specificReturn := fake.stringReturnsOnCall[len(fake.stringArgsForCall)]
+	fake.stringArgsForCall = append(fake.stringArgsForCall, struct {
+	}{})
+	stub := fake.StringStub
+	fakeReturns := fake.stringReturns
+	fake.recordInvocation("String", []interface{}{})
+	fake.stringMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *mockedConnectionInfo) StringCallCount() int {
+	fake.stringMutex.RLock()
+	defer fake.stringMutex.RUnlock()
+	return len(fake.stringArgsForCall)
+}
+
+func (fake *mockedConnectionInfo) StringCalls(stub func() string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = stub
+}
+
+func (fake *mockedConnectionInfo) StringReturns(result1 string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = nil
+	fake.stringReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) StringReturnsOnCall(i int, result1 string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = nil
+	if fake.stringReturnsOnCall == nil {
+		fake.stringReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.stringReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) Transport() string {
+	fake.transportMutex.Lock()
+	ret, specificReturn := fake.transportReturnsOnCall[len(fake.transportArgsForCall)]
+	fake.transportArgsForCall = append(fake.transportArgsForCall, struct {
+	}{})
+	stub := fake.TransportStub
+	fakeReturns := fake.transportReturns
+	fake.recordInvocation("Transport", []interface{}{})
+	fake.transportMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *mockedConnectionInfo) TransportCallCount() int {
+	fake.transportMutex.RLock()
+	defer fake.transportMutex.RUnlock()
+	return len(fake.transportArgsForCall)
+}
+
+func (fake *mockedConnectionInfo) TransportCalls(stub func() string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = stub
+}
+
+func (fake *mockedConnectionInfo) TransportReturns(result1 string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = nil
+	fake.transportReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) TransportReturnsOnCall(i int, result1 string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = nil
+	if fake.transportReturnsOnCall == nil {
+		fake.transportReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.transportReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) Type() string {
+	fake.typeMutex.Lock()
+	ret, specificReturn := fake.typeReturnsOnCall[len(fake.typeArgsForCall)]
+	fake.typeArgsForCall = append(fake.typeArgsForCall, struct {
+	}{})
+	stub := fake.TypeStub
+	fakeReturns := fake.typeReturns
+	fake.recordInvocation("Type", []interface{}{})
+	fake.typeMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *mockedConnectionInfo) TypeCallCount() int {
+	fake.typeMutex.RLock()
+	defer fake.typeMutex.RUnlock()
+	return len(fake.typeArgsForCall)
+}
+
+func (fake *mockedConnectionInfo) TypeCalls(stub func() string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = stub
+}
+
+func (fake *mockedConnectionInfo) TypeReturns(result1 string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = nil
+	fake.typeReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) TypeReturnsOnCall(i int, result1 string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = nil
+	if fake.typeReturnsOnCall == nil {
+		fake.typeReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.typeReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *mockedConnectionInfo) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.cryptoMutex.RLock()
+	defer fake.cryptoMutex.RUnlock()
+	fake.establishedAtMutex.RLock()
+	defer fake.establishedAtMutex.RUnlock()
+	fake.priorityMutex.RLock()
+	defer fake.priorityMutex.RUnlock()
+	fake.remoteAddrMutex.RLock()
+	defer fake.remoteAddrMutex.RUnlock()
+	fake.stringMutex.RLock()
+	defer fake.stringMutex.RUnlock()
+	fake.transportMutex.RLock()
+	defer fake.transportMutex.RUnlock()
+	fake.typeMutex.RLock()
+	defer fake.typeMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *mockedConnectionInfo) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}

+ 1112 - 0
lib/protocol/mocks/connection.go

@@ -0,0 +1,1112 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"context"
+	"net"
+	"sync"
+	"time"
+
+	"github.com/syncthing/syncthing/lib/protocol"
+)
+
+type Connection struct {
+	CloseStub        func(error)
+	closeMutex       sync.RWMutex
+	closeArgsForCall []struct {
+		arg1 error
+	}
+	ClosedStub        func() bool
+	closedMutex       sync.RWMutex
+	closedArgsForCall []struct {
+	}
+	closedReturns struct {
+		result1 bool
+	}
+	closedReturnsOnCall map[int]struct {
+		result1 bool
+	}
+	ClusterConfigStub        func(protocol.ClusterConfig)
+	clusterConfigMutex       sync.RWMutex
+	clusterConfigArgsForCall []struct {
+		arg1 protocol.ClusterConfig
+	}
+	CryptoStub        func() string
+	cryptoMutex       sync.RWMutex
+	cryptoArgsForCall []struct {
+	}
+	cryptoReturns struct {
+		result1 string
+	}
+	cryptoReturnsOnCall map[int]struct {
+		result1 string
+	}
+	DownloadProgressStub        func(context.Context, string, []protocol.FileDownloadProgressUpdate)
+	downloadProgressMutex       sync.RWMutex
+	downloadProgressArgsForCall []struct {
+		arg1 context.Context
+		arg2 string
+		arg3 []protocol.FileDownloadProgressUpdate
+	}
+	EstablishedAtStub        func() time.Time
+	establishedAtMutex       sync.RWMutex
+	establishedAtArgsForCall []struct {
+	}
+	establishedAtReturns struct {
+		result1 time.Time
+	}
+	establishedAtReturnsOnCall map[int]struct {
+		result1 time.Time
+	}
+	IDStub        func() protocol.DeviceID
+	iDMutex       sync.RWMutex
+	iDArgsForCall []struct {
+	}
+	iDReturns struct {
+		result1 protocol.DeviceID
+	}
+	iDReturnsOnCall map[int]struct {
+		result1 protocol.DeviceID
+	}
+	IndexStub        func(context.Context, string, []protocol.FileInfo) error
+	indexMutex       sync.RWMutex
+	indexArgsForCall []struct {
+		arg1 context.Context
+		arg2 string
+		arg3 []protocol.FileInfo
+	}
+	indexReturns struct {
+		result1 error
+	}
+	indexReturnsOnCall map[int]struct {
+		result1 error
+	}
+	IndexUpdateStub        func(context.Context, string, []protocol.FileInfo) error
+	indexUpdateMutex       sync.RWMutex
+	indexUpdateArgsForCall []struct {
+		arg1 context.Context
+		arg2 string
+		arg3 []protocol.FileInfo
+	}
+	indexUpdateReturns struct {
+		result1 error
+	}
+	indexUpdateReturnsOnCall map[int]struct {
+		result1 error
+	}
+	PriorityStub        func() int
+	priorityMutex       sync.RWMutex
+	priorityArgsForCall []struct {
+	}
+	priorityReturns struct {
+		result1 int
+	}
+	priorityReturnsOnCall map[int]struct {
+		result1 int
+	}
+	RemoteAddrStub        func() net.Addr
+	remoteAddrMutex       sync.RWMutex
+	remoteAddrArgsForCall []struct {
+	}
+	remoteAddrReturns struct {
+		result1 net.Addr
+	}
+	remoteAddrReturnsOnCall map[int]struct {
+		result1 net.Addr
+	}
+	RequestStub        func(context.Context, string, string, int, int64, int, []byte, uint32, bool) ([]byte, error)
+	requestMutex       sync.RWMutex
+	requestArgsForCall []struct {
+		arg1 context.Context
+		arg2 string
+		arg3 string
+		arg4 int
+		arg5 int64
+		arg6 int
+		arg7 []byte
+		arg8 uint32
+		arg9 bool
+	}
+	requestReturns struct {
+		result1 []byte
+		result2 error
+	}
+	requestReturnsOnCall map[int]struct {
+		result1 []byte
+		result2 error
+	}
+	StartStub        func()
+	startMutex       sync.RWMutex
+	startArgsForCall []struct {
+	}
+	StatisticsStub        func() protocol.Statistics
+	statisticsMutex       sync.RWMutex
+	statisticsArgsForCall []struct {
+	}
+	statisticsReturns struct {
+		result1 protocol.Statistics
+	}
+	statisticsReturnsOnCall map[int]struct {
+		result1 protocol.Statistics
+	}
+	StringStub        func() string
+	stringMutex       sync.RWMutex
+	stringArgsForCall []struct {
+	}
+	stringReturns struct {
+		result1 string
+	}
+	stringReturnsOnCall map[int]struct {
+		result1 string
+	}
+	TransportStub        func() string
+	transportMutex       sync.RWMutex
+	transportArgsForCall []struct {
+	}
+	transportReturns struct {
+		result1 string
+	}
+	transportReturnsOnCall map[int]struct {
+		result1 string
+	}
+	TypeStub        func() string
+	typeMutex       sync.RWMutex
+	typeArgsForCall []struct {
+	}
+	typeReturns struct {
+		result1 string
+	}
+	typeReturnsOnCall map[int]struct {
+		result1 string
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *Connection) Close(arg1 error) {
+	fake.closeMutex.Lock()
+	fake.closeArgsForCall = append(fake.closeArgsForCall, struct {
+		arg1 error
+	}{arg1})
+	stub := fake.CloseStub
+	fake.recordInvocation("Close", []interface{}{arg1})
+	fake.closeMutex.Unlock()
+	if stub != nil {
+		fake.CloseStub(arg1)
+	}
+}
+
+func (fake *Connection) CloseCallCount() int {
+	fake.closeMutex.RLock()
+	defer fake.closeMutex.RUnlock()
+	return len(fake.closeArgsForCall)
+}
+
+func (fake *Connection) CloseCalls(stub func(error)) {
+	fake.closeMutex.Lock()
+	defer fake.closeMutex.Unlock()
+	fake.CloseStub = stub
+}
+
+func (fake *Connection) CloseArgsForCall(i int) error {
+	fake.closeMutex.RLock()
+	defer fake.closeMutex.RUnlock()
+	argsForCall := fake.closeArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Connection) Closed() bool {
+	fake.closedMutex.Lock()
+	ret, specificReturn := fake.closedReturnsOnCall[len(fake.closedArgsForCall)]
+	fake.closedArgsForCall = append(fake.closedArgsForCall, struct {
+	}{})
+	stub := fake.ClosedStub
+	fakeReturns := fake.closedReturns
+	fake.recordInvocation("Closed", []interface{}{})
+	fake.closedMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) ClosedCallCount() int {
+	fake.closedMutex.RLock()
+	defer fake.closedMutex.RUnlock()
+	return len(fake.closedArgsForCall)
+}
+
+func (fake *Connection) ClosedCalls(stub func() bool) {
+	fake.closedMutex.Lock()
+	defer fake.closedMutex.Unlock()
+	fake.ClosedStub = stub
+}
+
+func (fake *Connection) ClosedReturns(result1 bool) {
+	fake.closedMutex.Lock()
+	defer fake.closedMutex.Unlock()
+	fake.ClosedStub = nil
+	fake.closedReturns = struct {
+		result1 bool
+	}{result1}
+}
+
+func (fake *Connection) ClosedReturnsOnCall(i int, result1 bool) {
+	fake.closedMutex.Lock()
+	defer fake.closedMutex.Unlock()
+	fake.ClosedStub = nil
+	if fake.closedReturnsOnCall == nil {
+		fake.closedReturnsOnCall = make(map[int]struct {
+			result1 bool
+		})
+	}
+	fake.closedReturnsOnCall[i] = struct {
+		result1 bool
+	}{result1}
+}
+
+func (fake *Connection) ClusterConfig(arg1 protocol.ClusterConfig) {
+	fake.clusterConfigMutex.Lock()
+	fake.clusterConfigArgsForCall = append(fake.clusterConfigArgsForCall, struct {
+		arg1 protocol.ClusterConfig
+	}{arg1})
+	stub := fake.ClusterConfigStub
+	fake.recordInvocation("ClusterConfig", []interface{}{arg1})
+	fake.clusterConfigMutex.Unlock()
+	if stub != nil {
+		fake.ClusterConfigStub(arg1)
+	}
+}
+
+func (fake *Connection) ClusterConfigCallCount() int {
+	fake.clusterConfigMutex.RLock()
+	defer fake.clusterConfigMutex.RUnlock()
+	return len(fake.clusterConfigArgsForCall)
+}
+
+func (fake *Connection) ClusterConfigCalls(stub func(protocol.ClusterConfig)) {
+	fake.clusterConfigMutex.Lock()
+	defer fake.clusterConfigMutex.Unlock()
+	fake.ClusterConfigStub = stub
+}
+
+func (fake *Connection) ClusterConfigArgsForCall(i int) protocol.ClusterConfig {
+	fake.clusterConfigMutex.RLock()
+	defer fake.clusterConfigMutex.RUnlock()
+	argsForCall := fake.clusterConfigArgsForCall[i]
+	return argsForCall.arg1
+}
+
+func (fake *Connection) Crypto() string {
+	fake.cryptoMutex.Lock()
+	ret, specificReturn := fake.cryptoReturnsOnCall[len(fake.cryptoArgsForCall)]
+	fake.cryptoArgsForCall = append(fake.cryptoArgsForCall, struct {
+	}{})
+	stub := fake.CryptoStub
+	fakeReturns := fake.cryptoReturns
+	fake.recordInvocation("Crypto", []interface{}{})
+	fake.cryptoMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) CryptoCallCount() int {
+	fake.cryptoMutex.RLock()
+	defer fake.cryptoMutex.RUnlock()
+	return len(fake.cryptoArgsForCall)
+}
+
+func (fake *Connection) CryptoCalls(stub func() string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = stub
+}
+
+func (fake *Connection) CryptoReturns(result1 string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = nil
+	fake.cryptoReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Connection) CryptoReturnsOnCall(i int, result1 string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = nil
+	if fake.cryptoReturnsOnCall == nil {
+		fake.cryptoReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.cryptoReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Connection) DownloadProgress(arg1 context.Context, arg2 string, arg3 []protocol.FileDownloadProgressUpdate) {
+	var arg3Copy []protocol.FileDownloadProgressUpdate
+	if arg3 != nil {
+		arg3Copy = make([]protocol.FileDownloadProgressUpdate, len(arg3))
+		copy(arg3Copy, arg3)
+	}
+	fake.downloadProgressMutex.Lock()
+	fake.downloadProgressArgsForCall = append(fake.downloadProgressArgsForCall, struct {
+		arg1 context.Context
+		arg2 string
+		arg3 []protocol.FileDownloadProgressUpdate
+	}{arg1, arg2, arg3Copy})
+	stub := fake.DownloadProgressStub
+	fake.recordInvocation("DownloadProgress", []interface{}{arg1, arg2, arg3Copy})
+	fake.downloadProgressMutex.Unlock()
+	if stub != nil {
+		fake.DownloadProgressStub(arg1, arg2, arg3)
+	}
+}
+
+func (fake *Connection) DownloadProgressCallCount() int {
+	fake.downloadProgressMutex.RLock()
+	defer fake.downloadProgressMutex.RUnlock()
+	return len(fake.downloadProgressArgsForCall)
+}
+
+func (fake *Connection) DownloadProgressCalls(stub func(context.Context, string, []protocol.FileDownloadProgressUpdate)) {
+	fake.downloadProgressMutex.Lock()
+	defer fake.downloadProgressMutex.Unlock()
+	fake.DownloadProgressStub = stub
+}
+
+func (fake *Connection) DownloadProgressArgsForCall(i int) (context.Context, string, []protocol.FileDownloadProgressUpdate) {
+	fake.downloadProgressMutex.RLock()
+	defer fake.downloadProgressMutex.RUnlock()
+	argsForCall := fake.downloadProgressArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Connection) EstablishedAt() time.Time {
+	fake.establishedAtMutex.Lock()
+	ret, specificReturn := fake.establishedAtReturnsOnCall[len(fake.establishedAtArgsForCall)]
+	fake.establishedAtArgsForCall = append(fake.establishedAtArgsForCall, struct {
+	}{})
+	stub := fake.EstablishedAtStub
+	fakeReturns := fake.establishedAtReturns
+	fake.recordInvocation("EstablishedAt", []interface{}{})
+	fake.establishedAtMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) EstablishedAtCallCount() int {
+	fake.establishedAtMutex.RLock()
+	defer fake.establishedAtMutex.RUnlock()
+	return len(fake.establishedAtArgsForCall)
+}
+
+func (fake *Connection) EstablishedAtCalls(stub func() time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = stub
+}
+
+func (fake *Connection) EstablishedAtReturns(result1 time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = nil
+	fake.establishedAtReturns = struct {
+		result1 time.Time
+	}{result1}
+}
+
+func (fake *Connection) EstablishedAtReturnsOnCall(i int, result1 time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = nil
+	if fake.establishedAtReturnsOnCall == nil {
+		fake.establishedAtReturnsOnCall = make(map[int]struct {
+			result1 time.Time
+		})
+	}
+	fake.establishedAtReturnsOnCall[i] = struct {
+		result1 time.Time
+	}{result1}
+}
+
+func (fake *Connection) ID() protocol.DeviceID {
+	fake.iDMutex.Lock()
+	ret, specificReturn := fake.iDReturnsOnCall[len(fake.iDArgsForCall)]
+	fake.iDArgsForCall = append(fake.iDArgsForCall, struct {
+	}{})
+	stub := fake.IDStub
+	fakeReturns := fake.iDReturns
+	fake.recordInvocation("ID", []interface{}{})
+	fake.iDMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) IDCallCount() int {
+	fake.iDMutex.RLock()
+	defer fake.iDMutex.RUnlock()
+	return len(fake.iDArgsForCall)
+}
+
+func (fake *Connection) IDCalls(stub func() protocol.DeviceID) {
+	fake.iDMutex.Lock()
+	defer fake.iDMutex.Unlock()
+	fake.IDStub = stub
+}
+
+func (fake *Connection) IDReturns(result1 protocol.DeviceID) {
+	fake.iDMutex.Lock()
+	defer fake.iDMutex.Unlock()
+	fake.IDStub = nil
+	fake.iDReturns = struct {
+		result1 protocol.DeviceID
+	}{result1}
+}
+
+func (fake *Connection) IDReturnsOnCall(i int, result1 protocol.DeviceID) {
+	fake.iDMutex.Lock()
+	defer fake.iDMutex.Unlock()
+	fake.IDStub = nil
+	if fake.iDReturnsOnCall == nil {
+		fake.iDReturnsOnCall = make(map[int]struct {
+			result1 protocol.DeviceID
+		})
+	}
+	fake.iDReturnsOnCall[i] = struct {
+		result1 protocol.DeviceID
+	}{result1}
+}
+
+func (fake *Connection) Index(arg1 context.Context, arg2 string, arg3 []protocol.FileInfo) error {
+	var arg3Copy []protocol.FileInfo
+	if arg3 != nil {
+		arg3Copy = make([]protocol.FileInfo, len(arg3))
+		copy(arg3Copy, arg3)
+	}
+	fake.indexMutex.Lock()
+	ret, specificReturn := fake.indexReturnsOnCall[len(fake.indexArgsForCall)]
+	fake.indexArgsForCall = append(fake.indexArgsForCall, struct {
+		arg1 context.Context
+		arg2 string
+		arg3 []protocol.FileInfo
+	}{arg1, arg2, arg3Copy})
+	stub := fake.IndexStub
+	fakeReturns := fake.indexReturns
+	fake.recordInvocation("Index", []interface{}{arg1, arg2, arg3Copy})
+	fake.indexMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) IndexCallCount() int {
+	fake.indexMutex.RLock()
+	defer fake.indexMutex.RUnlock()
+	return len(fake.indexArgsForCall)
+}
+
+func (fake *Connection) IndexCalls(stub func(context.Context, string, []protocol.FileInfo) error) {
+	fake.indexMutex.Lock()
+	defer fake.indexMutex.Unlock()
+	fake.IndexStub = stub
+}
+
+func (fake *Connection) IndexArgsForCall(i int) (context.Context, string, []protocol.FileInfo) {
+	fake.indexMutex.RLock()
+	defer fake.indexMutex.RUnlock()
+	argsForCall := fake.indexArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Connection) IndexReturns(result1 error) {
+	fake.indexMutex.Lock()
+	defer fake.indexMutex.Unlock()
+	fake.IndexStub = nil
+	fake.indexReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Connection) IndexReturnsOnCall(i int, result1 error) {
+	fake.indexMutex.Lock()
+	defer fake.indexMutex.Unlock()
+	fake.IndexStub = nil
+	if fake.indexReturnsOnCall == nil {
+		fake.indexReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.indexReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Connection) IndexUpdate(arg1 context.Context, arg2 string, arg3 []protocol.FileInfo) error {
+	var arg3Copy []protocol.FileInfo
+	if arg3 != nil {
+		arg3Copy = make([]protocol.FileInfo, len(arg3))
+		copy(arg3Copy, arg3)
+	}
+	fake.indexUpdateMutex.Lock()
+	ret, specificReturn := fake.indexUpdateReturnsOnCall[len(fake.indexUpdateArgsForCall)]
+	fake.indexUpdateArgsForCall = append(fake.indexUpdateArgsForCall, struct {
+		arg1 context.Context
+		arg2 string
+		arg3 []protocol.FileInfo
+	}{arg1, arg2, arg3Copy})
+	stub := fake.IndexUpdateStub
+	fakeReturns := fake.indexUpdateReturns
+	fake.recordInvocation("IndexUpdate", []interface{}{arg1, arg2, arg3Copy})
+	fake.indexUpdateMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3)
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) IndexUpdateCallCount() int {
+	fake.indexUpdateMutex.RLock()
+	defer fake.indexUpdateMutex.RUnlock()
+	return len(fake.indexUpdateArgsForCall)
+}
+
+func (fake *Connection) IndexUpdateCalls(stub func(context.Context, string, []protocol.FileInfo) error) {
+	fake.indexUpdateMutex.Lock()
+	defer fake.indexUpdateMutex.Unlock()
+	fake.IndexUpdateStub = stub
+}
+
+func (fake *Connection) IndexUpdateArgsForCall(i int) (context.Context, string, []protocol.FileInfo) {
+	fake.indexUpdateMutex.RLock()
+	defer fake.indexUpdateMutex.RUnlock()
+	argsForCall := fake.indexUpdateArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
+}
+
+func (fake *Connection) IndexUpdateReturns(result1 error) {
+	fake.indexUpdateMutex.Lock()
+	defer fake.indexUpdateMutex.Unlock()
+	fake.IndexUpdateStub = nil
+	fake.indexUpdateReturns = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Connection) IndexUpdateReturnsOnCall(i int, result1 error) {
+	fake.indexUpdateMutex.Lock()
+	defer fake.indexUpdateMutex.Unlock()
+	fake.IndexUpdateStub = nil
+	if fake.indexUpdateReturnsOnCall == nil {
+		fake.indexUpdateReturnsOnCall = make(map[int]struct {
+			result1 error
+		})
+	}
+	fake.indexUpdateReturnsOnCall[i] = struct {
+		result1 error
+	}{result1}
+}
+
+func (fake *Connection) Priority() int {
+	fake.priorityMutex.Lock()
+	ret, specificReturn := fake.priorityReturnsOnCall[len(fake.priorityArgsForCall)]
+	fake.priorityArgsForCall = append(fake.priorityArgsForCall, struct {
+	}{})
+	stub := fake.PriorityStub
+	fakeReturns := fake.priorityReturns
+	fake.recordInvocation("Priority", []interface{}{})
+	fake.priorityMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) PriorityCallCount() int {
+	fake.priorityMutex.RLock()
+	defer fake.priorityMutex.RUnlock()
+	return len(fake.priorityArgsForCall)
+}
+
+func (fake *Connection) PriorityCalls(stub func() int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = stub
+}
+
+func (fake *Connection) PriorityReturns(result1 int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = nil
+	fake.priorityReturns = struct {
+		result1 int
+	}{result1}
+}
+
+func (fake *Connection) PriorityReturnsOnCall(i int, result1 int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = nil
+	if fake.priorityReturnsOnCall == nil {
+		fake.priorityReturnsOnCall = make(map[int]struct {
+			result1 int
+		})
+	}
+	fake.priorityReturnsOnCall[i] = struct {
+		result1 int
+	}{result1}
+}
+
+func (fake *Connection) RemoteAddr() net.Addr {
+	fake.remoteAddrMutex.Lock()
+	ret, specificReturn := fake.remoteAddrReturnsOnCall[len(fake.remoteAddrArgsForCall)]
+	fake.remoteAddrArgsForCall = append(fake.remoteAddrArgsForCall, struct {
+	}{})
+	stub := fake.RemoteAddrStub
+	fakeReturns := fake.remoteAddrReturns
+	fake.recordInvocation("RemoteAddr", []interface{}{})
+	fake.remoteAddrMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) RemoteAddrCallCount() int {
+	fake.remoteAddrMutex.RLock()
+	defer fake.remoteAddrMutex.RUnlock()
+	return len(fake.remoteAddrArgsForCall)
+}
+
+func (fake *Connection) RemoteAddrCalls(stub func() net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = stub
+}
+
+func (fake *Connection) RemoteAddrReturns(result1 net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = nil
+	fake.remoteAddrReturns = struct {
+		result1 net.Addr
+	}{result1}
+}
+
+func (fake *Connection) RemoteAddrReturnsOnCall(i int, result1 net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = nil
+	if fake.remoteAddrReturnsOnCall == nil {
+		fake.remoteAddrReturnsOnCall = make(map[int]struct {
+			result1 net.Addr
+		})
+	}
+	fake.remoteAddrReturnsOnCall[i] = struct {
+		result1 net.Addr
+	}{result1}
+}
+
+func (fake *Connection) Request(arg1 context.Context, arg2 string, arg3 string, arg4 int, arg5 int64, arg6 int, arg7 []byte, arg8 uint32, arg9 bool) ([]byte, error) {
+	var arg7Copy []byte
+	if arg7 != nil {
+		arg7Copy = make([]byte, len(arg7))
+		copy(arg7Copy, arg7)
+	}
+	fake.requestMutex.Lock()
+	ret, specificReturn := fake.requestReturnsOnCall[len(fake.requestArgsForCall)]
+	fake.requestArgsForCall = append(fake.requestArgsForCall, struct {
+		arg1 context.Context
+		arg2 string
+		arg3 string
+		arg4 int
+		arg5 int64
+		arg6 int
+		arg7 []byte
+		arg8 uint32
+		arg9 bool
+	}{arg1, arg2, arg3, arg4, arg5, arg6, arg7Copy, arg8, arg9})
+	stub := fake.RequestStub
+	fakeReturns := fake.requestReturns
+	fake.recordInvocation("Request", []interface{}{arg1, arg2, arg3, arg4, arg5, arg6, arg7Copy, arg8, arg9})
+	fake.requestMutex.Unlock()
+	if stub != nil {
+		return stub(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
+	}
+	if specificReturn {
+		return ret.result1, ret.result2
+	}
+	return fakeReturns.result1, fakeReturns.result2
+}
+
+func (fake *Connection) RequestCallCount() int {
+	fake.requestMutex.RLock()
+	defer fake.requestMutex.RUnlock()
+	return len(fake.requestArgsForCall)
+}
+
+func (fake *Connection) RequestCalls(stub func(context.Context, string, string, int, int64, int, []byte, uint32, bool) ([]byte, error)) {
+	fake.requestMutex.Lock()
+	defer fake.requestMutex.Unlock()
+	fake.RequestStub = stub
+}
+
+func (fake *Connection) RequestArgsForCall(i int) (context.Context, string, string, int, int64, int, []byte, uint32, bool) {
+	fake.requestMutex.RLock()
+	defer fake.requestMutex.RUnlock()
+	argsForCall := fake.requestArgsForCall[i]
+	return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5, argsForCall.arg6, argsForCall.arg7, argsForCall.arg8, argsForCall.arg9
+}
+
+func (fake *Connection) RequestReturns(result1 []byte, result2 error) {
+	fake.requestMutex.Lock()
+	defer fake.requestMutex.Unlock()
+	fake.RequestStub = nil
+	fake.requestReturns = struct {
+		result1 []byte
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Connection) RequestReturnsOnCall(i int, result1 []byte, result2 error) {
+	fake.requestMutex.Lock()
+	defer fake.requestMutex.Unlock()
+	fake.RequestStub = nil
+	if fake.requestReturnsOnCall == nil {
+		fake.requestReturnsOnCall = make(map[int]struct {
+			result1 []byte
+			result2 error
+		})
+	}
+	fake.requestReturnsOnCall[i] = struct {
+		result1 []byte
+		result2 error
+	}{result1, result2}
+}
+
+func (fake *Connection) Start() {
+	fake.startMutex.Lock()
+	fake.startArgsForCall = append(fake.startArgsForCall, struct {
+	}{})
+	stub := fake.StartStub
+	fake.recordInvocation("Start", []interface{}{})
+	fake.startMutex.Unlock()
+	if stub != nil {
+		fake.StartStub()
+	}
+}
+
+func (fake *Connection) StartCallCount() int {
+	fake.startMutex.RLock()
+	defer fake.startMutex.RUnlock()
+	return len(fake.startArgsForCall)
+}
+
+func (fake *Connection) StartCalls(stub func()) {
+	fake.startMutex.Lock()
+	defer fake.startMutex.Unlock()
+	fake.StartStub = stub
+}
+
+func (fake *Connection) Statistics() protocol.Statistics {
+	fake.statisticsMutex.Lock()
+	ret, specificReturn := fake.statisticsReturnsOnCall[len(fake.statisticsArgsForCall)]
+	fake.statisticsArgsForCall = append(fake.statisticsArgsForCall, struct {
+	}{})
+	stub := fake.StatisticsStub
+	fakeReturns := fake.statisticsReturns
+	fake.recordInvocation("Statistics", []interface{}{})
+	fake.statisticsMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) StatisticsCallCount() int {
+	fake.statisticsMutex.RLock()
+	defer fake.statisticsMutex.RUnlock()
+	return len(fake.statisticsArgsForCall)
+}
+
+func (fake *Connection) StatisticsCalls(stub func() protocol.Statistics) {
+	fake.statisticsMutex.Lock()
+	defer fake.statisticsMutex.Unlock()
+	fake.StatisticsStub = stub
+}
+
+func (fake *Connection) StatisticsReturns(result1 protocol.Statistics) {
+	fake.statisticsMutex.Lock()
+	defer fake.statisticsMutex.Unlock()
+	fake.StatisticsStub = nil
+	fake.statisticsReturns = struct {
+		result1 protocol.Statistics
+	}{result1}
+}
+
+func (fake *Connection) StatisticsReturnsOnCall(i int, result1 protocol.Statistics) {
+	fake.statisticsMutex.Lock()
+	defer fake.statisticsMutex.Unlock()
+	fake.StatisticsStub = nil
+	if fake.statisticsReturnsOnCall == nil {
+		fake.statisticsReturnsOnCall = make(map[int]struct {
+			result1 protocol.Statistics
+		})
+	}
+	fake.statisticsReturnsOnCall[i] = struct {
+		result1 protocol.Statistics
+	}{result1}
+}
+
+func (fake *Connection) String() string {
+	fake.stringMutex.Lock()
+	ret, specificReturn := fake.stringReturnsOnCall[len(fake.stringArgsForCall)]
+	fake.stringArgsForCall = append(fake.stringArgsForCall, struct {
+	}{})
+	stub := fake.StringStub
+	fakeReturns := fake.stringReturns
+	fake.recordInvocation("String", []interface{}{})
+	fake.stringMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) StringCallCount() int {
+	fake.stringMutex.RLock()
+	defer fake.stringMutex.RUnlock()
+	return len(fake.stringArgsForCall)
+}
+
+func (fake *Connection) StringCalls(stub func() string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = stub
+}
+
+func (fake *Connection) StringReturns(result1 string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = nil
+	fake.stringReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Connection) StringReturnsOnCall(i int, result1 string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = nil
+	if fake.stringReturnsOnCall == nil {
+		fake.stringReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.stringReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Connection) Transport() string {
+	fake.transportMutex.Lock()
+	ret, specificReturn := fake.transportReturnsOnCall[len(fake.transportArgsForCall)]
+	fake.transportArgsForCall = append(fake.transportArgsForCall, struct {
+	}{})
+	stub := fake.TransportStub
+	fakeReturns := fake.transportReturns
+	fake.recordInvocation("Transport", []interface{}{})
+	fake.transportMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) TransportCallCount() int {
+	fake.transportMutex.RLock()
+	defer fake.transportMutex.RUnlock()
+	return len(fake.transportArgsForCall)
+}
+
+func (fake *Connection) TransportCalls(stub func() string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = stub
+}
+
+func (fake *Connection) TransportReturns(result1 string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = nil
+	fake.transportReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Connection) TransportReturnsOnCall(i int, result1 string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = nil
+	if fake.transportReturnsOnCall == nil {
+		fake.transportReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.transportReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Connection) Type() string {
+	fake.typeMutex.Lock()
+	ret, specificReturn := fake.typeReturnsOnCall[len(fake.typeArgsForCall)]
+	fake.typeArgsForCall = append(fake.typeArgsForCall, struct {
+	}{})
+	stub := fake.TypeStub
+	fakeReturns := fake.typeReturns
+	fake.recordInvocation("Type", []interface{}{})
+	fake.typeMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *Connection) TypeCallCount() int {
+	fake.typeMutex.RLock()
+	defer fake.typeMutex.RUnlock()
+	return len(fake.typeArgsForCall)
+}
+
+func (fake *Connection) TypeCalls(stub func() string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = stub
+}
+
+func (fake *Connection) TypeReturns(result1 string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = nil
+	fake.typeReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Connection) TypeReturnsOnCall(i int, result1 string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = nil
+	if fake.typeReturnsOnCall == nil {
+		fake.typeReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.typeReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *Connection) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.closeMutex.RLock()
+	defer fake.closeMutex.RUnlock()
+	fake.closedMutex.RLock()
+	defer fake.closedMutex.RUnlock()
+	fake.clusterConfigMutex.RLock()
+	defer fake.clusterConfigMutex.RUnlock()
+	fake.cryptoMutex.RLock()
+	defer fake.cryptoMutex.RUnlock()
+	fake.downloadProgressMutex.RLock()
+	defer fake.downloadProgressMutex.RUnlock()
+	fake.establishedAtMutex.RLock()
+	defer fake.establishedAtMutex.RUnlock()
+	fake.iDMutex.RLock()
+	defer fake.iDMutex.RUnlock()
+	fake.indexMutex.RLock()
+	defer fake.indexMutex.RUnlock()
+	fake.indexUpdateMutex.RLock()
+	defer fake.indexUpdateMutex.RUnlock()
+	fake.priorityMutex.RLock()
+	defer fake.priorityMutex.RUnlock()
+	fake.remoteAddrMutex.RLock()
+	defer fake.remoteAddrMutex.RUnlock()
+	fake.requestMutex.RLock()
+	defer fake.requestMutex.RUnlock()
+	fake.startMutex.RLock()
+	defer fake.startMutex.RUnlock()
+	fake.statisticsMutex.RLock()
+	defer fake.statisticsMutex.RUnlock()
+	fake.stringMutex.RLock()
+	defer fake.stringMutex.RUnlock()
+	fake.transportMutex.RLock()
+	defer fake.transportMutex.RUnlock()
+	fake.typeMutex.RLock()
+	defer fake.typeMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *Connection) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ protocol.Connection = new(Connection)

+ 494 - 0
lib/protocol/mocks/connection_info.go

@@ -0,0 +1,494 @@
+// Code generated by counterfeiter. DO NOT EDIT.
+package mocks
+
+import (
+	"net"
+	"sync"
+	"time"
+
+	"github.com/syncthing/syncthing/lib/protocol"
+)
+
+type ConnectionInfo struct {
+	CryptoStub        func() string
+	cryptoMutex       sync.RWMutex
+	cryptoArgsForCall []struct {
+	}
+	cryptoReturns struct {
+		result1 string
+	}
+	cryptoReturnsOnCall map[int]struct {
+		result1 string
+	}
+	EstablishedAtStub        func() time.Time
+	establishedAtMutex       sync.RWMutex
+	establishedAtArgsForCall []struct {
+	}
+	establishedAtReturns struct {
+		result1 time.Time
+	}
+	establishedAtReturnsOnCall map[int]struct {
+		result1 time.Time
+	}
+	PriorityStub        func() int
+	priorityMutex       sync.RWMutex
+	priorityArgsForCall []struct {
+	}
+	priorityReturns struct {
+		result1 int
+	}
+	priorityReturnsOnCall map[int]struct {
+		result1 int
+	}
+	RemoteAddrStub        func() net.Addr
+	remoteAddrMutex       sync.RWMutex
+	remoteAddrArgsForCall []struct {
+	}
+	remoteAddrReturns struct {
+		result1 net.Addr
+	}
+	remoteAddrReturnsOnCall map[int]struct {
+		result1 net.Addr
+	}
+	StringStub        func() string
+	stringMutex       sync.RWMutex
+	stringArgsForCall []struct {
+	}
+	stringReturns struct {
+		result1 string
+	}
+	stringReturnsOnCall map[int]struct {
+		result1 string
+	}
+	TransportStub        func() string
+	transportMutex       sync.RWMutex
+	transportArgsForCall []struct {
+	}
+	transportReturns struct {
+		result1 string
+	}
+	transportReturnsOnCall map[int]struct {
+		result1 string
+	}
+	TypeStub        func() string
+	typeMutex       sync.RWMutex
+	typeArgsForCall []struct {
+	}
+	typeReturns struct {
+		result1 string
+	}
+	typeReturnsOnCall map[int]struct {
+		result1 string
+	}
+	invocations      map[string][][]interface{}
+	invocationsMutex sync.RWMutex
+}
+
+func (fake *ConnectionInfo) Crypto() string {
+	fake.cryptoMutex.Lock()
+	ret, specificReturn := fake.cryptoReturnsOnCall[len(fake.cryptoArgsForCall)]
+	fake.cryptoArgsForCall = append(fake.cryptoArgsForCall, struct {
+	}{})
+	stub := fake.CryptoStub
+	fakeReturns := fake.cryptoReturns
+	fake.recordInvocation("Crypto", []interface{}{})
+	fake.cryptoMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *ConnectionInfo) CryptoCallCount() int {
+	fake.cryptoMutex.RLock()
+	defer fake.cryptoMutex.RUnlock()
+	return len(fake.cryptoArgsForCall)
+}
+
+func (fake *ConnectionInfo) CryptoCalls(stub func() string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = stub
+}
+
+func (fake *ConnectionInfo) CryptoReturns(result1 string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = nil
+	fake.cryptoReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *ConnectionInfo) CryptoReturnsOnCall(i int, result1 string) {
+	fake.cryptoMutex.Lock()
+	defer fake.cryptoMutex.Unlock()
+	fake.CryptoStub = nil
+	if fake.cryptoReturnsOnCall == nil {
+		fake.cryptoReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.cryptoReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *ConnectionInfo) EstablishedAt() time.Time {
+	fake.establishedAtMutex.Lock()
+	ret, specificReturn := fake.establishedAtReturnsOnCall[len(fake.establishedAtArgsForCall)]
+	fake.establishedAtArgsForCall = append(fake.establishedAtArgsForCall, struct {
+	}{})
+	stub := fake.EstablishedAtStub
+	fakeReturns := fake.establishedAtReturns
+	fake.recordInvocation("EstablishedAt", []interface{}{})
+	fake.establishedAtMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *ConnectionInfo) EstablishedAtCallCount() int {
+	fake.establishedAtMutex.RLock()
+	defer fake.establishedAtMutex.RUnlock()
+	return len(fake.establishedAtArgsForCall)
+}
+
+func (fake *ConnectionInfo) EstablishedAtCalls(stub func() time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = stub
+}
+
+func (fake *ConnectionInfo) EstablishedAtReturns(result1 time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = nil
+	fake.establishedAtReturns = struct {
+		result1 time.Time
+	}{result1}
+}
+
+func (fake *ConnectionInfo) EstablishedAtReturnsOnCall(i int, result1 time.Time) {
+	fake.establishedAtMutex.Lock()
+	defer fake.establishedAtMutex.Unlock()
+	fake.EstablishedAtStub = nil
+	if fake.establishedAtReturnsOnCall == nil {
+		fake.establishedAtReturnsOnCall = make(map[int]struct {
+			result1 time.Time
+		})
+	}
+	fake.establishedAtReturnsOnCall[i] = struct {
+		result1 time.Time
+	}{result1}
+}
+
+func (fake *ConnectionInfo) Priority() int {
+	fake.priorityMutex.Lock()
+	ret, specificReturn := fake.priorityReturnsOnCall[len(fake.priorityArgsForCall)]
+	fake.priorityArgsForCall = append(fake.priorityArgsForCall, struct {
+	}{})
+	stub := fake.PriorityStub
+	fakeReturns := fake.priorityReturns
+	fake.recordInvocation("Priority", []interface{}{})
+	fake.priorityMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *ConnectionInfo) PriorityCallCount() int {
+	fake.priorityMutex.RLock()
+	defer fake.priorityMutex.RUnlock()
+	return len(fake.priorityArgsForCall)
+}
+
+func (fake *ConnectionInfo) PriorityCalls(stub func() int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = stub
+}
+
+func (fake *ConnectionInfo) PriorityReturns(result1 int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = nil
+	fake.priorityReturns = struct {
+		result1 int
+	}{result1}
+}
+
+func (fake *ConnectionInfo) PriorityReturnsOnCall(i int, result1 int) {
+	fake.priorityMutex.Lock()
+	defer fake.priorityMutex.Unlock()
+	fake.PriorityStub = nil
+	if fake.priorityReturnsOnCall == nil {
+		fake.priorityReturnsOnCall = make(map[int]struct {
+			result1 int
+		})
+	}
+	fake.priorityReturnsOnCall[i] = struct {
+		result1 int
+	}{result1}
+}
+
+func (fake *ConnectionInfo) RemoteAddr() net.Addr {
+	fake.remoteAddrMutex.Lock()
+	ret, specificReturn := fake.remoteAddrReturnsOnCall[len(fake.remoteAddrArgsForCall)]
+	fake.remoteAddrArgsForCall = append(fake.remoteAddrArgsForCall, struct {
+	}{})
+	stub := fake.RemoteAddrStub
+	fakeReturns := fake.remoteAddrReturns
+	fake.recordInvocation("RemoteAddr", []interface{}{})
+	fake.remoteAddrMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *ConnectionInfo) RemoteAddrCallCount() int {
+	fake.remoteAddrMutex.RLock()
+	defer fake.remoteAddrMutex.RUnlock()
+	return len(fake.remoteAddrArgsForCall)
+}
+
+func (fake *ConnectionInfo) RemoteAddrCalls(stub func() net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = stub
+}
+
+func (fake *ConnectionInfo) RemoteAddrReturns(result1 net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = nil
+	fake.remoteAddrReturns = struct {
+		result1 net.Addr
+	}{result1}
+}
+
+func (fake *ConnectionInfo) RemoteAddrReturnsOnCall(i int, result1 net.Addr) {
+	fake.remoteAddrMutex.Lock()
+	defer fake.remoteAddrMutex.Unlock()
+	fake.RemoteAddrStub = nil
+	if fake.remoteAddrReturnsOnCall == nil {
+		fake.remoteAddrReturnsOnCall = make(map[int]struct {
+			result1 net.Addr
+		})
+	}
+	fake.remoteAddrReturnsOnCall[i] = struct {
+		result1 net.Addr
+	}{result1}
+}
+
+func (fake *ConnectionInfo) String() string {
+	fake.stringMutex.Lock()
+	ret, specificReturn := fake.stringReturnsOnCall[len(fake.stringArgsForCall)]
+	fake.stringArgsForCall = append(fake.stringArgsForCall, struct {
+	}{})
+	stub := fake.StringStub
+	fakeReturns := fake.stringReturns
+	fake.recordInvocation("String", []interface{}{})
+	fake.stringMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *ConnectionInfo) StringCallCount() int {
+	fake.stringMutex.RLock()
+	defer fake.stringMutex.RUnlock()
+	return len(fake.stringArgsForCall)
+}
+
+func (fake *ConnectionInfo) StringCalls(stub func() string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = stub
+}
+
+func (fake *ConnectionInfo) StringReturns(result1 string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = nil
+	fake.stringReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *ConnectionInfo) StringReturnsOnCall(i int, result1 string) {
+	fake.stringMutex.Lock()
+	defer fake.stringMutex.Unlock()
+	fake.StringStub = nil
+	if fake.stringReturnsOnCall == nil {
+		fake.stringReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.stringReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *ConnectionInfo) Transport() string {
+	fake.transportMutex.Lock()
+	ret, specificReturn := fake.transportReturnsOnCall[len(fake.transportArgsForCall)]
+	fake.transportArgsForCall = append(fake.transportArgsForCall, struct {
+	}{})
+	stub := fake.TransportStub
+	fakeReturns := fake.transportReturns
+	fake.recordInvocation("Transport", []interface{}{})
+	fake.transportMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *ConnectionInfo) TransportCallCount() int {
+	fake.transportMutex.RLock()
+	defer fake.transportMutex.RUnlock()
+	return len(fake.transportArgsForCall)
+}
+
+func (fake *ConnectionInfo) TransportCalls(stub func() string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = stub
+}
+
+func (fake *ConnectionInfo) TransportReturns(result1 string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = nil
+	fake.transportReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *ConnectionInfo) TransportReturnsOnCall(i int, result1 string) {
+	fake.transportMutex.Lock()
+	defer fake.transportMutex.Unlock()
+	fake.TransportStub = nil
+	if fake.transportReturnsOnCall == nil {
+		fake.transportReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.transportReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *ConnectionInfo) Type() string {
+	fake.typeMutex.Lock()
+	ret, specificReturn := fake.typeReturnsOnCall[len(fake.typeArgsForCall)]
+	fake.typeArgsForCall = append(fake.typeArgsForCall, struct {
+	}{})
+	stub := fake.TypeStub
+	fakeReturns := fake.typeReturns
+	fake.recordInvocation("Type", []interface{}{})
+	fake.typeMutex.Unlock()
+	if stub != nil {
+		return stub()
+	}
+	if specificReturn {
+		return ret.result1
+	}
+	return fakeReturns.result1
+}
+
+func (fake *ConnectionInfo) TypeCallCount() int {
+	fake.typeMutex.RLock()
+	defer fake.typeMutex.RUnlock()
+	return len(fake.typeArgsForCall)
+}
+
+func (fake *ConnectionInfo) TypeCalls(stub func() string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = stub
+}
+
+func (fake *ConnectionInfo) TypeReturns(result1 string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = nil
+	fake.typeReturns = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *ConnectionInfo) TypeReturnsOnCall(i int, result1 string) {
+	fake.typeMutex.Lock()
+	defer fake.typeMutex.Unlock()
+	fake.TypeStub = nil
+	if fake.typeReturnsOnCall == nil {
+		fake.typeReturnsOnCall = make(map[int]struct {
+			result1 string
+		})
+	}
+	fake.typeReturnsOnCall[i] = struct {
+		result1 string
+	}{result1}
+}
+
+func (fake *ConnectionInfo) Invocations() map[string][][]interface{} {
+	fake.invocationsMutex.RLock()
+	defer fake.invocationsMutex.RUnlock()
+	fake.cryptoMutex.RLock()
+	defer fake.cryptoMutex.RUnlock()
+	fake.establishedAtMutex.RLock()
+	defer fake.establishedAtMutex.RUnlock()
+	fake.priorityMutex.RLock()
+	defer fake.priorityMutex.RUnlock()
+	fake.remoteAddrMutex.RLock()
+	defer fake.remoteAddrMutex.RUnlock()
+	fake.stringMutex.RLock()
+	defer fake.stringMutex.RUnlock()
+	fake.transportMutex.RLock()
+	defer fake.transportMutex.RUnlock()
+	fake.typeMutex.RLock()
+	defer fake.typeMutex.RUnlock()
+	copiedInvocations := map[string][][]interface{}{}
+	for key, value := range fake.invocations {
+		copiedInvocations[key] = value
+	}
+	return copiedInvocations
+}
+
+func (fake *ConnectionInfo) recordInvocation(key string, args []interface{}) {
+	fake.invocationsMutex.Lock()
+	defer fake.invocationsMutex.Unlock()
+	if fake.invocations == nil {
+		fake.invocations = map[string][][]interface{}{}
+	}
+	if fake.invocations[key] == nil {
+		fake.invocations[key] = [][]interface{}{}
+	}
+	fake.invocations[key] = append(fake.invocations[key], args)
+}
+
+var _ protocol.ConnectionInfo = new(ConnectionInfo)

+ 7 - 0
lib/protocol/protocol.go

@@ -1,5 +1,12 @@
 // Copyright (C) 2014 The Protocol Authors.
 
+// Prevents import loop, for internal testing
+//go:generate counterfeiter -o mocked_connection_info_test.go --fake-name mockedConnectionInfo . ConnectionInfo
+//go:generate go run ../../script/prune_mocks.go -t mocked_connection_info_test.go
+
+//go:generate counterfeiter -o mocks/connection_info.go --fake-name ConnectionInfo . ConnectionInfo
+//go:generate counterfeiter -o mocks/connection.go --fake-name Connection . Connection
+
 package protocol
 
 import (

+ 11 - 11
lib/protocol/protocol_test.go

@@ -31,10 +31,10 @@ func TestPing(t *testing.T) {
 	ar, aw := io.Pipe()
 	br, bw := io.Pipe()
 
-	c0 := NewConnection(c0ID, ar, bw, testutils.NoopCloser{}, newTestModel(), &testutils.FakeConnectionInfo{"name"}, CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
+	c0 := NewConnection(c0ID, ar, bw, testutils.NoopCloser{}, newTestModel(), new(mockedConnectionInfo), CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
 	c0.Start()
 	defer closeAndWait(c0, ar, bw)
-	c1 := NewConnection(c1ID, br, aw, testutils.NoopCloser{}, newTestModel(), &testutils.FakeConnectionInfo{"name"}, CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
+	c1 := NewConnection(c1ID, br, aw, testutils.NoopCloser{}, newTestModel(), new(mockedConnectionInfo), CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
 	c1.Start()
 	defer closeAndWait(c1, ar, bw)
 	c0.ClusterConfig(ClusterConfig{})
@@ -57,10 +57,10 @@ func TestClose(t *testing.T) {
 	ar, aw := io.Pipe()
 	br, bw := io.Pipe()
 
-	c0 := NewConnection(c0ID, ar, bw, testutils.NoopCloser{}, m0, &testutils.FakeConnectionInfo{"name"}, CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
+	c0 := NewConnection(c0ID, ar, bw, testutils.NoopCloser{}, m0, new(mockedConnectionInfo), CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
 	c0.Start()
 	defer closeAndWait(c0, ar, bw)
-	c1 := NewConnection(c1ID, br, aw, testutils.NoopCloser{}, m1, &testutils.FakeConnectionInfo{"name"}, CompressionAlways)
+	c1 := NewConnection(c1ID, br, aw, testutils.NoopCloser{}, m1, new(mockedConnectionInfo), CompressionAlways)
 	c1.Start()
 	defer closeAndWait(c1, ar, bw)
 	c0.ClusterConfig(ClusterConfig{})
@@ -102,7 +102,7 @@ func TestCloseOnBlockingSend(t *testing.T) {
 	m := newTestModel()
 
 	rw := testutils.NewBlockingRW()
-	c := NewConnection(c0ID, rw, rw, testutils.NoopCloser{}, m, &testutils.FakeConnectionInfo{"name"}, CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
+	c := NewConnection(c0ID, rw, rw, testutils.NoopCloser{}, m, new(mockedConnectionInfo), CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
 	c.Start()
 	defer closeAndWait(c, rw)
 
@@ -153,10 +153,10 @@ func TestCloseRace(t *testing.T) {
 	ar, aw := io.Pipe()
 	br, bw := io.Pipe()
 
-	c0 := NewConnection(c0ID, ar, bw, testutils.NoopCloser{}, m0, &testutils.FakeConnectionInfo{"c0"}, CompressionNever).(wireFormatConnection).Connection.(*rawConnection)
+	c0 := NewConnection(c0ID, ar, bw, testutils.NoopCloser{}, m0, new(mockedConnectionInfo), CompressionNever).(wireFormatConnection).Connection.(*rawConnection)
 	c0.Start()
 	defer closeAndWait(c0, ar, bw)
-	c1 := NewConnection(c1ID, br, aw, testutils.NoopCloser{}, m1, &testutils.FakeConnectionInfo{"c1"}, CompressionNever)
+	c1 := NewConnection(c1ID, br, aw, testutils.NoopCloser{}, m1, new(mockedConnectionInfo), CompressionNever)
 	c1.Start()
 	defer closeAndWait(c1, ar, bw)
 	c0.ClusterConfig(ClusterConfig{})
@@ -193,7 +193,7 @@ func TestClusterConfigFirst(t *testing.T) {
 	m := newTestModel()
 
 	rw := testutils.NewBlockingRW()
-	c := NewConnection(c0ID, rw, &testutils.NoopRW{}, testutils.NoopCloser{}, m, &testutils.FakeConnectionInfo{"name"}, CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
+	c := NewConnection(c0ID, rw, &testutils.NoopRW{}, testutils.NoopCloser{}, m, new(mockedConnectionInfo), CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
 	c.Start()
 	defer closeAndWait(c, rw)
 
@@ -245,7 +245,7 @@ func TestCloseTimeout(t *testing.T) {
 	m := newTestModel()
 
 	rw := testutils.NewBlockingRW()
-	c := NewConnection(c0ID, rw, rw, testutils.NoopCloser{}, m, &testutils.FakeConnectionInfo{"name"}, CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
+	c := NewConnection(c0ID, rw, rw, testutils.NoopCloser{}, m, new(mockedConnectionInfo), CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
 	c.Start()
 	defer closeAndWait(c, rw)
 
@@ -865,7 +865,7 @@ func TestClusterConfigAfterClose(t *testing.T) {
 	m := newTestModel()
 
 	rw := testutils.NewBlockingRW()
-	c := NewConnection(c0ID, rw, rw, testutils.NoopCloser{}, m, &testutils.FakeConnectionInfo{"name"}, CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
+	c := NewConnection(c0ID, rw, rw, testutils.NoopCloser{}, m, new(mockedConnectionInfo), CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
 	c.Start()
 	defer closeAndWait(c, rw)
 
@@ -889,7 +889,7 @@ func TestDispatcherToCloseDeadlock(t *testing.T) {
 	// the model callbacks (ClusterConfig).
 	m := newTestModel()
 	rw := testutils.NewBlockingRW()
-	c := NewConnection(c0ID, rw, &testutils.NoopRW{}, testutils.NoopCloser{}, m, &testutils.FakeConnectionInfo{"name"}, CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
+	c := NewConnection(c0ID, rw, &testutils.NoopRW{}, testutils.NoopCloser{}, m, new(mockedConnectionInfo), CompressionAlways).(wireFormatConnection).Connection.(*rawConnection)
 	m.ccFn = func(devID DeviceID, cc ClusterConfig) {
 		c.Close(errManual)
 	}

+ 0 - 46
lib/testutils/testutils.go

@@ -8,9 +8,7 @@ package testutils
 
 import (
 	"errors"
-	"net"
 	"sync"
-	"time"
 )
 
 var ErrClosed = errors.New("closed")
@@ -60,47 +58,3 @@ type NoopCloser struct{}
 func (NoopCloser) Close() error {
 	return nil
 }
-
-// FakeConnectionInfo implements the methods of protocol.Connection that are
-// not implemented by protocol.Connection
-type FakeConnectionInfo struct {
-	Name string
-}
-
-func (f *FakeConnectionInfo) RemoteAddr() net.Addr {
-	return &FakeAddr{}
-}
-
-func (f *FakeConnectionInfo) Type() string {
-	return "fake"
-}
-
-func (f *FakeConnectionInfo) Crypto() string {
-	return "fake"
-}
-
-func (f *FakeConnectionInfo) Transport() string {
-	return "fake"
-}
-
-func (f *FakeConnectionInfo) Priority() int {
-	return 9000
-}
-
-func (f *FakeConnectionInfo) String() string {
-	return ""
-}
-
-func (f *FakeConnectionInfo) EstablishedAt() time.Time {
-	return time.Time{}
-}
-
-type FakeAddr struct{}
-
-func (FakeAddr) Network() string {
-	return "network"
-}
-
-func (FakeAddr) String() string {
-	return "address"
-}

+ 1 - 0
meta/copyright_test.go

@@ -31,6 +31,7 @@ var copyrightRegexps = []string{
 	`package auto`,
 	`automatically generated by genxdr`,
 	`generated by protoc`,
+	`^// Code generated .* DO NOT EDIT\.$`,
 }
 
 var copyrightRe = regexp.MustCompile(strings.Join(copyrightRegexps, "|"))

+ 1 - 1
proto/generate.go

@@ -25,7 +25,7 @@ import (
 
 // Inception, go generate calls the script itself that then deals with generation.
 // This is only done because go:generate does not support wildcards in paths.
-//go:generate go run generate.go lib/protocol lib/config lib/fs lib/db
+//go:generate go run generate.go lib/protocol lib/config lib/fs lib/db lib/discover
 
 func main() {
 	for _, path := range os.Args[1:] {

+ 13 - 0
proto/lib/discover/local.proto

@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+package discover;
+
+import "repos/protobuf/gogoproto/gogo.proto";
+
+import "ext.proto";
+
+message Announce {
+    bytes           id          = 1 [(ext.goname) = "ID", (ext.device_id) = true, (gogoproto.nullable) = false];
+    repeated string addresses   = 2;
+    int64           instance_id = 3 [(ext.goname) = "InstanceID"];
+}

+ 15 - 0
proto/lib/protocol/deviceid_test.proto

@@ -0,0 +1,15 @@
+
+syntax = "proto3";
+
+package protocol;
+
+import "ext.proto";
+import "repos/protobuf/gogoproto/gogo.proto";
+
+message TestOldDeviceID {
+    bytes test = 1;
+}
+
+message TestNewDeviceID {
+    bytes test = 1 [(ext.device_id) = true, (gogoproto.nullable) = false];
+}

+ 79 - 0
script/prune_mocks.go

@@ -0,0 +1,79 @@
+// Copyright (C) 2021 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 https://mozilla.org/MPL/2.0/.
+
+// +build ignore
+
+package main
+
+import (
+	"bufio"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+)
+
+func main() {
+	var path string
+	flag.StringVar(&path, "t", "", "Name of file to prune")
+	flag.Parse()
+
+	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			log.Fatal(err)
+		}
+		if !info.Mode().IsRegular() {
+			return nil
+		}
+		err = pruneInterfaceCheck(path, info.Size())
+		if err != nil {
+			log.Fatal(err)
+		}
+		err = exec.Command("goimports", "-w", path).Run()
+		if err != nil {
+			log.Fatal(err)
+		}
+		return nil
+	})
+}
+
+func pruneInterfaceCheck(path string, size int64) error {
+	fd, err := os.Open(path)
+	if err != nil {
+		return err
+	}
+	defer fd.Close()
+
+	tmp, err := ioutil.TempFile(".", "")
+	if err != nil {
+		return err
+	}
+
+	scanner := bufio.NewScanner(fd)
+
+	for scanner.Scan() {
+		line := scanner.Text()
+		if strings.HasPrefix(strings.TrimSpace(line), "var _ ") {
+			continue
+		}
+		if _, err := tmp.WriteString(line + "\n"); err != nil {
+			os.Remove(tmp.Name())
+			return err
+		}
+	}
+
+	if err := fd.Close(); err != nil {
+		return err
+	}
+	if err := os.Remove(path); err != nil {
+		return err
+	}
+	return os.Rename(tmp.Name(), path)
+}