diff --git a/.github/workflows/build-syncthing.yaml b/.github/workflows/build-syncthing.yaml index faffe93cc2e..8e84a26d13f 100644 --- a/.github/workflows/build-syncthing.yaml +++ b/.github/workflows/build-syncthing.yaml @@ -62,6 +62,8 @@ jobs: git config --global core.eol lf - uses: actions/checkout@v4 + with: + fetch-depth: 0 - uses: actions/setup-go@v5 with: @@ -77,7 +79,7 @@ jobs: run: | go install calmh.dev/go-test-json-to-loki@latest - - name: Test + - name: Test (unit) run: | go version go run build.go test | go-test-json-to-loki @@ -88,6 +90,17 @@ jobs: LOKI_PASSWORD: ${{ secrets.LOKI_PASSWORD }} LOKI_LABELS: "go=${{ matrix.go }},runner=${{ matrix.runner }},repo=${{ github.repository }},ref=${{ github.ref }}" + - name: Test (integration) + run: | + cd test + go test | go-test-json-to-loki + env: + GOFLAGS: "-json" + LOKI_URL: ${{ vars.LOKI_URL }} + LOKI_USER: ${{ vars.LOKI_USER }} + LOKI_PASSWORD: ${{ secrets.LOKI_PASSWORD }} + LOKI_LABELS: "go=${{ matrix.go }},runner=${{ matrix.runner }},repo=${{ github.repository }},ref=${{ github.ref }}" + # # Meta checks for formatting, copyright, etc # diff --git a/lib/rc/debug.go b/lib/rc/debug.go deleted file mode 100644 index d9a6454c8c2..00000000000 --- a/lib/rc/debug.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) 2015 The Syncthing Authors. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. - -package rc - -import ( - "github.com/syncthing/syncthing/lib/logger" -) - -var ( - l = logger.DefaultLogger.NewFacility("rc", "Remote control package") -) diff --git a/lib/rc/rc.go b/lib/rc/rc.go index 919631cb3b2..0612052313e 100644 --- a/lib/rc/rc.go +++ b/lib/rc/rc.go @@ -8,161 +8,32 @@ package rc import ( - "bufio" "bytes" + "context" "encoding/json" "errors" "fmt" "io" - "log" "net/http" - "net/url" - "os" - "os/exec" - "path/filepath" - "strconv" "time" - "github.com/syncthing/syncthing/lib/config" "github.com/syncthing/syncthing/lib/dialer" - "github.com/syncthing/syncthing/lib/events" - "github.com/syncthing/syncthing/lib/model" - "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/sync" ) -// APIKey is set via the STGUIAPIKEY variable when we launch the binary, to -// ensure that we have API access regardless of authentication settings. -const APIKey = "592A47BC-A7DF-4C2F-89E0-A80B3E5094EE" - -type Process struct { - // Set at initialization - addr string - - // Set by eventLoop() - eventMut sync.Mutex - id protocol.DeviceID - folders []string - startComplete chan struct{} - stopped chan struct{} - stopErr error - sequence map[string]map[string]int64 // Folder ID => Device ID => Sequence - done map[string]bool // Folder ID => 100% - - cmd *exec.Cmd - logfd *os.File +type API struct { + addr string + apiKey string } -// NewProcess returns a new Process talking to Syncthing at the specified address. -// Example: NewProcess("127.0.0.1:8082") -func NewProcess(addr string) *Process { - p := &Process{ - addr: addr, - sequence: make(map[string]map[string]int64), - done: make(map[string]bool), - eventMut: sync.NewMutex(), - startComplete: make(chan struct{}), - stopped: make(chan struct{}), +func NewAPI(addr, apiKey string) *API { + p := &API{ + addr: addr, + apiKey: apiKey, } return p } -func (p *Process) ID() protocol.DeviceID { - return p.id -} - -// LogTo creates the specified log file and ensures that stdout and stderr -// from the Start()ed process is redirected there. Must be called before -// Start(). -func (p *Process) LogTo(filename string) error { - if p.cmd != nil { - panic("logfd cannot be set with an existing cmd") - } - - if p.logfd != nil { - p.logfd.Close() - } - - fd, err := os.Create(filename) - if err != nil { - return err - } - p.logfd = fd - return nil -} - -// Start runs the specified Syncthing binary with the given arguments. -// Syncthing should be configured to provide an API on the address given to -// NewProcess. Event processing is started. -func (p *Process) Start(bin string, args ...string) error { - cmd := exec.Command(bin, args...) - if p.logfd != nil { - cmd.Stdout = p.logfd - cmd.Stderr = p.logfd - } - cmd.Env = append(os.Environ(), "STNORESTART=1", "STGUIAPIKEY="+APIKey) - - err := cmd.Start() - if err != nil { - return err - } - - p.cmd = cmd - go p.eventLoop() - go p.wait() - - return nil -} - -func (p *Process) wait() { - p.cmd.Wait() - - if p.logfd != nil { - p.stopErr = p.checkForProblems(p.logfd) - } - - close(p.stopped) -} - -// AwaitStartup waits for the Syncthing process to start and perform initial -// scans of all folders. -func (p *Process) AwaitStartup() { - select { - case <-p.startComplete: - case <-p.stopped: - } -} - -// Stop stops the running Syncthing process. If the process was logging to a -// local file (set by LogTo), the log file will be opened and checked for -// panics and data races. The presence of either will be signalled in the form -// of a returned error. -func (p *Process) Stop() (*os.ProcessState, error) { - select { - case <-p.stopped: - return p.cmd.ProcessState, p.stopErr - default: - } - - if _, err := p.Post("/rest/system/shutdown", nil); err != nil && err != io.ErrUnexpectedEOF { - // Unexpected EOF is somewhat expected here, as we may exit before - // returning something sensible. - return nil, err - } - - <-p.stopped - - return p.cmd.ProcessState, p.stopErr -} - -// Stopped returns a channel that will be closed when Syncthing has stopped. -func (p *Process) Stopped() chan struct{} { - return p.stopped -} - -// Get performs an HTTP GET and returns the bytes and/or an error. Any non-200 -// return code is returned as an error. -func (p *Process) Get(path string) ([]byte, error) { +func (p *API) Get(ctx context.Context, path string, dst any) error { client := &http.Client{ Timeout: 30 * time.Second, Transport: &http.Transport{ @@ -173,24 +44,22 @@ func (p *Process) Get(path string) ([]byte, error) { } url := fmt.Sprintf("http://%s%s", p.addr, path) - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { - return nil, err + return err } - req.Header.Add("X-API-Key", APIKey) + req.Header.Add("Authorization", "Bearer "+p.apiKey) resp, err := client.Do(req) if err != nil { - return nil, err + return err } - return p.readResponse(resp) + return p.readResponse(resp, dst) } -// Post performs an HTTP POST and returns the bytes and/or an error. Any -// non-200 return code is returned as an error. -func (p *Process) Post(path string, data io.Reader) ([]byte, error) { +func (p *API) Post(path string, src, dst any) error { client := &http.Client{ Timeout: 600 * time.Second, Transport: &http.Transport{ @@ -198,481 +67,59 @@ func (p *Process) Post(path string, data io.Reader) ([]byte, error) { }, } url := fmt.Sprintf("http://%s%s", p.addr, path) - req, err := http.NewRequest("POST", url, data) + var postBody io.Reader + if src != nil { + data, err := json.Marshal(src) + if err != nil { + return err + } + postBody = bytes.NewReader(data) + } + req, err := http.NewRequest(http.MethodPost, url, postBody) if err != nil { - return nil, err + return err } - req.Header.Add("X-API-Key", APIKey) + req.Header.Add("Authorization", "Bearer "+p.apiKey) req.Header.Add("Content-Type", "application/json") resp, err := client.Do(req) if err != nil { - return nil, err + return err } - return p.readResponse(resp) + return p.readResponse(resp, dst) } type Event struct { ID int Time time.Time Type string - Data interface{} + Data any } -func (p *Process) Events(since int) ([]Event, error) { - bs, err := p.Get(fmt.Sprintf("/rest/events?since=%d&timeout=10", since)) - if err != nil { - return nil, err - } - +func (p *API) Events(ctx context.Context, since int) ([]Event, error) { var evs []Event - dec := json.NewDecoder(bytes.NewReader(bs)) - dec.UseNumber() - err = dec.Decode(&evs) - if err != nil { - return nil, fmt.Errorf("events: %w in %q", err, bs) - } - return evs, err -} - -func (p *Process) Rescan(folder string) error { - _, err := p.Post("/rest/db/scan?folder="+url.QueryEscape(folder), nil) - return err -} - -func (p *Process) RescanDelay(folder string, delaySeconds int) error { - _, err := p.Post(fmt.Sprintf("/rest/db/scan?folder=%s&next=%d", url.QueryEscape(folder), delaySeconds), nil) - return err -} - -func (p *Process) RescanSub(folder string, sub string, delaySeconds int) error { - return p.RescanSubs(folder, []string{sub}, delaySeconds) -} - -func (p *Process) RescanSubs(folder string, subs []string, delaySeconds int) error { - data := url.Values{} - data.Set("folder", folder) - for _, sub := range subs { - data.Add("sub", sub) - } - data.Set("next", strconv.Itoa(delaySeconds)) - _, err := p.Post("/rest/db/scan?"+data.Encode(), nil) - return err -} - -func (p *Process) ConfigInSync() (bool, error) { - bs, err := p.Get("/rest/system/config/insync") - if err != nil { - return false, err - } - return bytes.Contains(bs, []byte("true")), nil -} - -func (p *Process) GetConfig() (config.Configuration, error) { - var cfg config.Configuration - bs, err := p.Get("/rest/system/config") - if err != nil { - return cfg, err - } - - err = json.Unmarshal(bs, &cfg) - return cfg, err -} - -func (p *Process) PostConfig(cfg config.Configuration) error { - buf := new(bytes.Buffer) - if err := json.NewEncoder(buf).Encode(cfg); err != nil { - return err - } - _, err := p.Post("/rest/system/config", buf) - return err -} - -func (p *Process) PauseDevice(dev protocol.DeviceID) error { - _, err := p.Post("/rest/system/pause?device="+dev.String(), nil) - return err -} - -func (p *Process) ResumeDevice(dev protocol.DeviceID) error { - _, err := p.Post("/rest/system/resume?device="+dev.String(), nil) - return err -} - -func (p *Process) PauseAll() error { - _, err := p.Post("/rest/system/pause", nil) - return err -} - -func (p *Process) ResumeAll() error { - _, err := p.Post("/rest/system/resume", nil) - return err -} - -func InSync(folder string, ps ...*Process) bool { - for _, p := range ps { - p.eventMut.Lock() - } - defer func() { - for _, p := range ps { - p.eventMut.Unlock() - } - }() - - for i := range ps { - // If our latest FolderSummary didn't report 100%, then we are not done. - - if !ps[i].done[folder] { - l.Debugf("done = ps[%d].done[%q] = false", i, folder) - return false - } - - // Check Sequence for each device. The local version seen by remote - // devices should be the same as what it has locally, or the index - // hasn't been sent yet. - - sourceID := ps[i].id.String() - sourceSeq := ps[i].sequence[folder][sourceID] - l.Debugf("sourceSeq = ps[%d].sequence[%q][%q] = %d", i, folder, sourceID, sourceSeq) - for j := range ps { - if i != j { - remoteSeq := ps[j].sequence[folder][sourceID] - if remoteSeq != sourceSeq { - l.Debugf("remoteSeq = ps[%d].sequence[%q][%q] = %d", j, folder, sourceID, remoteSeq) - return false - } - } - } - } - - return true -} - -func AwaitSync(folder string, ps ...*Process) { - for { - time.Sleep(250 * time.Millisecond) - if InSync(folder, ps...) { - return - } - } -} - -type Model struct { - GlobalBytes int - GlobalDeleted int - GlobalFiles int - InSyncBytes int - InSyncFiles int - Invalid string - LocalBytes int - LocalDeleted int - LocalFiles int - NeedBytes int - NeedFiles int - State string - StateChanged time.Time - Version int -} - -func (p *Process) Model(folder string) (Model, error) { - bs, err := p.Get("/rest/db/status?folder=" + url.QueryEscape(folder)) - if err != nil { - return Model{}, err - } - - var res Model - if err := json.Unmarshal(bs, &res); err != nil { - return Model{}, err + if err := p.Get(ctx, fmt.Sprintf("/rest/events?since=%d&timeout=10", since), &evs); err != nil { + return nil, err } - - l.Debugf("%+v", res) - - return res, nil + return evs, nil } -func (*Process) readResponse(resp *http.Response) ([]byte, error) { +func (*API) readResponse(resp *http.Response, dst any) error { bs, err := io.ReadAll(resp.Body) resp.Body.Close() - if err != nil { - return bs, err - } - if resp.StatusCode != 200 { - return bs, errors.New(resp.Status) - } - return bs, nil -} - -func (p *Process) checkForProblems(logfd *os.File) error { - fd, err := os.Open(logfd.Name()) if err != nil { return err } - defer fd.Close() - - raceConditionStart := []byte("WARNING: DATA RACE") - raceConditionSep := []byte("==================") - panicConditionStart := []byte("panic:") - panicConditionSep := []byte("[") // fallback if we don't already know our ID - if p.id.String() != "" { - panicConditionSep = []byte(p.id.String()[:5]) + if resp.StatusCode == http.StatusNoContent { + return nil } - sc := bufio.NewScanner(fd) - race := false - _panic := false - - for sc.Scan() { - line := sc.Bytes() - if race || _panic { - if bytes.Contains(line, panicConditionSep) { - _panic = false - continue - } - fmt.Printf("%s\n", line) - if bytes.Contains(line, raceConditionSep) { - race = false - } - } else if bytes.Contains(line, raceConditionStart) { - fmt.Printf("%s\n", raceConditionSep) - fmt.Printf("%s\n", raceConditionStart) - race = true - if err == nil { - err = errors.New("Race condition detected") - } - } else if bytes.Contains(line, panicConditionStart) { - _panic = true - if err == nil { - err = errors.New("Panic detected") - } - } + if resp.StatusCode != http.StatusOK { + return errors.New(resp.Status) } - - return err -} - -func (p *Process) eventLoop() { - since := 0 - notScanned := make(map[string]struct{}) - start := time.Now() - for { - select { - case <-p.stopped: - return - default: - } - - evs, err := p.Events(since) - if err != nil { - if time.Since(start) < 5*time.Second { - // The API has probably not started yet, lets give it some time. - continue - } - - // If we're stopping, no need to print the error. - select { - case <-p.stopped: - return - default: - } - - log.Println("eventLoop: events:", err) - continue - } - - for _, ev := range evs { - if ev.ID != since+1 { - l.Warnln("Event ID jumped", since, "to", ev.ID) - } - since = ev.ID - - switch ev.Type { - case "Starting": - // The Starting event tells us where the configuration is. Load - // it and populate our list of folders. - - data := ev.Data.(map[string]interface{}) - id, err := protocol.DeviceIDFromString(data["myID"].(string)) - if err != nil { - log.Println("eventLoop: DeviceIdFromString:", err) - continue - } - p.id = id - - home := data["home"].(string) - w, _, err := config.Load(filepath.Join(home, "config.xml"), protocol.LocalDeviceID, events.NoopLogger) - if err != nil { - log.Println("eventLoop: Starting:", err) - continue - } - for id := range w.Folders() { - p.eventMut.Lock() - p.folders = append(p.folders, id) - p.eventMut.Unlock() - notScanned[id] = struct{}{} - } - - l.Debugln("Started", p.id) - - case "StateChanged": - // When a folder changes to idle, we tick it off by removing - // it from p.notScanned. - - if len(p.folders) == 0 { - // We haven't parsed the config yet, shouldn't happen - panic("race, or lost startup event") - } - - select { - case <-p.startComplete: - default: - data := ev.Data.(map[string]interface{}) - to := data["to"].(string) - if to == "idle" { - folder := data["folder"].(string) - delete(notScanned, folder) - if len(notScanned) == 0 { - close(p.startComplete) - } - } - } - - case "LocalIndexUpdated": - data := ev.Data.(map[string]interface{}) - folder := data["folder"].(string) - p.eventMut.Lock() - m := p.updateSequenceLocked(folder, p.id.String(), data["sequence"]) - p.done[folder] = false - l.Debugf("LocalIndexUpdated %v %v done=false\n\t%+v", p.id, folder, m) - p.eventMut.Unlock() - - case "RemoteIndexUpdated": - data := ev.Data.(map[string]interface{}) - device := data["device"].(string) - folder := data["folder"].(string) - p.eventMut.Lock() - m := p.updateSequenceLocked(folder, device, data["sequence"]) - p.done[folder] = false - l.Debugf("RemoteIndexUpdated %v %v done=false\n\t%+v", p.id, folder, m) - p.eventMut.Unlock() - - case "FolderSummary": - data := ev.Data.(map[string]interface{}) - folder := data["folder"].(string) - summary := data["summary"].(map[string]interface{}) - need, _ := summary["needTotalItems"].(json.Number).Int64() - done := need == 0 - p.eventMut.Lock() - m := p.updateSequenceLocked(folder, p.id.String(), summary["sequence"]) - p.done[folder] = done - l.Debugf("FolderSummary %v %v\n\t%+v\n\t%+v", p.id, folder, p.done, m) - p.eventMut.Unlock() - - case "FolderCompletion": - data := ev.Data.(map[string]interface{}) - device := data["device"].(string) - folder := data["folder"].(string) - p.eventMut.Lock() - m := p.updateSequenceLocked(folder, device, data["sequence"]) - l.Debugf("FolderCompletion %v\n\t%+v", p.id, folder, m) - p.eventMut.Unlock() - } - } + if dst == nil { + return nil } -} - -func (p *Process) updateSequenceLocked(folder, device string, sequenceIntf interface{}) map[string]int64 { - sequence, _ := sequenceIntf.(json.Number).Int64() - m := p.sequence[folder] - if m == nil { - m = make(map[string]int64) - } - m[device] = sequence - p.sequence[folder] = m - return m -} - -type ConnectionStats struct { - Address string - Type string - Connected bool - Paused bool - ClientVersion string - InBytesTotal int64 - OutBytesTotal int64 -} - -func (p *Process) Connections() (map[string]ConnectionStats, error) { - bs, err := p.Get("/rest/system/connections") - if err != nil { - return nil, err - } - - var res map[string]ConnectionStats - if err := json.Unmarshal(bs, &res); err != nil { - return nil, err - } - - return res, nil -} - -type SystemStatus struct { - Alloc int64 - Goroutines int - MyID protocol.DeviceID - PathSeparator string - StartTime time.Time - Sys int64 - Themes []string - Tilde string - Uptime int -} - -func (p *Process) SystemStatus() (SystemStatus, error) { - bs, err := p.Get("/rest/system/status") - if err != nil { - return SystemStatus{}, err - } - - var res SystemStatus - if err := json.Unmarshal(bs, &res); err != nil { - return SystemStatus{}, err - } - - return res, nil -} - -type SystemVersion struct { - Arch string - Codename string - LongVersion string - OS string - Version string -} - -func (p *Process) SystemVersion() (SystemVersion, error) { - bs, err := p.Get("/rest/system/version") - if err != nil { - return SystemVersion{}, err - } - - var res SystemVersion - if err := json.Unmarshal(bs, &res); err != nil { - return SystemVersion{}, err - } - - return res, nil -} - -func (p *Process) RemoteInSync(folder string, dev protocol.DeviceID) (bool, error) { - bs, err := p.Get(fmt.Sprintf("/rest/db/completion?folder=%v&device=%v", url.QueryEscape(folder), dev)) - if err != nil { - return false, err - } - - var comp model.FolderCompletion - if err := json.Unmarshal(bs, &comp); err != nil { - return false, err - } - - return comp.NeedItems+comp.NeedDeletes == 0, nil + return json.Unmarshal(bs, dst) } diff --git a/test/.gitignore b/test/.gitignore deleted file mode 100644 index 85a78711906..00000000000 --- a/test/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -s1 -s2 -s3 -s4 -s12-1 -s12-2 -s23-2 -s23-3 -md5-* -genfiles -md5r -json -*.idx.gz -dirs-* -*.out -csrftokens.txt -s4d -http -h*/index* -*.syncthing-reset* -panic-*.log -audit-*.log -h*/config.xml.v* -h*/config.xml.orig diff --git a/test/cli_test.go b/test/cli_test.go deleted file mode 100644 index c19d4383124..00000000000 --- a/test/cli_test.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "os" - "os/exec" - "path/filepath" - "testing" - "time" -) - -func TestCLIReset(t *testing.T) { - dirs := []string{"h1/index-v0.14.0.db"} - - // Create directories that reset will remove - - for _, dir := range dirs { - err := os.Mkdir(dir, 0755) - if err != nil && !os.IsExist(err) { - t.Fatal(err) - } - } - - // Run reset to clean up - - cmd := exec.Command("../bin/syncthing", "--no-browser", "--home", "h1", "--reset-database") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stdout - err := cmd.Run() - if err != nil { - t.Fatal(err) - } - - // Verify that they're gone - - for _, dir := range dirs { - _, err := os.Stat(dir) - if err == nil { - t.Errorf("%s still exists", dir) - } - } - - // Clean up - - dirs, err = filepath.Glob("*.syncthing-reset-*") - if err != nil { - t.Fatal(err) - } - removeAll(dirs...) -} - -func TestCLIGenerate(t *testing.T) { - err := os.RemoveAll("home.out") - if err != nil { - t.Fatal(err) - } - - // --generate should create a bunch of stuff - - cmd := exec.Command("../bin/syncthing", "--no-browser", "--generate", "home.out") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stdout - err = cmd.Run() - if err != nil { - t.Fatal(err) - } - - // Verify that the files that should have been created have been - - for _, f := range []string{"home.out/config.xml", "home.out/cert.pem", "home.out/key.pem"} { - _, err := os.Stat(f) - if err != nil { - t.Errorf("%s is not correctly generated", f) - } - } -} - -func TestCLIFirstStartup(t *testing.T) { - err := os.RemoveAll("home.out") - if err != nil { - t.Fatal(err) - } - - // First startup should create config, BEP certificate, and HTTP certificate. - - cmd := exec.Command("../bin/syncthing", "--no-browser", "--home", "home.out") - cmd.Env = append(os.Environ(), "STNORESTART=1") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stdout - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - exitError := make(chan error, 1) - filesOk := make(chan struct{}) - processDone := make(chan struct{}) - - go func() { - // Wait for process exit. - exitError <- cmd.Wait() - close(processDone) - }() - - go func() { - again: - for { - select { - case <-processDone: - return - default: - // Verify that the files that should have been created have been - for _, f := range []string{"home.out/config.xml", "home.out/cert.pem", "home.out/key.pem", "home.out/https-cert.pem", "home.out/https-key.pem"} { - _, err := os.Stat(f) - if err != nil { - time.Sleep(500 * time.Millisecond) - continue again - } - } - - // Make sure the process doesn't exit with an error just after creating certificates. - time.Sleep(time.Second) - filesOk <- struct{}{} - return - } - } - }() - - select { - case e := <-exitError: - t.Error(e) - case <-filesOk: - cmd.Process.Kill() - return - } -} diff --git a/test/conflict_test.go b/test/conflict_test.go deleted file mode 100644 index de93fe3542a..00000000000 --- a/test/conflict_test.go +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright (C) 2015 The Syncthing Authors. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. - -//go:build integration -// +build integration - -package integration - -import ( - "bytes" - "log" - "os" - "path/filepath" - "testing" - "time" - - "github.com/syncthing/syncthing/lib/rc" -) - -func TestConflictsDefault(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 100, 20, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - fd, err := os.Create("s1/testfile.txt") - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("hello\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - expected, err := directoryContents("s1") - if err != nil { - t.Fatal(err) - } - - sender := startInstance(t, 1) - defer checkedStop(t, sender) - receiver := startInstance(t, 2) - defer checkedStop(t, receiver) - - sender.ResumeAll() - receiver.ResumeAll() - - // Rescan with a delay on the next one, so we are not surprised by a - // sudden rescan while we're trying to introduce conflicts. - - if err := sender.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - if err := receiver.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - rc.AwaitSync("default", sender, receiver) - - log.Println("Verifying...") - - actual, err := directoryContents("s2") - if err != nil { - t.Fatal(err) - } - err = compareDirectoryContents(actual, expected) - if err != nil { - t.Fatal(err) - } - - log.Println("Introducing a conflict (simultaneous edit)...") - - if err := sender.PauseDevice(receiver.ID()); err != nil { - t.Fatal(err) - } - - fd, err = os.OpenFile("s1/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("text added to s1\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - fd, err = os.OpenFile("s2/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("text added to s2\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - if err := sender.ResumeDevice(receiver.ID()); err != nil { - t.Fatal(err) - } - - log.Println("Syncing...") - - if err := sender.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - if err := receiver.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - rc.AwaitSync("default", sender, receiver) - - // Expect one conflict file, created on either side. - - files, err := filepath.Glob("s?/*sync-conflict*") - if err != nil { - t.Fatal(err) - } - if len(files) != 2 { - t.Errorf("Expected 1 conflicted file on each side, instead of totally %d", len(files)) - } else if filepath.Base(files[0]) != filepath.Base(files[1]) { - t.Errorf(`Expected same conflicted file on both sides, got "%v" and "%v"`, files[0], files[1]) - } - - log.Println("Introducing a conflict (edit plus delete)...") - - if err := sender.PauseDevice(receiver.ID()); err != nil { - t.Fatal(err) - } - - err = os.Remove("s1/testfile.txt") - if err != nil { - t.Fatal(err) - } - - fd, err = os.OpenFile("s2/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("more text added to s2\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - if err := sender.ResumeDevice(receiver.ID()); err != nil { - t.Fatal(err) - } - - log.Println("Syncing...") - - if err := sender.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - if err := receiver.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - rc.AwaitSync("default", sender, receiver) - - // The conflict is resolved to the advantage of the edit over the delete. - // As such, we get the edited content synced back to s1 where it was - // removed. - - files, err = filepath.Glob("s2/*sync-conflict*") - if err != nil { - t.Fatal(err) - } - if len(files) != 1 { - t.Errorf("Expected 1 conflicted files instead of %d", len(files)) - } - bs, err := os.ReadFile("s1/testfile.txt") - if err != nil { - t.Error("reading file:", err) - } - if !bytes.Contains(bs, []byte("more text added to s2")) { - t.Error("s1/testfile.txt should contain data added in s2") - } -} - -func TestConflictsInitialMerge(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - err = os.Mkdir("s1", 0755) - if err != nil { - t.Fatal(err) - } - err = os.Mkdir("s2", 0755) - if err != nil { - t.Fatal(err) - } - - // File 1 is a conflict - - err = os.WriteFile("s1/file1", []byte("hello\n"), 0644) - if err != nil { - t.Fatal(err) - } - - err = os.WriteFile("s2/file1", []byte("goodbye\n"), 0644) - if err != nil { - t.Fatal(err) - } - - // File 2 exists on s1 only - - err = os.WriteFile("s1/file2", []byte("hello\n"), 0644) - if err != nil { - t.Fatal(err) - } - - // File 3 exists on s2 only - - err = os.WriteFile("s2/file3", []byte("goodbye\n"), 0644) - if err != nil { - t.Fatal(err) - } - - // Let them sync - - sender := startInstance(t, 1) - defer checkedStop(t, sender) - receiver := startInstance(t, 2) - defer checkedStop(t, receiver) - - sender.ResumeAll() - receiver.ResumeAll() - - log.Println("Syncing...") - - rc.AwaitSync("default", sender, receiver) - - // Do it once more so the conflict copies propagate to both sides. - - sender.Rescan("default") - receiver.Rescan("default") - - rc.AwaitSync("default", sender, receiver) - - checkedStop(t, sender) - checkedStop(t, receiver) - - log.Println("Verifying...") - - // s1 should have four files (there's a conflict) - - files, err := filepath.Glob("s1/file*") - if err != nil { - t.Fatal(err) - } - if len(files) != 4 { - t.Errorf("Expected 4 files in s1 instead of %d", len(files)) - } - - // s2 should have four files (there's a conflict) - - files, err = filepath.Glob("s2/file*") - if err != nil { - t.Fatal(err) - } - if len(files) != 4 { - t.Errorf("Expected 4 files in s2 instead of %d", len(files)) - } - - // file1 is in conflict, so there's two versions of that one - - files, err = filepath.Glob("s2/file1*") - if err != nil { - t.Fatal(err) - } - if len(files) != 2 { - t.Errorf("Expected 2 'file1' files in s2 instead of %d", len(files)) - } -} - -func TestConflictsIndexReset(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - err = os.Mkdir("s1", 0755) - if err != nil { - t.Fatal(err) - } - err = os.Mkdir("s2", 0755) - if err != nil { - t.Fatal(err) - } - - // Three files on s1 - - err = os.WriteFile("s1/file1", []byte("hello\n"), 0644) - if err != nil { - t.Fatal(err) - } - err = os.WriteFile("s1/file2", []byte("hello\n"), 0644) - if err != nil { - t.Fatal(err) - } - err = os.WriteFile("s2/file3", []byte("hello\n"), 0644) - if err != nil { - t.Fatal(err) - } - - // Let them sync - - sender := startInstance(t, 1) - defer checkedStop(t, sender) - receiver := startInstance(t, 2) - defer checkedStop(t, receiver) - - sender.ResumeAll() - receiver.ResumeAll() - - log.Println("Syncing...") - - rc.AwaitSync("default", sender, receiver) - - log.Println("Verifying...") - - // s1 should have three files - - files, err := filepath.Glob("s1/file*") - if err != nil { - t.Fatal(err) - } - if len(files) != 3 { - t.Errorf("Expected 3 files in s1 instead of %d", len(files)) - } - - // s2 should have three files - - files, err = filepath.Glob("s2/file*") - if err != nil { - t.Fatal(err) - } - if len(files) != 3 { - t.Errorf("Expected 3 files in s2 instead of %d", len(files)) - } - - log.Println("Updating...") - - // change s2/file2 a few times, so that its version counter increases. - // This will make the file on the cluster look newer than what we have - // locally after we rest the index, unless we have a fix for that. - - for i := 0; i < 5; i++ { - err = os.WriteFile("s2/file2", []byte("hello1\n"), 0644) - if err != nil { - t.Fatal(err) - } - err = receiver.Rescan("default") - if err != nil { - t.Fatal(err) - } - time.Sleep(time.Second) - } - - rc.AwaitSync("default", sender, receiver) - - // Now nuke the index - - log.Println("Resetting...") - - checkedStop(t, receiver) - removeAll("h2/index*") - - // s1/file1 (remote) changes while receiver is down - - err = os.WriteFile("s1/file1", []byte("goodbye\n"), 0644) - if err != nil { - t.Fatal(err) - } - - // s1 must know about it - err = sender.Rescan("default") - if err != nil { - t.Fatal(err) - } - - // s2/file2 (local) changes while receiver is down - - err = os.WriteFile("s2/file2", []byte("goodbye\n"), 0644) - if err != nil { - t.Fatal(err) - } - - receiver = startInstance(t, 2) - defer checkedStop(t, receiver) - receiver.ResumeAll() - - log.Println("Syncing...") - - rc.AwaitSync("default", sender, receiver) - - // s2 should have five files (three plus two conflicts) - - files, err = filepath.Glob("s2/file*") - if err != nil { - t.Fatal(err) - } - if len(files) != 5 { - t.Errorf("Expected 5 files in s2 instead of %d", len(files)) - } - - // file1 is in conflict, so there's two versions of that one - - files, err = filepath.Glob("s2/file1*") - if err != nil { - t.Fatal(err) - } - if len(files) != 2 { - t.Errorf("Expected 2 'file1' files in s2 instead of %d", len(files)) - } - - // file2 is in conflict, so there's two versions of that one - - files, err = filepath.Glob("s2/file2*") - if err != nil { - t.Fatal(err) - } - if len(files) != 2 { - t.Errorf("Expected 2 'file2' files in s2 instead of %d", len(files)) - } -} - -func TestConflictsSameContent(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - err = os.Mkdir("s1", 0755) - if err != nil { - t.Fatal(err) - } - err = os.Mkdir("s2", 0755) - if err != nil { - t.Fatal(err) - } - - // Two files on s1 - - err = os.WriteFile("s1/file1", []byte("hello\n"), 0644) - if err != nil { - t.Fatal(err) - } - err = os.WriteFile("s1/file2", []byte("hello\n"), 0644) - if err != nil { - t.Fatal(err) - } - - // Two files on s2, content differs in file1 only, timestamps differ on both. - - err = os.WriteFile("s2/file1", []byte("goodbye\n"), 0644) - if err != nil { - t.Fatal(err) - } - err = os.WriteFile("s2/file2", []byte("hello\n"), 0644) - if err != nil { - t.Fatal(err) - } - - ts := time.Now().Add(-time.Hour) - os.Chtimes("s2/file1", ts, ts) - os.Chtimes("s2/file2", ts, ts) - - // Let them sync - - sender := startInstance(t, 1) - defer checkedStop(t, sender) - receiver := startInstance(t, 2) - defer checkedStop(t, receiver) - - sender.ResumeAll() - receiver.ResumeAll() - - log.Println("Syncing...") - - rc.AwaitSync("default", sender, receiver) - - // Let conflict copies propagate - - sender.Rescan("default") - receiver.Rescan("default") - rc.AwaitSync("default", sender, receiver) - - log.Println("Verifying...") - - // s1 should have three files - - files, err := filepath.Glob("s1/file*") - if err != nil { - t.Fatal(err) - } - if len(files) != 3 { - t.Errorf("Expected 3 files in s1 instead of %d", len(files)) - } - - // s2 should have three files - - files, err = filepath.Glob("s2/file*") - if err != nil { - t.Fatal(err) - } - if len(files) != 3 { - t.Errorf("Expected 3 files in s2 instead of %d", len(files)) - } -} diff --git a/test/delay_scan_test.go b/test/delay_scan_test.go deleted file mode 100644 index 1cb90e2c179..00000000000 --- a/test/delay_scan_test.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "log" - "os" - "sync" - "testing" - "time" -) - -func TestRescanWithDelay(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "h1/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 50, 18, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating .stignore...") - err = os.WriteFile("s1/.stignore", []byte("some ignore data\n"), 0644) - if err != nil { - t.Fatal(err) - } - - log.Println("Starting up...") - - st := startInstance(t, 1) - - var wg sync.WaitGroup - log.Println("Starting scans...") - for j := 0; j < 20; j++ { - j := j - wg.Add(1) - go func() { - defer wg.Done() - err := st.RescanDelay("default", 1) - log.Println(j) - if err != nil { - log.Println(err) - t.Fatal(err) - } - }() - } - - wg.Wait() - log.Println("Scans done") - time.Sleep(2 * time.Second) - - // This is where the real test is currently, since stop() checks for data - // race output in the log. - log.Println("Stopping...") - checkedStop(t, st) -} diff --git a/test/file_util.go b/test/file_util.go new file mode 100644 index 00000000000..ff0e7852d9d --- /dev/null +++ b/test/file_util.go @@ -0,0 +1,140 @@ +// Copyright (C) 2023 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 integration + +import ( + "fmt" + "io" + "os" + "path/filepath" + "strings" + "testing" + + "golang.org/x/exp/slices" + + "github.com/syncthing/syncthing/lib/rand" + "github.com/syncthing/syncthing/lib/sha256" +) + +// generateTree generates n files with random data in a temporary directory +// and returns the path to the directory. +func generateTree(t *testing.T, n int) string { + t.Helper() + dir := t.TempDir() + for i := 0; i < n; i++ { + // Generate a random string. The first character is the directory + // name, the rest is the file name. + rnd := strings.ToLower(rand.String(16)) + sub := rnd[:1] + file := rnd[1:] + size := 512<<10 + rand.Intn(1024)<<10 // between 512 KiB and 1.5 MiB + + // Create the file with random data. + os.Mkdir(filepath.Join(dir, sub), 0o700) + lr := io.LimitReader(rand.Reader, int64(size)) + fd, err := os.Create(filepath.Join(dir, sub, file)) + if err != nil { + t.Fatal(err) + } + _, err = io.Copy(fd, lr) + if err != nil { + t.Fatal(err) + } + if err := fd.Close(); err != nil { + t.Fatal(err) + } + } + return dir +} + +// compareTrees compares the contents of two directories recursively. It +// reports any differences as test failures. Returns the number of files +// that were checked. +func compareTrees(t *testing.T, a, b string) int { + t.Helper() + + // These will not match, so we ignore them. + ignore := []string{".", ".stfolder"} + + nfiles := 0 + if err := filepath.Walk(a, func(path string, aInfo os.FileInfo, err error) error { + if err != nil { + return err + } + + rel, err := filepath.Rel(a, path) + if err != nil { + return err + } + + // We need to ignore any files under .stfolder, too. + // See https://github.com/syncthing/syncthing/pull/9525 + if slices.ContainsFunc(ignore, func(ignore string) bool { + return strings.HasPrefix(rel, ignore) + }) { + return nil + } + + bPath := filepath.Join(b, rel) + bInfo, err := os.Stat(bPath) + if err != nil { + return err + } + + if aInfo.IsDir() != bInfo.IsDir() { + t.Errorf("mismatched directory/file: %q", rel) + } + + if aInfo.Mode() != bInfo.Mode() { + t.Errorf("mismatched mode: %q", rel) + } + + if aInfo.Mode().IsRegular() { + if !aInfo.ModTime().Equal(bInfo.ModTime()) { + t.Errorf("mismatched mod time: %q", rel) + } + + if aInfo.Size() != bInfo.Size() { + t.Errorf("mismatched size: %q", rel) + } + + aHash, err := sha256file(path) + if err != nil { + return err + } + bHash, err := sha256file(bPath) + if err != nil { + return err + } + if aHash != bHash { + t.Errorf("mismatched hash: %q", rel) + } + + nfiles++ + } + + return nil + }); err != nil { + t.Fatal(err) + } + return nfiles +} + +func sha256file(fname string) (string, error) { + f, err := os.Open(fname) + if err != nil { + return "", err + } + defer f.Close() + + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + return "", err + } + hb := h.Sum(nil) + return fmt.Sprintf("%x", hb), nil +} diff --git a/test/filetype_test.go b/test/filetype_test.go deleted file mode 100644 index a6e4987a867..00000000000 --- a/test/filetype_test.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "log" - "os" - "testing" - - "github.com/syncthing/syncthing/lib/config" - "github.com/syncthing/syncthing/lib/events" - "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/rc" -) - -func TestFileTypeChange(t *testing.T) { - // Use no versioning - id, _ := protocol.DeviceIDFromString(id2) - cfg, _, _ := config.Load("h2/config.xml", id, events.NoopLogger) - fld := cfg.Folders()["default"] - fld.Versioning = config.VersioningConfiguration{} - cfg.SetFolder(fld) - os.Rename("h2/config.xml", "h2/config.xml.orig") - defer os.Rename("h2/config.xml.orig", "h2/config.xml") - cfg.Save() - - testFileTypeChange(t) -} - -func TestFileTypeChangeSimpleVersioning(t *testing.T) { - // Use simple versioning - id, _ := protocol.DeviceIDFromString(id2) - cfg, _, _ := config.Load("h2/config.xml", id, events.NoopLogger) - fld := cfg.Folders()["default"] - fld.Versioning = config.VersioningConfiguration{ - Type: "simple", - Params: map[string]string{"keep": "5"}, - } - cfg.SetFolder(fld) - os.Rename("h2/config.xml", "h2/config.xml.orig") - defer os.Rename("h2/config.xml.orig", "h2/config.xml") - cfg.Save() - - testFileTypeChange(t) -} - -func TestFileTypeChangeStaggeredVersioning(t *testing.T) { - // Use staggered versioning - id, _ := protocol.DeviceIDFromString(id2) - cfg, _, _ := config.Load("h2/config.xml", id, events.NoopLogger) - fld := cfg.Folders()["default"] - fld.Versioning = config.VersioningConfiguration{ - Type: "staggered", - } - cfg.SetFolder(fld) - os.Rename("h2/config.xml", "h2/config.xml.orig") - defer os.Rename("h2/config.xml.orig", "h2/config.xml") - cfg.Save() - - testFileTypeChange(t) -} - -func testFileTypeChange(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 100, 20, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - // A file that we will replace with a directory later - - if fd, err := os.Create("s1/fileToReplace"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - - // A directory that we will replace with a file later - - err = os.Mkdir("s1/emptyDirToReplace", 0755) - if err != nil { - t.Fatal(err) - } - - // A directory with files that we will replace with a file later - - err = os.Mkdir("s1/dirToReplace", 0755) - if err != nil { - t.Fatal(err) - } - if fd, err := os.Create("s1/dirToReplace/emptyFile"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - - // Verify that the files and directories sync to the other side - - sender := startInstance(t, 1) - defer checkedStop(t, sender) - - receiver := startInstance(t, 2) - defer checkedStop(t, receiver) - - sender.ResumeAll() - receiver.ResumeAll() - - log.Println("Syncing...") - - rc.AwaitSync("default", sender, receiver) - - // Delay scans for the moment - if err := sender.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - log.Println("Making some changes...") - - // Replace file with directory - - err = os.RemoveAll("s1/fileToReplace") - if err != nil { - t.Fatal(err) - } - err = os.Mkdir("s1/fileToReplace", 0755) - if err != nil { - t.Fatal(err) - } - - // Replace empty directory with file - - err = os.RemoveAll("s1/emptyDirToReplace") - if err != nil { - t.Fatal(err) - } - if fd, err := os.Create("s1/emptyDirToReplace"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - - // Clear directory and replace with file - - err = os.RemoveAll("s1/dirToReplace") - if err != nil { - t.Fatal(err) - } - if fd, err := os.Create("s1/dirToReplace"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - - // Sync these changes and recheck - - log.Println("Syncing...") - - if err := sender.Rescan("default"); err != nil { - t.Fatal(err) - } - - rc.AwaitSync("default", sender, receiver) - - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } -} diff --git a/test/folders.sh b/test/folders.sh deleted file mode 100755 index 52cfb62a847..00000000000 --- a/test/folders.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -for ((id=0;id<200;id++)); do -cat < - fake - - - -EOT -done \ No newline at end of file diff --git a/test/h1/cert.pem b/test/h1/cert.pem deleted file mode 100644 index 3af840e15d5..00000000000 --- a/test/h1/cert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID3jCCAkigAwIBAgIBADALBgkqhkiG9w0BAQUwFDESMBAGA1UEAxMJc3luY3Ro -aW5nMB4XDTE0MDMxNDA3MDA1M1oXDTQ5MTIzMTIzNTk1OVowFDESMBAGA1UEAxMJ -c3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEArDOcd5ft -R7SnalxF1ckU3lDQpgfMIPhFDU//4dvdSSFevrMuVDTbUYhyCfGtg/g+F5TmKhZg -E2peYhllITupz5MP7OHGaO2GHf2XnUDD4QUO3E+KVAUw7dyFSwy09esqApVLzH3+ -ov+QXyyzmRWPsJe9u18BHU1Hob/RmBhS9m2CAJgzN6EJ8KGjApiW3iR8lD/hjVyi -IVde8IRD6qYHEJYiPJuziTVcQpCblVYxTz3ScmmT190/O9UvViIpcOPQdwgOdewP -NNMK35c9Edt0AH5flYp6jgrja9NkLQJ3+KOiro6yl9IUS5w87GMxI8qzI8SgCAZZ -pYSoLbu1FJPvxV4p5eHwuprBCwmFYZWw6Y7rqH0sN52C+3TeObJCMNP9ilPadqRI -+G0Q99TCaloeR022x33r/8D8SIn3FP35zrlFM+DvqlxoS6glbNb/Bj3p9vN0XONO -RCuynOGe9F/4h/DaNnrbrRWqJOxBsZTsbbcJaKATfWU/Z9GcC+pUpPRhAgMBAAGj -PzA9MA4GA1UdDwEB/wQEAwIAoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH -AwIwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQUDggGBAFF8dklGoC43fMrUZfb4 -6areRWG8quO6cSX6ATzRQVJ8WJ5VcC7OJk8/FeiYA+wcvUJ/1Zm/VHMYugtOz5M8 -CrWAF1r9D3Xfe5D8qfrEOYG2XjxD2nFHCnkbY4fP+SMSuXaDs7ixQnzw0UFh1wsV -9Jy/QrgXFAIFZtu1Nz+rrvoAgw24gkDhY3557MbmYfmfPsJ8cw+WJ845sxGMPFF2 -c+5EN0jiSm0AwZK11BMJda36ke829UZctDkopbGEg1peydDR5LiyhiTAPtWn7uT/ -PkzHYLuaECAkVbWC3bZLocMGOP6F1pG+BMr00NJgVy05ASQzi4FPjcZQNNY8s69R -ZgoCIBaJZq3ti1EsZQ1H0Ynm2c2NMVKdj4czoy8a9ZC+DCuhG7EV5Foh20VhCWgA -RfPhlHVJthuimsWBx39X85gjSBR017uk0AxOJa6pzh/b/RPCRtUfX8EArInS3XCf -RvRtdrnBZNI3tiREopZGt0SzgDZUs4uDVBUX8HnHzyFJrg== ------END CERTIFICATE----- diff --git a/test/h1/config.xml b/test/h1/config.xml deleted file mode 100644 index c55cc5349ee..00000000000 --- a/test/h1/config.xml +++ /dev/null @@ -1,188 +0,0 @@ - - - basic - - - - - - - 1 - - 3600 - - basic - - 1 - 0 - 0 - random - false - 0 - 0 - -1 - false - false - false - 25 - .stfolder - false - 0 - 2 - false - standard - standard - false - true - false - false - false - false - - 0 - 0 - - - -
tcp://127.0.0.1:22001
- false - false - 0 - 0 - 0 - false - 0 - 3 -
- -
tcp://127.0.0.1:22002
-
quic://127.0.0.1:22002
- false - false - 0 - 0 - 0 - false - 0 - 3 -
- -
127.0.0.1:8081
- testuser - $2a$10$7tKL5uvLDGn5s2VLPM2yWOK/II45az0mTel8hxAUJDRQN1Tk2QYwu - abc123 - default -
- - - tcp://127.0.0.1:22001 - quic://127.0.0.1:22001 - default - false - true - 21027 - [ff12::8384]:21027 - 0 - 0 - 5 - false - 10 - false - true - 0 - 30 - 10 - 3 - 2 - tmwxxCqi - https://data.syncthing.net/newdata - false - 1800 - 12 - false - 24 - false - 5 - false - 1 - https://upgrades.syncthing.net/meta.json - false - 10 - 0 - true - 0 - https://crash.syncthing.net/newcrash - true - 180 - 20 - default - auto - 0 - true - false - 0 - 0 - false - 10 - 20 - 30 - 40 - 50 - 0 - - - - basic - - - - 1 - - 3600 - - basic - - 0 - 0 - 0 - random - false - 0 - 0 - 10 - false - false - false - 25 - .stfolder - false - 0 - 2 - false - standard - standard - false - false - false - false - false - false - - 1024 - 4096 - - - -
dynamic
- false - false - 0 - 0 - 0 - false - 0 - 3 -
- -
-
diff --git a/test/h1/https-cert.pem b/test/h1/https-cert.pem deleted file mode 100644 index ac14760f07b..00000000000 --- a/test/h1/https-cert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID5TCCAk+gAwIBAgIIBYqoKiSgB+owCwYJKoZIhvcNAQELMBQxEjAQBgNVBAMT -CXN5bmN0aGluZzAeFw0xNDA5MTQyMjIzMzVaFw00OTEyMzEyMzU5NTlaMBQxEjAQ -BgNVBAMTCXN5bmN0aGluZzCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGB -AKZK/sjb6ZuVVHPvo77Cp5E8LfiznfoIWJRoX/MczE99iDyFZm1Wf9GFT8WhXICM -C2kgGbr/gAxhkeEcZ500vhA2C+aois1DGcb+vNY53I0qp3vSUl4ow55R0xJ4UjpJ -nJWF8p9iPDMwMP6WQ/E/ekKRKCOt0TFj4xqtiSt0pxPLeHfKVpWXxqIVDhnsoGQ+ -NWuUjM3FkmEmhp5DdRtwskiZZYz1zCgoHkFzKt/+IxjCuzbO0+Ti8R3b/d0A+WLN -LHr0SjatajLbHebA+9c3ts6t3V5YzcMqDJ4MyxFtRoXFJjEbcM9IqKQE8t8TIhv8 -a302yRikJ2uPx+fXJGospnmWCbaK2rViPbvICSgvSBA3As0f3yPzXsEt+aW5NmDV -fLBX1DU7Ow6oBqZTlI+STrzZR1qfvIuweIWoPqnPNd4sxuoxAK50ViUKdOtSYL/a -F0eM3bqbp2ozhct+Bfmqu2oI/RHXe+RUfAXrlFQ8p6jcISW2ip+oiBtR4GZkncI9 -YQIDAQABoz8wPTAOBgNVHQ8BAf8EBAMCAKAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG -CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCwYJKoZIhvcNAQELA4IBgQBsYc5XVQy5 -aJVdwx+mAKiuCs5ZCvV4H4VWY9XUwEJuUUD3yXw2xyzuQl5+lOxfiQcaudhVwARC -Dao75MUctXmx1YU+J5G31cGdC9kbxWuo1xypkK+2Zl+Kwh65aod3OkHVz9oNkKpf -JnXbdph4UiFJzijSruXDDaerrQdABUvlusPozZn8vMwZ21Ls/eNIOJvA0S2d2jep -fvmu7yQPejDp7zcgPdmneuZqmUyXLxxFopYqHqFQVM8f+Y8iZ8HnMiAJgLKQcmro -pp1z/NY0Xr0pLyBY5d/sO+tZmQkyUEWegHtEtQQOO+x8BWinDEAurej/YvZTWTmN -+YoUvGdKyV6XfC6WPFcUDFHY4KPSqS3xoLmoVV4xNjJU3aG/xL4uDencNZR/UFNw -wKsdvm9SX4TpSLlQa0wu1iNv7QyeR4ZKgaBNSwp2rxpatOi7TTs9KRPfjLFLpYAg -bIons/a890SIxpuneuhQZkH63t930EXIZ+9GkU0aUs7MFg5cCmwmlvE= ------END CERTIFICATE----- diff --git a/test/h1/https-key.pem b/test/h1/https-key.pem deleted file mode 100644 index ac3d2fafc9f..00000000000 --- a/test/h1/https-key.pem +++ /dev/null @@ -1,39 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/test/h1/key.pem b/test/h1/key.pem deleted file mode 100644 index 4c40deb8bf4..00000000000 --- a/test/h1/key.pem +++ /dev/null @@ -1,39 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/test/h2/cert.pem b/test/h2/cert.pem deleted file mode 100644 index 0ddc3cde77e..00000000000 --- a/test/h2/cert.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBmzCCASCgAwIBAgIIawvqtXNSqBQwCgYIKoZIzj0EAwMwFDESMBAGA1UEAxMJ -c3luY3RoaW5nMB4XDTE1MTEyNzA4MDA1N1oXDTQ5MTIzMTIzNTk1OVowFDESMBAG -A1UEAxMJc3luY3RoaW5nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7iI2E5etAs53 -6s+SUV3HKZeK55iHUY6X4PHePjyvNxOCZ6GvbErOXWqumU4+vzVREW1wvNtGXAtv -z/hsHIPJ7EdKIX0QPATms2NplCbaFlUxHBpUzhlNulhsoV5ajn7yoz8wPTAOBgNV -HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud -EwEB/wQCMAAwCgYIKoZIzj0EAwMDaQAwZgIxAPe+pj6NrQiK720v/9IMDPWIRxqt -hxgy03YGzbQskXRDJVvLU49HCHV+8JNL6WwgKgIxALA+RdYb0qDxhcdtt57Zu3A1 -eQZEvsJg9FGJOjYDnxZYqEpNZSgTwgcRvGH1Srt37w== ------END CERTIFICATE----- diff --git a/test/h2/config.xml b/test/h2/config.xml deleted file mode 100644 index 8a2e1ab9b9f..00000000000 --- a/test/h2/config.xml +++ /dev/null @@ -1,186 +0,0 @@ - - - basic - - - - - - - 1 - - 3600 - - basic - - 8 - 0 - 0 - random - false - 0 - 0 - -1 - false - false - false - 25 - .stfolder - false - 0 - 8 - false - standard - standard - false - true - false - false - false - false - - 0 - 0 - - - -
tcp://127.0.0.1:22001
-
quic://127.0.0.1:22001
- false - false - 0 - 0 - 0 - false - 0 - 3 -
- -
tcp://127.0.0.1:22002
- false - false - 0 - 0 - 0 - false - 0 - 3 -
- -
127.0.0.1:8082
- abc123 - default -
- - - tcp://127.0.0.1:22002 - quic://127.0.0.1:22002 - default - false - true - 21027 - [ff12::8384]:21027 - 0 - 0 - 5 - true - 10 - false - true - 0 - 1 - 10 - 3 - 2 - x7AWqz5k - https://data.syncthing.net/newdata - false - 1800 - 12 - false - 24 - false - 5 - true - 1 - https://upgrades.syncthing.net/meta.json - false - 10 - 0 - true - 0 - https://crash.syncthing.net/newcrash - true - 180 - 20 - default - auto - 0 - true - false - 0 - 0 - false - 10 - 20 - 30 - 40 - 50 - 0 - - - - basic - - - - 1 - - 3600 - - basic - - 0 - 0 - 0 - random - false - 0 - 0 - 10 - false - false - false - 25 - .stfolder - false - 0 - 2 - false - standard - standard - false - false - false - false - false - false - - 1024 - 4096 - - - -
dynamic
- false - false - 0 - 0 - 0 - false - 0 - 3 -
- -
-
diff --git a/test/h2/https-cert.pem b/test/h2/https-cert.pem deleted file mode 100644 index ad8b99adc3c..00000000000 --- a/test/h2/https-cert.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC3zCCAcegAwIBAgIILrHT86p9vYAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UE -AxMEc3lubzAeFw0xNTExMjcwODA1NTNaFw00OTEyMzEyMzU5NTlaMA8xDTALBgNV -BAMTBHN5bm8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdxcS30eEu -D8fKokMseLzBJSXvXL0HI6f33ALG7cLi9cXZBurW7Q+bsrHeq6RiZx8PWT5aUkr6 -NI3tp3pSip0psJ6PROnmEN5g1rcT/0sQ2oRc5EEiA6jnS2kHgA3vSgaPvtXPqXow -ZD3J/h4IONVIqoxASMNu9rWHjy0CFKXHKBs4pyygysEaj+fL3fuCdvigdkcs5mro -z9O7QRWj6WWrmRfn0pcavN8fU/1TmisLqyxiheRY5WWelnJ3mdAC4dlj2dIj6oHw -QuUnzB4TCenLsD1i0MZzSi8tSVzx0ajra0zyslDfEbdd1HBQweP45R2rUWet2GnL -MfOyfe5GWwWNAgMBAAGjPzA9MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggr -BgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOC -AQEAbOVQB4fKIKVtiGi3SSHzdkG5T4p+1FGdSGCl/HjnpPRJ7Q4ZV4n7c7wXm6ya -Lg9lryJCRjK+gH2jIT16x8XqwUOxnlJEfqF85qqAm9h1Kf40wuCAdt72WjypCvZf -dzdgQT5wZ21A0lMltThf2dREcpD8+meh5qv3GNBOZpz2+OYiKnLlWi1Wh9MCwRNr -M+3amX7sJKnb+/xslx29fPzPpq/uypZKHFNG142fNG6wW3aKHELNA0szlSQGwWfe -0Aw1k6RrKz45iZPQ9HbRB3bF7t/gJVeN+uo484NZQG7cnej4zXEooL6W5jfo/ECr -vqe+Ym0B+xIRsfn0FApfVUqZkA== ------END CERTIFICATE----- diff --git a/test/h2/https-key.pem b/test/h2/https-key.pem deleted file mode 100644 index fd691d55997..00000000000 --- a/test/h2/https-key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEA3cXEt9HhLg/HyqJDLHi8wSUl71y9ByOn99wCxu3C4vXF2Qbq -1u0Pm7Kx3qukYmcfD1k+WlJK+jSN7ad6UoqdKbCej0Tp5hDeYNa3E/9LENqEXORB -IgOo50tpB4AN70oGj77Vz6l6MGQ9yf4eCDjVSKqMQEjDbva1h48tAhSlxygbOKcs -oMrBGo/ny937gnb4oHZHLOZq6M/Tu0EVo+llq5kX59KXGrzfH1P9U5orC6ssYoXk -WOVlnpZyd5nQAuHZY9nSI+qB8ELlJ8weEwnpy7A9YtDGc0ovLUlc8dGo62tM8rJQ -3xG3XdRwUMHj+OUdq1FnrdhpyzHzsn3uRlsFjQIDAQABAoIBAG8AxWUIrUAj7+mx -7BN/X2MBmApGDetb4oACZHVznn+BawUlHDh1scFJ4RPGL+J9ISPKlJYa6KJx2bRh -hq136hBq8gJeCQD54oTwE/TzbHxEE8p3CU7gLBORQEHby53BHKWobFajyqAcHH1V -L20IHWFg1BB9Gy0YWWY/uNR4xz12G6NIRjwQSGKv9Qgxz7VwE7jn0BbYE3GzaCgb -x/CqJ5ED8ZGLK7BWLgnld6qYwRX7TExRLzyzEJ8WhjxavuO83dxKSgr4OgowuRqh -hgubcLcjdsvdjae+93wdXBvkKNX7GL6ksCViylQ6fZ1WesGuQBK9FWnDodaAgjdX -r0+KOqECgYEA389RP5PhYpnp0aZcFbfIwyI79VjsvZvHbpllRjJ5GSXfe4ceI0uz -6KVIUflrvEJxJhCustLYcGtU4VY5aanENDqN5/UBkUsBvocZwyf25mL8cGMSQ8h7 -huMbCgZFVwMHLa979d3QHJpUhk4AipKqKEX5GP3o6YaC3Mgr6VzI9lUCgYEA/atw -BuEsS031Qw7sYt37XBO2X+rPGl2oJbwpvglOlUd9m53wOv+N9Vwy0YWdtv4C0tqu -z3UY/US+flLC7urOS6l0kmZlOqQv6sBccQ7CSNaPZxT0Av8eXAjefk0vFfKBfcfj -Niku0HjGtPeaNemdBRMUfO2YjNb6ZONMIzbV2lkCgYBnq2tyLLjI6IxzLUEYWkIn -iTMGycMXbRIq++j6ZCTN7kofuQ3PwaA7Ulw2hHdQA+LPhAi4EoxpPn5ZxovfkuCs -ZLcYy9eHCpxrOb9IM7ndK9rM4Ec0mKgHaik7Mn5p+KAZnGCqGa3todsnPvhnN9qT -vx3MYsjBayowxJP6i50W5QKBgCu1CkxlJ9ihygyP2bL/RHwM+XN1ZdHJKVu3HAoe -WGfoNYBGqknAFpmcFTV8rDwHcD0caNpd9rxMx/XEFMpNstXekLNY6UA9YfQ0yLjC -Lj+WmIbOWWzawERjUtK4QdCqRB2D/2YpmmNZLAOqVevMIL3rF7Cez5YUxHf1ofy/ -SgGhAoGAaBDS2pwAxCGDa04drmC9CkqHuN3k4nyIFDdWDPHnbetWiG60XlRTMGrk -sirWOQkp0sxiKx7e+E0Gvh13PbU3SUQ+ymOTEblUK+plYwMKTbHRS9XZQJEB4Om4 -3y82RmIaP9TvfSsn0UZEKozHThnijSPa8BFJbkKK8lxT0sOFK3Y= ------END RSA PRIVATE KEY----- diff --git a/test/h2/key.pem b/test/h2/key.pem deleted file mode 100644 index 55010937f3a..00000000000 --- a/test/h2/key.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MIGkAgEBBDBz4/RQhZfObYcjS4t5bZthw0Pj6YliqI357mdB6hfiQgMdTB8v7jnO -Scbil+Rri0+gBwYFK4EEACKhZANiAATuIjYTl60Cznfqz5JRXccpl4rnmIdRjpfg -8d4+PK83E4Jnoa9sSs5daq6ZTj6/NVERbXC820ZcC2/P+Gwcg8nsR0ohfRA8BOaz -Y2mUJtoWVTEcGlTOGU26WGyhXlqOfvI= ------END EC PRIVATE KEY----- diff --git a/test/h3/cert.pem b/test/h3/cert.pem deleted file mode 100644 index 0c5094f2aca..00000000000 --- a/test/h3/cert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID3jCCAkigAwIBAgIBADALBgkqhkiG9w0BAQUwFDESMBAGA1UEAxMJc3luY3Ro -aW5nMB4XDTE0MDMxNDA3MDExMVoXDTQ5MTIzMTIzNTk1OVowFDESMBAGA1UEAxMJ -c3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAypziXAfA -GG5mEwTIo+dUt3a4SxKnCVWfTXq7RF5ukCdz3jRRRoqy2ujbW5oe7qmqELTUzkJU -eJkuCyvLIhVsKgt2r1peThy5+3/kUst9Faitnke1/jYtWwSf7WmK9TQBN/tFxdgR -SM0LpdvsIJQqB5eodR51KrsjkJcKzEHeE2IQA8EKD1LcfXz8p22zdaZ4CNhz7mgF -ghkRT6NINDZiMtm6R4qXqYyW1MNlYLw+DqXvE2eCQMQOcqI7SSZTeS3eSTP5NQum -AmaLKn3JZQ9G6Ldn0VSWSPlXqVSaFTI9LnYICTDa4Nj4+L6idwzjmBkxPr8vBjlj -15eo6xcU4fKqh2/xHIcZYpas1bwo5ljGdcfRm4L1zpxDY+nJFIgRv0Ndpltve+T8 -o3qiqFvIMiphFUtdb2pzgaTi8FW9SHMRFiuj6sNLI0Yb9u8BoN/QsWZnFh6fQoHW -PKtkJrPZGw4GMMTHeEQe/eLW9VAH7ywPyc2hSzSri44aR44s4ErSV+XfAgMBAAGj -PzA9MA4GA1UdDwEB/wQEAwIAoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH -AwIwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQUDggGBAJshUcNfAveVE115S/NQ -h+HfqahB3Gw69KmSWgFNXAEyXwOftmz9p2gL6DwfbU1SkbakU/YLJ3/mP4Q69EmX -axzr108hUJ2qxH091IfKPCuTDtLsFY7g0PI+SBzADFSkoFe79aF/PSjaZk6fjvEl -44PXzhxqqnSS+9lXQk+DIS6/jSVuX1XYvkkdHRXd9d7nw42sONDdSX8oQAUvGOeR -CBleWB4AqS6HH2zFVIzRvjDsSg2wUXQjcqMqef7zBMpuWKTIQf+uaXWsEuPK2a3V -IPwreWGwkxqGTToLagqOdAhgN+owvTJS9PaqxFqlxp8ypIYBnZ5VL5G5p115C17/ -xVENRxX0/oB99L5HGRhAuIGE4LhXq858DzmTZFcwm3fHragPKS/MMI71Z6U5RH2p -VouosWzxAEx3Piq+ccenPLt6VPO5iFn+ppoBfwAFtNKyTrXcTQm33oJWFz+NSMAl -vCq5H4c9x5CoWDpX2bdjpnZ3xcSj84fPYpkKBI52eZAvcw== ------END CERTIFICATE----- diff --git a/test/h3/config.xml b/test/h3/config.xml deleted file mode 100644 index ac99d810274..00000000000 --- a/test/h3/config.xml +++ /dev/null @@ -1,142 +0,0 @@ - - - basic - - - - 1 - - - 3600 - - 1 - 0 - 0 - random - false - 0 - 0 - -1 - false - false - false - 25 - .stfolder - false - 0 - 0 - false - standard - standard - false - true - - - basic - - - 1 - - 3600 - - 1 - 0 - 0 - random - false - 0 - 0 - -1 - false - false - false - 25 - .stfolder - false - 0 - 0 - false - standard - standard - false - true - - -
tcp://127.0.0.1:22001
- false - false - 0 - 0 - 0 -
- -
tcp://127.0.0.1:22002
- false - false - 0 - 0 - 0 -
- -
tcp://127.0.0.1:22003
- false - false - 0 - 0 - 0 -
- -
127.0.0.1:8083
- abc123 - default -
- - - dynamic+https://relays.syncthing.net/endpoint - tcp://127.0.0.1:22003 - default - false - false - 21027 - [ff12::8384]:21027 - 0 - 0 - 5 - true - 10 - false - false - 0 - 30 - 10 - 3 - 2 - UL4yowgK - https://data.syncthing.net/newdata - false - 1800 - true - 12 - false - 24 - false - 5 - false - 1 - https://upgrades.syncthing.net/meta.json - false - 10 - 0 - ~ - true - 0 - https://crash.syncthing.net/newcrash - true - 180 - 20 - default - auto - 0 - true - -
diff --git a/test/h3/https-cert.pem b/test/h3/https-cert.pem deleted file mode 100644 index b14d69bcbd3..00000000000 --- a/test/h3/https-cert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID5TCCAk+gAwIBAgIIdbrEV5+jpE0wCwYJKoZIhvcNAQELMBQxEjAQBgNVBAMT -CXN5bmN0aGluZzAeFw0xNDA5MTQyMjI0MDdaFw00OTEyMzEyMzU5NTlaMBQxEjAQ -BgNVBAMTCXN5bmN0aGluZzCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGB -ALEhr4uC9J4vwDSXQCviKfJBln+LhQhHn8xBEi4xqedmYbXkesIZfCBf6t7DIgdN -whPkcJb74tbiMqEyEIVFHRbdlyFRaDLfvCoV3f7OU36EoChDsAQ+LCHza39pWcsq -uGXBk6xsuMAgPubPr4tYbUW+bgrC5owK1Ny1341TOwcxpXw3XzaRNqwMgKVPUfB4 -jfr9vf59OgQb+kElWyVMCbuHHEGVLYUmIa1tjFOul6HgUEfbTKvyjeXkJKKMnMXX -rERdp3kq/nIkKzhpqu0X6L6vnG4vQ+7hvs5NIhyjSgMVXr7dMlxWYoIEbGyR9ZXD -Yr3vL/3EAoTOA0OuBV5OHHb+wQGK8eeiKzlheXF7nAeIpitH7/sih3I7Yk+bdsGY -HlWkOkGt1xQh/d9BDCm3+MPhIZRlF/m1QYha8ofLIbk8vLpJZSpY/2q8qV7xCKKd -0b4E/x+ee7KDdBxsH4XzqZAMW/9zFQEu8VxQSPp2Wfwda+gKmWB3XzRrNdyqbtcg -zQIDAQABoz8wPTAOBgNVHQ8BAf8EBAMCAKAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG -CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCwYJKoZIhvcNAQELA4IBgQBHlkaRKtXm -pb882RdvFMXLuChuqhDjf8cciWaqaN7N0f3u9JetO+3MGOLsSrv5EBVNFYVqGzwc -otapi3w3CJ1Cu/bRSl88A1TlLIzjet6R6/gbcRmshW7KgZa2yfeDiIOZw4O5SQvX -SFvJNqViotMj3XgAE8iNo2pyEkQk4l/HHEf8/ALYSlU9O4SVr7kw0udoZOIrlx2a -EvQXsXf/kJDeBJ2TNDZ0p4gow8kacsxmKt/uoKDBGiRyUdeC9Au0qa2LNgc9yO0z -dzaBTpDT5kuuFBjul7GFsqvSoQx+DXcvj1URBsaGMKUHJXpdbSpIBmiWv+tdSdw5 -qipizzSBMpKOofCtkPn7eCGumCp0oxk1EHMAyMD0eLFy+v+rEBBpld40J0CB28MT -6r5rUkH77aKRXSLeO0hGRuiuKPtJLG+P9n8/q4SwZZ42LF3XpeE35l8noG7KFnXl -lkbbdLZR5FaFwRbosB07LE9UkjYrWokHw4PGab1H/pkcYazBhXDREVU= ------END CERTIFICATE----- diff --git a/test/h3/https-key.pem b/test/h3/https-key.pem deleted file mode 100644 index 59b11aad5f3..00000000000 --- a/test/h3/https-key.pem +++ /dev/null @@ -1,39 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/test/h3/key.pem b/test/h3/key.pem deleted file mode 100644 index f09af8508e1..00000000000 --- a/test/h3/key.pem +++ /dev/null @@ -1,39 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/test/h4/cert.pem b/test/h4/cert.pem deleted file mode 100644 index d329435cbd0..00000000000 --- a/test/h4/cert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID6TCCAlGgAwIBAgIISz5XufRr9xMwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UE -AxMJc3luY3RoaW5nMB4XDTE1MDcyMjA3MDIzOFoXDTQ5MTIzMTIzNTk1OVowFDES -MBAGA1UEAxMJc3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC -AYEA4nE2FPVQkfMStJms0SUEjSi5qUC4I2+aCFD+q6rLJHhgzdvjXoQ8iWX8hFLu -nza3mMKTSjcThnpR/yA1S0ipATsdQ5c5xjceliSLDxImBcBaMtvGejgOlFwC6zTz -5CJAnLo8odQtAgaaUtGJU145OAHM/cTA0xKd+nh0UvuJHT56Ur6dZ/VKzONnWsUW -qI/YVp7mRvv1PimN74ppTQSadU1s3gyq3b7mnl/aWjN42/G6kO27NXA1lVblnFk/ -Cee6HFxUIy5upTFXnAm1DaEFVdzQ1dxBAEXwIbh2WOXeVCyDONzaqVcYPYQKG5NT -KbYY08rnDmRFlURHFQ/eEr49zniLrQRfL3pSNCEGmuVpPAEsuGQ5EQW1b8aEFMgp -IR+Jo59JyU04HrP27VctyUEBT4MCQn4G9gN6Qy1EKTKq49UVNR+1eMtuq9/o6tXl -rwepnO9AITclPdpvGc93hTshEBZFQF+rHkUMoj7jXr9zAGchRoY8cxaJM0DGrpjc -uGONAgMBAAGjPzA9MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD -AQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAYEAgiC2 -LYPXPCtuaF7qGbas0A5zYtPr0PrXaILl4uYA63+ZXKPMOQ+LkdgRzSQxvKLrPLQM -/LwWOTONuqT2sw8Wj+MilzDOXIlEWG2Gqy3/xS7H5RAkZqjVHhuBRXnJiZEl5HAh -ASMGiyejII2uN7k+5sjCFmuSfdcI18f/AjUL5fz53TpIJinyCakQipdicI9jZvLR -jJ2sqy9wJ3yhTtUm5M33bsLPjhnwMkTTYvvMomfRI8qUYflWxb5BZ82FvNVUE9kA -hDdJzluINMofMAblyf9TxX0q1bunPc9soAMtUSDWRmNtviV9uggEdtGYrmDrK7Dz -+89AB60QSN6MJzVNPdJZCPvefuJjk9isQBUbQE/CsVFeooKJ/DU5arbUV2mjaifV -Z6GxHiEkynSWaNMQLioi+vPguMdAuotdqpInVjCLKJbKiOXrYfIhYJFATc0lRBHx -9LUH020HOACgX+WVFiDEDx7OCu868IbDJK/gryb5IfIpbaY4xit9eoqMS4BP ------END CERTIFICATE----- diff --git a/test/h4/config.xml b/test/h4/config.xml deleted file mode 100644 index d0627cd9159..00000000000 --- a/test/h4/config.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - basic - - 1 - - 3600 - - 1 - 2048 - 0 - random - false - 0 - 0 - -1 - false - false - false - 25 - .stfolder - false - 0 - 0 - false - standard - standard - false - true - - -
dynamic
- false - false - 0 - 0 - 0 -
- -
127.0.0.1:8084
- PMA5yUTG-Mw98nJ0YEtWTCHlM5O4aNi0 - default -
- - - dynamic+https://relays.syncthing.net/endpoint - tcp://127.0.0.1:22004 - default - false - false - 21027 - [ff12::8384]:21027 - 0 - 0 - 60 - true - 10 - false - false - 60 - 30 - 10 - 3 - 2 - vF5srHmT - https://data.syncthing.net/newdata - false - 1800 - true - 12 - false - 24 - false - 5 - false - 1 - https://upgrades.syncthing.net/meta.json - false - 10 - 0 - ~ - true - 0 - https://crash.syncthing.net/newcrash - true - 180 - 20 - default - auto - 0 - true - -
diff --git a/test/h4/https-cert.pem b/test/h4/https-cert.pem deleted file mode 100644 index e767708eb89..00000000000 --- a/test/h4/https-cert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID3zCCAkegAwIBAgIIWH6f9/hiHaowDQYJKoZIhvcNAQELBQAwDzENMAsGA1UE -AxMEc3lubzAeFw0xNTA3MjIwNzE1MjlaFw00OTEyMzEyMzU5NTlaMA8xDTALBgNV -BAMTBHN5bm8wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCgideynuoI -MfN2PR7WfPWvRjnYNuNp5U1C5GzAfrKxVaHkfpt+AsXHHsuo1Xl3gdsIs1Uc2Z8R -yLPxFgT+bLKKqwTw4D/9JTHtF2vOLkZLB4/0Bhe2BAXepEEIZDqEHsNE7A8ma9Jv -JlBxW55xoXUE5ak2tNvxQneoDj+WKpd24jyZBMp/TC52dhy6TmDfahrQjU29Nz7n -tlVC1eol7YqB7+M1CXK2OK74m9J9G8tnweDKJKPv9t011dIhyd2GqRI36fU1EuIC -+NSWhcl1VGEa3eCN9Bn+pUo5oDSiMfGmbVo77al31wpN+2+BprH/JTWSWtvBG6uh -Cyq5cqkDxMeXmCD863+xorE0hyqZkRrS2XSaJI7hhOgVCUUrfPMK3p9n1pkZ+RfN -AtYFPhit2bJyjSBJNN0qxnmMHspZFO+eoeNQkaeL7sDeHLo2ZEUIJMyq4ElsimLU -i/+bQCaHl4vz/rz8nRNnIsm4o2adgLie3ZA2lJ+5vEBN+1GlaHIrEnUCAwEAAaM/ -MD0wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD -AjAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBgQBsbVHPEvzX2Emas+yG -zbKa1wcuxNWn7nmYjz8YXuFURjGAt1U8wPV+YhgZrhR1rImwGRkXjRwL3vCvm5xi -aTNNK2g132amMKhWcAwm/bXJsW3smFpUmmb6j1jZj2eQo3UFNpEql+GzHF/iLWgA -74xsqRkqTR/tkoD/W47ASn92rlj8vKmVafiq132/YlqxzaJB4FQyfmdHd1HMsStk -r531DXSBsK9CBnM/oEkoCBsJFi6xiUNf7D7wjvoVnCcrIx4bNXiMKgbZA/M0mh9t -bDI5b+2j1Af7npPzHAEYEWbWSGwpDBnpB9PuG11WjozLpwDA2My5yjiwHQYw3cIV -QM17Oia97QjgOLbbG5Hpy6SF0KxUyCINpg780U7WKyVLherpdQ1ABRmlC0laXDh5 -Oq500d316ej28VITWj3gMhocw4KwXpkjh9cweLTPV7wiUsoO2ksEMjEPdGCjzHXg -k7KQB7dqbOS7VIOJj8+GPbaf3aTdG+b1z3KVcDMH+59TddE= ------END CERTIFICATE----- diff --git a/test/h4/https-key.pem b/test/h4/https-key.pem deleted file mode 100644 index 977d43a0cd9..00000000000 --- a/test/h4/https-key.pem +++ /dev/null @@ -1,39 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/test/h4/key.pem b/test/h4/key.pem deleted file mode 100644 index 9b2be1337f2..00000000000 --- a/test/h4/key.pem +++ /dev/null @@ -1,39 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/test/http_test.go b/test/http_test.go deleted file mode 100644 index 3dd9cf75196..00000000000 --- a/test/http_test.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "bytes" - "io" - "net/http" - "os" - "strings" - "testing" - - "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/rc" -) - -func TestHTTPGetIndex(t *testing.T) { - p := startInstance(t, 2) - defer checkedStop(t, p) - - // Check for explicit index.html - - res, err := http.Get("http://localhost:8082/index.html") - if err != nil { - t.Fatal(err) - } - if res.StatusCode != 200 { - t.Errorf("Status %d != 200", res.StatusCode) - } - bs, err := io.ReadAll(res.Body) - if err != nil { - t.Fatal(err) - } - if len(bs) < 1024 { - t.Errorf("Length %d < 1024", len(bs)) - } - if !bytes.Contains(bs, []byte("")) { - t.Error("Incorrect response") - } - if res.Header.Get("Set-Cookie") == "" { - t.Error("No set-cookie header") - } - res.Body.Close() - - // Check for implicit index.html - - res, err = http.Get("http://localhost:8082/") - if err != nil { - t.Fatal(err) - } - if res.StatusCode != 200 { - t.Errorf("Status %d != 200", res.StatusCode) - } - bs, err = io.ReadAll(res.Body) - if err != nil { - t.Fatal(err) - } - if len(bs) < 1024 { - t.Errorf("Length %d < 1024", len(bs)) - } - if !bytes.Contains(bs, []byte("")) { - t.Error("Incorrect response") - } - if res.Header.Get("Set-Cookie") == "" { - t.Error("No set-cookie header") - } - res.Body.Close() -} - -func TestHTTPGetIndexAuth(t *testing.T) { - p := startInstance(t, 1) - defer checkedStop(t, p) - - // Without auth should give 401 - - res, err := http.Get("http://127.0.0.1:8081/") - if err != nil { - t.Fatal(err) - } - res.Body.Close() - if res.StatusCode != 401 { - t.Errorf("Status %d != 401", res.StatusCode) - } - - // With wrong username/password should give 401 - - req, err := http.NewRequest("GET", "http://127.0.0.1:8081/", nil) - if err != nil { - t.Fatal(err) - } - req.SetBasicAuth("testuser", "wrongpass") - - res, err = http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - res.Body.Close() - if res.StatusCode != 401 { - t.Fatalf("Status %d != 401", res.StatusCode) - } - - // With correct username/password should succeed - - req, err = http.NewRequest("GET", "http://127.0.0.1:8081/", nil) - if err != nil { - t.Fatal(err) - } - req.SetBasicAuth("testuser", "testpass") - - res, err = http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - res.Body.Close() - if res.StatusCode != 200 { - t.Fatalf("Status %d != 200", res.StatusCode) - } -} - -func TestHTTPOptions(t *testing.T) { - p := startInstance(t, 2) - defer checkedStop(t, p) - - req, err := http.NewRequest("OPTIONS", "http://127.0.0.1:8082/rest/system/error/clear", nil) - if err != nil { - t.Fatal(err) - } - res, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - res.Body.Close() - if res.StatusCode != 204 { - t.Fatalf("Status %d != 204 for OPTIONS", res.StatusCode) - } -} - -func TestHTTPPOSTWithoutCSRF(t *testing.T) { - p := startInstance(t, 2) - defer checkedStop(t, p) - - // Should fail without CSRF - - req, err := http.NewRequest("POST", "http://127.0.0.1:8082/rest/system/error/clear", nil) - if err != nil { - t.Fatal(err) - } - res, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - res.Body.Close() - if res.StatusCode != 403 { - t.Fatalf("Status %d != 403 for POST", res.StatusCode) - } - - // Get CSRF - - req, err = http.NewRequest("GET", "http://127.0.0.1:8082/", nil) - if err != nil { - t.Fatal(err) - } - res, err = http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - res.Body.Close() - hdr := res.Header.Get("Set-Cookie") - id := res.Header.Get("X-Syncthing-ID")[:protocol.ShortIDStringLength] - if !strings.Contains(hdr, "CSRF-Token") { - t.Error("Missing CSRF-Token in", hdr) - } - - // Should succeed with CSRF - - req, err = http.NewRequest("POST", "http://127.0.0.1:8082/rest/system/error/clear", nil) - if err != nil { - t.Fatal(err) - } - - req.Header.Set("X-CSRF-Token-"+id, hdr[len("CSRF-Token-"+id+"="):]) - res, err = http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - res.Body.Close() - if res.StatusCode != 200 { - t.Fatalf("Status %d != 200 for POST", res.StatusCode) - } - - // Should fail with incorrect CSRF - - req, err = http.NewRequest("POST", "http://127.0.0.1:8082/rest/system/error/clear", nil) - if err != nil { - t.Fatal(err) - } - req.Header.Set("X-CSRF-Token-"+id, hdr[len("CSRF-Token-"+id+"="):]+"X") - res, err = http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - res.Body.Close() - if res.StatusCode != 403 { - t.Fatalf("Status %d != 403 for POST", res.StatusCode) - } -} - -func setupAPIBench() *rc.Process { - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - panic(err) - } - - err = generateFiles("s1", 25000, 20, "../LICENSE") - if err != nil { - panic(err) - } - - err = os.WriteFile("s1/knownfile", []byte("somedatahere"), 0644) - if err != nil { - panic(err) - } - - // This will panic if there is an actual failure to start, when we try to - // call nil.Fatal(...) - return startInstance(nil, 1) -} - -func benchmarkURL(b *testing.B, url string) { - p := setupAPIBench() - defer p.Stop() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := p.Get(url) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkAPI_db_completion(b *testing.B) { - benchmarkURL(b, "/rest/db/completion?folder=default&device="+protocol.LocalDeviceID.String()) -} - -func BenchmarkAPI_db_file(b *testing.B) { - benchmarkURL(b, "/rest/db/file?folder=default&file=knownfile") -} - -func BenchmarkAPI_db_ignores(b *testing.B) { - benchmarkURL(b, "/rest/db/ignores?folder=default") -} - -func BenchmarkAPI_db_need(b *testing.B) { - benchmarkURL(b, "/rest/db/need?folder=default") -} - -func BenchmarkAPI_db_status(b *testing.B) { - benchmarkURL(b, "/rest/db/status?folder=default") -} - -func BenchmarkAPI_db_browse_dirsonly(b *testing.B) { - benchmarkURL(b, "/rest/db/browse?folder=default&dirsonly=true") -} diff --git a/test/ignore_test.go b/test/ignore_test.go deleted file mode 100644 index abc2faab419..00000000000 --- a/test/ignore_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "log" - "os" - "path/filepath" - "testing" - "time" -) - -func TestIgnores(t *testing.T) { - // Clean and start a syncthing instance - - log.Println("Cleaning...") - err := removeAll("s1", "h1/index*") - if err != nil { - t.Fatal(err) - } - - p := startInstance(t, 1) - defer checkedStop(t, p) - - // Create eight empty files and directories - - dirs := []string{"d1", "d2", "d3", "d4", "d11", "d12", "d13", "d14"} - files := []string{"f1", "f2", "f3", "f4", "f11", "f12", "f13", "f14", "d1/f1.TXT"} - - for _, dir := range dirs { - err := os.Mkdir(filepath.Join("s1", dir), 0755) - if err != nil { - t.Fatal(err) - } - } - - for _, file := range files { - fd, err := os.Create(filepath.Join("s1", file)) - if err != nil { - t.Fatal(err) - } - fd.Close() - } - - // Rescan and verify that we see them all - - if err := p.Rescan("default"); err != nil { - t.Fatal(err) - } - - m, err := p.Model("default") - if err != nil { - t.Fatal(err) - } - expected := len(files) // nothing is ignored - if m.LocalFiles != expected { - t.Fatalf("Incorrect number of files after initial scan, %d != %d", m.LocalFiles, expected) - } - - // Add some of them to an ignore file - - err = os.WriteFile("s1/.stignore", - []byte("f1*\nf2\nd1*\nd2\ns1*\ns2\n(?i)*.txt"), // [fds][34] only non-ignored items - 0644) - if err != nil { - t.Fatal(err) - } - - // Rescan and verify that we see them - - if err := p.Rescan("default"); err != nil { - t.Fatal(err) - } - - m, err = p.Model("default") - if err != nil { - t.Fatal(err) - } - expected = len(files) * 2 / 8 // two out of eight items should remain - if m.LocalFiles != expected { - t.Fatalf("Incorrect number of files after first ignore, %d != %d", m.LocalFiles, expected) - } - - // Change the pattern to include some of the files and dirs previously ignored - - time.Sleep(1100 * time.Millisecond) - err = os.WriteFile("s1/.stignore", []byte("f2\nd2\ns2\n"), 0644) - - // Rescan and verify that we see them - - if err := p.Rescan("default"); err != nil { - t.Fatal(err) - } - - m, err = p.Model("default") - if err != nil { - t.Fatal(err) - } - expected = len(files)*7/8 + 1 // seven out of eight items should remain, plus the foo.TXT - if m.LocalFiles != expected { - t.Fatalf("Incorrect number of files after second ignore, %d != %d", m.LocalFiles, expected) - } -} diff --git a/test/instance_util.go b/test/instance_util.go new file mode 100644 index 00000000000..d80b2682fbb --- /dev/null +++ b/test/instance_util.go @@ -0,0 +1,144 @@ +// Copyright (C) 2023 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 integration + +import ( + "bufio" + "bytes" + "io" + "net" + "os/exec" + "regexp" + "testing" + "time" + + "github.com/syncthing/syncthing/lib/protocol" + "github.com/syncthing/syncthing/lib/rand" +) + +const syncthingBinary = "../bin/syncthing" + +// instance represents a running instance of Syncthing. +type instance struct { + deviceID protocol.DeviceID + syncthingDir string + userHomeDir string + apiAddress string + apiKey string + tcpPort int +} + +// startInstance starts a Syncthing instance with authentication. The +// username, password and API key are in the returned instance. +func startInstance(t *testing.T) *instance { + t.Helper() + + // Use temporary directories for the Syncthing and user home + // directories. The user home directory won't be used for anything, but + // it needs to exist... + syncthingDir := t.TempDir() + userHomeDir := t.TempDir() + + inst := &instance{ + syncthingDir: syncthingDir, + userHomeDir: userHomeDir, + apiKey: rand.String(32), + } + + // Start Syncthing with the config and API key. + cmd := exec.Command(syncthingBinary, "--no-browser", "--no-default-folder", "--home", syncthingDir) + cmd.Env = append(basicEnv(userHomeDir), "STGUIAPIKEY="+inst.apiKey) + rd, wr := io.Pipe() + cmd.Stdout = wr + cmd.Stderr = wr + lr := newSyncthingMetadataReader(rd) + + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + + t.Cleanup(func() { + cmd.Process.Kill() + cmd.Wait() + }) + + // Wait up to 30 seconds to get the device ID, which comes first. + select { + case inst.deviceID = <-lr.myIDCh: + case <-time.After(30 * time.Second): + t.Log(lr.log) + t.Fatal("timeout waiting for device ID") + } + + // Once we have that, the sync listeners & API should be up and running + // quickly. Give it another few seconds. + select { + case inst.apiAddress = <-lr.apiAddrCh: + case <-time.After(5 * time.Second): + t.Log(lr.log) + t.Fatal("timeout waiting for API address") + } + select { + case inst.tcpPort = <-lr.tcpPortCh: + case <-time.After(5 * time.Second): + t.Log(lr.log) + t.Fatal("timeout waiting for listen address") + } + + return inst +} + +func basicEnv(userHomeDir string) []string { + return []string{"HOME=" + userHomeDir, "userprofile=" + userHomeDir, "STNOUPGRADE=1", "STNORESTART=1", "STMONITORED=1", "STGUIADDRESS=127.0.0.1:0"} +} + +// syncthingMetadataReader reads the output of a Syncthing process and +// extracts the listen address and device ID. The results are in the channel +// fields, which can be read once. +type syncthingMetadataReader struct { + log *bytes.Buffer + apiAddrCh chan string + myIDCh chan protocol.DeviceID + tcpPortCh chan int +} + +func newSyncthingMetadataReader(r io.Reader) *syncthingMetadataReader { + sc := bufio.NewScanner(r) + lr := &syncthingMetadataReader{ + log: new(bytes.Buffer), + apiAddrCh: make(chan string, 1), + myIDCh: make(chan protocol.DeviceID, 1), + tcpPortCh: make(chan int, 1), + } + addrExp := regexp.MustCompile(`GUI and API listening on ([^\s]+)`) + myIDExp := regexp.MustCompile(`My ID: ([^\s]+)`) + tcpAddrExp := regexp.MustCompile(`TCP listener \((.+)\) starting`) + go func() { + for sc.Scan() { + line := sc.Text() + lr.log.WriteString(line + "\n") + if m := addrExp.FindStringSubmatch(line); len(m) == 2 { + lr.apiAddrCh <- m[1] + } + if m := myIDExp.FindStringSubmatch(line); len(m) == 2 { + id, err := protocol.DeviceIDFromString(m[1]) + if err != nil { + panic(err) + } + lr.myIDCh <- id + } + if m := tcpAddrExp.FindStringSubmatch(line); len(m) == 2 { + addr, err := net.ResolveTCPAddr("tcp", m[1]) + if err != nil { + panic(err) + } + lr.tcpPortCh <- addr.Port + } + } + }() + return lr +} diff --git a/test/logs/.gitignore b/test/logs/.gitignore deleted file mode 100644 index f47cb2045f1..00000000000 --- a/test/logs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.out diff --git a/test/manypeers_test.go b/test/manypeers_test.go deleted file mode 100644 index 0e65f81f099..00000000000 --- a/test/manypeers_test.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "bytes" - "encoding/json" - "log" - "os" - "testing" - - "github.com/syncthing/syncthing/lib/config" - "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/rc" -) - -func TestManyPeers(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 200, 20, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - receiver := startInstance(t, 2) - defer checkedStop(t, receiver) - receiver.ResumeAll() - - bs, err := receiver.Get("/rest/system/config") - if err != nil { - t.Fatal(err) - } - - var cfg config.Configuration - if err := json.Unmarshal(bs, &cfg); err != nil { - t.Fatal(err) - } - - for len(cfg.Devices) < 100 { - bs := make([]byte, 16) - ReadRand(bs) - id := protocol.NewDeviceID(bs) - cfg.Devices = append(cfg.Devices, config.DeviceConfiguration{DeviceID: id}) - cfg.Folders[0].Devices = append(cfg.Folders[0].Devices, config.FolderDeviceConfiguration{DeviceID: id}) - } - - os.Rename("h2/config.xml", "h2/config.xml.orig") - defer os.Rename("h2/config.xml.orig", "h2/config.xml") - - var buf bytes.Buffer - json.NewEncoder(&buf).Encode(cfg) - _, err = receiver.Post("/rest/system/config", &buf) - if err != nil { - t.Fatal(err) - } - - sender := startInstance(t, 1) - defer checkedStop(t, sender) - sender.ResumeAll() - - rc.AwaitSync("default", sender, receiver) - - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } -} diff --git a/test/override_test.go b/test/override_test.go deleted file mode 100644 index 5851dfbe0db..00000000000 --- a/test/override_test.go +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (C) 2015 The Syncthing Authors. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. - -//go:build integration -// +build integration - -package integration - -import ( - "io" - "log" - "os" - "strings" - "testing" - "time" - - "github.com/syncthing/syncthing/lib/config" - "github.com/syncthing/syncthing/lib/events" - "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/rc" -) - -func TestOverride(t *testing.T) { - // Enable "send-only" on s1/default - id, _ := protocol.DeviceIDFromString(id1) - cfg, _, _ := config.Load("h1/config.xml", id, events.NoopLogger) - fld := cfg.Folders()["default"] - fld.Type = config.FolderTypeSendOnly - cfg.SetFolder(fld) - os.Rename("h1/config.xml", "h1/config.xml.orig") - defer os.Rename("h1/config.xml.orig", "h1/config.xml") - cfg.Save() - - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 100, 20, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - fd, err := os.Create("s1/testfile.txt") - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("hello\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - expected, err := directoryContents("s1") - if err != nil { - t.Fatal(err) - } - - sendOnly := startInstance(t, 1) - defer checkedStop(t, sendOnly) - - sendRecv := startInstance(t, 2) - defer checkedStop(t, sendRecv) - - sendOnly.ResumeAll() - sendRecv.ResumeAll() - - log.Println("Syncing...") - - rc.AwaitSync("default", sendOnly, sendRecv) - - log.Println("Verifying...") - - actual, err := directoryContents("s2") - if err != nil { - t.Fatal(err) - } - err = compareDirectoryContents(actual, expected) - if err != nil { - t.Fatal(err) - } - - log.Println("Changing file on sendRecv side...") - - fd, err = os.OpenFile("s2/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("text added to s2\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - if err := sendRecv.Rescan("default"); err != nil { - t.Fatal(err) - } - - log.Println("Waiting for index to send...") - - time.Sleep(10 * time.Second) - - log.Println("Hitting Override on sendOnly...") - - if _, err := sendOnly.Post("/rest/db/override?folder=default", nil); err != nil { - t.Fatal(err) - } - - log.Println("Syncing...") - - rc.AwaitSync("default", sendOnly, sendRecv) - - // Verify that the override worked - - fd, err = os.Open("s1/testfile.txt") - if err != nil { - t.Fatal(err) - } - bs, err := io.ReadAll(fd) - if err != nil { - t.Fatal(err) - } - fd.Close() - - if strings.Contains(string(bs), "added to s2") { - t.Error("Change should not have been synced to sendOnly") - } - - fd, err = os.Open("s2/testfile.txt") - if err != nil { - t.Fatal(err) - } - bs, err = io.ReadAll(fd) - if err != nil { - t.Fatal(err) - } - fd.Close() - - if strings.Contains(string(bs), "added to s2") { - t.Error("Change should have been overridden on sendRecv") - } -} - -/* This doesn't currently work with detection completion, as we don't actually -get to completion when in sendOnly/sendRecv mode. Needs fixing. - -func TestOverrideIgnores(t *testing.T) { - // Enable "sendOnly" on s1/default - id, _ := protocol.DeviceIDFromString(id1) - cfg, _, _ := config.Load("h1/config.xml", id, events.NoopLogger) - fld := cfg.Folders()["default"] - fld.ReadOnly = true - cfg.SetFolder(fld) - os.Rename("h1/config.xml", "h1/config.xml.orig") - defer os.Rename("h1/config.xml.orig", "h1/config.xml") - cfg.Save() - - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 10, 2, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - fd, err := os.Create("s1/testfile.txt") - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("original text\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - expected, err := directoryContents("s1") - if err != nil { - t.Fatal(err) - } - - log.Println("Starting sendOnly...") - sendOnly := syncthingProcess{ // id1 - instance: "1", - argv: []string{"--home", "h1"}, - port: 8081, - apiKey: apiKey, - } - err = sendOnly.start() - if err != nil { - t.Fatal(err) - } - defer sendOnly.stop() - - log.Println("Starting sendRecv...") - sendRecv := syncthingProcess{ // id2 - instance: "2", - argv: []string{"--home", "h2"}, - port: 8082, - apiKey: apiKey, - } - err = sendRecv.start() - if err != nil { - sendOnly.stop() - t.Fatal(err) - } - defer sendRecv.stop() - - log.Println("Syncing...") - - err = awaitCompletion("default", sendOnly, sendRecv) - if err != nil { - t.Fatal(err) - } - - log.Println("Verifying...") - - actual, err := directoryContents("s2") - if err != nil { - t.Fatal(err) - } - err = compareDirectoryContents(actual, expected) - if err != nil { - t.Fatal(err) - } - - log.Println("Ignoring testfile.txt on sendOnly...") - - fd, err = os.Create("s1/.stignore") - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("testfile.txt\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - log.Println("Modify testfile.txt on sendOnly...") - - fd, err = os.Create("s1/testfile.txt") - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("updated on sendOnly but ignored\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - fd, err = os.Create("s1/testfile2.txt") - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("sync me\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - err = sendOnly.rescan("default") - - log.Println("Waiting for sync...") - time.Sleep(10 * time.Second) - - // Verify that sync worked - - fd, err = os.Open("s2/testfile.txt") - if err != nil { - t.Fatal(err) - } - bs, err := io.ReadAll(fd) - if err != nil { - t.Fatal(err) - } - fd.Close() - - if !strings.Contains(string(bs), "original text") { - t.Error("Changes should not have been synced to sendRecv") - } - - fd, err = os.Open("s2/testfile2.txt") - if err != nil { - t.Fatal(err) - } - bs, err = io.ReadAll(fd) - if err != nil { - t.Fatal(err) - } - fd.Close() - - if !strings.Contains(string(bs), "sync me") { - t.Error("Changes should have been synced to sendRecv") - } - - log.Println("Removing file on sendRecv side...") - - os.Remove("s2/testfile.txt") - - err = sendRecv.rescan("default") - if err != nil { - t.Fatal(err) - } - - log.Println("Waiting for sync...") - time.Sleep(10 * time.Second) - - // Verify that nothing changed - - fd, err = os.Open("s1/testfile.txt") - if err != nil { - t.Fatal(err) - } - bs, err = io.ReadAll(fd) - if err != nil { - t.Fatal(err) - } - fd.Close() - - if !strings.Contains(string(bs), "updated on sendOnly but ignored") { - t.Error("Changes should not have been synced to sendOnly") - } - - fd, err = os.Open("s2/testfile.txt") - if err == nil { - t.Error("File should not exist on the sendRecv") - } - - log.Println("Creating file on sendRecv...") - - fd, err = os.Create("s2/testfile3.txt") - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("created on sendRecv, should be removed on override\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - log.Println("Hitting Override on sendOnly...") - - resp, err := sendOnly.post("/rest/db/override?folder=default", nil) - if err != nil { - t.Fatal(err) - } - if resp.StatusCode != 200 { - t.Fatal(resp.Status) - } - - log.Println("Waiting for sync...") - time.Sleep(10 * time.Second) - - fd, err = os.Open("s2/testfile.txt") - if err == nil { - t.Error("File should not exist on the sendRecv") - } - fd, err = os.Open("s2/testfile2.txt") - if err != nil { - t.Fatal(err) - } - bs, err = io.ReadAll(fd) - if err != nil { - t.Fatal(err) - } - fd.Close() - if !strings.Contains(string(bs), "sync me") { - t.Error("Changes should have been synced to sendRecv") - } - fd, err = os.Open("s2/testfile3.txt") - if err != nil { - t.Error("File should still exist on the sendRecv") - } - fd.Close() - - log.Println("Hitting Override on sendOnly (again)...") - - resp, err = sendOnly.post("/rest/db/override?folder=default", nil) - if err != nil { - t.Fatal(err) - } - if resp.StatusCode != 200 { - t.Fatal(resp.Status) - } - - log.Println("Waiting for sync...") - time.Sleep(10 * time.Second) - - fd, err = os.Open("s2/testfile.txt") - if err == nil { - t.Error("File should not exist on the sendRecv") - } - fd, err = os.Open("s2/testfile2.txt") - if err != nil { - t.Fatal(err) - } - bs, err = io.ReadAll(fd) - if err != nil { - t.Fatal(err) - } - fd.Close() - if !strings.Contains(string(bs), "sync me") { - t.Error("Changes should have been synced to sendRecv") - } - fd, err = os.Open("s2/testfile3.txt") - if err != nil { - t.Error("File should still exist on the sendRecv") - } - fd.Close() - -} -*/ diff --git a/test/parallel_scan_test.go b/test/parallel_scan_test.go deleted file mode 100644 index 13a07d5b639..00000000000 --- a/test/parallel_scan_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "log" - "os" - "sync" - "testing" - "time" -) - -func TestRescanInParallel(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "h1/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 5000, 18, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating .stignore...") - err = os.WriteFile("s1/.stignore", []byte("some ignore data\n"), 0644) - if err != nil { - t.Fatal(err) - } - - st := startInstance(t, 1) - defer checkedStop(t, st) - - var wg sync.WaitGroup - log.Println("Starting scans...") - for j := 0; j < 20; j++ { - j := j - wg.Add(1) - go func() { - defer wg.Done() - err := st.Rescan("default") - log.Println(j) - if err != nil { - log.Println(err) - t.Fatal(err) - } - }() - } - - wg.Wait() - log.Println("Scans done") - time.Sleep(2 * time.Second) - - // This is where the real test is currently, since stop() checks for data - // race output in the log. - log.Println("Stopping...") - checkedStop(t, st) -} diff --git a/test/reconnect_test.go b/test/reconnect_test.go deleted file mode 100644 index b002f084e52..00000000000 --- a/test/reconnect_test.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "log" - "testing" - "time" - - "github.com/syncthing/syncthing/lib/rc" -) - -func TestReconnectReceiverDuringTransfer(t *testing.T) { - testReconnectDuringTransfer(t, false, true) -} - -func TestReconnectSenderDuringTransfer(t *testing.T) { - testReconnectDuringTransfer(t, true, false) -} - -func testReconnectDuringTransfer(t *testing.T, restartSender, restartReceiver bool) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 250, 20, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - log.Println("Starting up...") - sender := startInstance(t, 1) - defer func() { - // We need a closure over sender, since we'll update it later to point - // at another process. - checkedStop(t, sender) - }() - - receiver := startInstance(t, 2) - defer func() { - // We need a closure over sender, since we'll update it later to - // point at another process. - checkedStop(t, receiver) - }() - - // Set rate limits - cfg, err := receiver.GetConfig() - if err != nil { - t.Fatal(err) - } - cfg.Options.MaxRecvKbps = 750 - cfg.Options.MaxSendKbps = 750 - cfg.Options.LimitBandwidthInLan = true - if err := receiver.PostConfig(cfg); err != nil { - t.Fatal(err) - } - - sender.ResumeAll() - receiver.ResumeAll() - - var prevBytes int - for { - recv, err := receiver.Model("default") - if err != nil { - t.Fatal(err) - } - - if recv.InSyncBytes > 0 && recv.InSyncBytes == recv.GlobalBytes && rc.InSync("default", receiver, sender) { - // Receiver is done - break - } else if recv.InSyncBytes > prevBytes+recv.GlobalBytes/10 { - // Receiver has made progress - prevBytes = recv.InSyncBytes - - if restartReceiver { - log.Printf("Stopping receiver...") - receiver.Stop() - receiver = startInstance(t, 2) - receiver.ResumeAll() - } - - if restartSender { - log.Printf("Stopping sender...") - sender.Stop() - sender = startInstance(t, 1) - sender.ResumeAll() - } - } - - time.Sleep(250 * time.Millisecond) - } - - // Reset rate limits - cfg, err = receiver.GetConfig() - if err != nil { - t.Fatal(err) - } - cfg.Options.MaxRecvKbps = 0 - cfg.Options.MaxSendKbps = 0 - cfg.Options.LimitBandwidthInLan = false - if err := receiver.PostConfig(cfg); err != nil { - t.Fatal(err) - } - - checkedStop(t, sender) - checkedStop(t, receiver) - - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Error(err) - } - - if err := checkRemoteInSync("default", receiver, sender); err != nil { - t.Error(err) - } -} diff --git a/test/reset_test.go b/test/reset_test.go deleted file mode 100644 index 35d471571ef..00000000000 --- a/test/reset_test.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "bytes" - "fmt" - "io" - "log" - "os" - "path/filepath" - "testing" - "time" -) - -func TestReset(t *testing.T) { - // Clean and start a syncthing instance - - log.Println("Cleaning...") - err := removeAll("s1", "h1/index*") - if err != nil { - t.Fatal(err) - } - if err := os.Mkdir("s1", 0755); err != nil { - t.Fatal(err) - } - - log.Println("Creating files...") - size := createFiles(t) - - p := startInstance(t, 1) - defer p.Stop() // Not checkedStop, because Syncthing will exit on its own - - m, err := p.Model("default") - if err != nil { - t.Fatal(err) - } - expected := size - if m.LocalFiles != expected { - t.Fatalf("Incorrect number of files after initial scan, %d != %d", m.LocalFiles, expected) - } - - // Clear all files but restore the folder marker - log.Println("Cleaning...") - err = removeAll("s1") - if err != nil { - t.Fatal(err) - } - if err := os.Mkdir("s1", 0755); err != nil { - t.Fatal(err) - } - if fd, err := os.Create("s1/.stfolder"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - - // Reset indexes of an invalid folder - log.Println("Reset invalid folder") - _, err = p.Post("/rest/system/reset?folder=invalid", nil) - if err == nil { - t.Fatalf("Cannot reset indexes of an invalid folder") - } - - // Reset indexes of the default folder - log.Println("Reset indexes of default folder") - bs, err := p.Post("/rest/system/reset?folder=default", nil) - if err != nil && err != io.ErrUnexpectedEOF { - t.Fatalf("Failed to reset indexes (default): %v (%s)", err, bytes.TrimSpace(bs)) - } - - // ---- Syncthing exits here ---- - select { - case <-p.Stopped(): - case <-time.After(20 * time.Second): - t.Fatal("timed out before Syncthing stopped") - } - - p = startInstance(t, 1) - defer p.Stop() // Not checkedStop, because Syncthing will exit on its own - - m, err = p.Model("default") - if err != nil { - t.Fatal(err) - } - expected = 0 - if m.LocalFiles != expected { - t.Fatalf("Incorrect number of files after initial scan, %d != %d", m.LocalFiles, expected) - } - - // Recreate the files and scan - log.Println("Creating files...") - size = createFiles(t) - - if err := p.Rescan("default"); err != nil { - t.Fatal(err) - } - - // Verify that we see them - m, err = p.Model("default") - if err != nil { - t.Fatal(err) - } - expected = size - if m.LocalFiles != expected { - t.Fatalf("Incorrect number of files after second creation phase, %d != %d", m.LocalFiles, expected) - } - - // Reset all indexes - log.Println("Reset DB...") - bs, err = p.Post("/rest/system/reset", nil) - if err != nil && err != io.ErrUnexpectedEOF { - t.Fatalf("Failed to reset indexes (all): %v (%s)", err, bytes.TrimSpace(bs)) - } - - // ---- Syncthing exits here ---- - select { - case <-p.Stopped(): - case <-time.After(20 * time.Second): - t.Fatal("timed out before Syncthing stopped") - } - - p = startInstance(t, 1) - defer checkedStop(t, p) - - m, err = p.Model("default") - if err != nil { - t.Fatal(err) - } - expected = size - if m.LocalFiles != expected { - t.Fatalf("Incorrect number of files after initial scan, %d != %d", m.LocalFiles, expected) - } -} - -func createFiles(t *testing.T) int { - // Create a few files - - const n = 8 - for i := 0; i < n; i++ { - file := fmt.Sprintf("f%d", i) - if err := os.WriteFile(filepath.Join("s1", file), []byte("data"), 0644); err != nil { - t.Fatal(err) - } - } - - return n -} diff --git a/test/scan_test.go b/test/scan_test.go deleted file mode 100644 index 32ad81b9fea..00000000000 --- a/test/scan_test.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "log" - "os" - "testing" - - "github.com/syncthing/syncthing/lib/rc" -) - -func TestScanSubdir(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 10, 10, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - // 1. Scan a single file in a known directory "file1.txt" - // 2. Scan a single file in an unknown directory "filetest/file1.txt" - // 3. Scan a single file in a deep unknown directory "filetest/1/2/3/4/5/6/7/file1.txt" - // 4. Scan a directory in a deep unknown directory "dirtest/1/2/3/4/5/6/7" - // 5. Scan a deleted file in a known directory "filetest/file1.txt" - // 6. Scan a deleted file in a deep unknown directory "rmdirtest/1/2/3/4/5/6/7" - // 7. 'Accidentally' forget to scan 1 of the 2 files in a known directory - - // Verify that the files and directories sync to the other side - sender := startInstance(t, 1) - defer checkedStop(t, sender) - - receiver := startInstance(t, 2) - defer checkedStop(t, receiver) - - sender.ResumeAll() - receiver.ResumeAll() - - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - - // Delay scans for the moment - if err := sender.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - // 1 - log.Println("Creating new file...") - if fd, err := os.Create("s1/file1.txt"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - if err := sender.RescanSub("default", "file1.txt", 86400); err != nil { - t.Fatal(err) - } - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - // 2 - log.Println("Creating a file in an unknown directory") - os.MkdirAll("s1/filetest", 0755) - if fd, err := os.Create("s1/filetest/file1.txt"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - if err := sender.RescanSub("default", "filetest/file1.txt", 86400); err != nil { - t.Fatal(err) - } - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - // 3 - log.Println("Creating a file in an unknown deep directory") - os.MkdirAll("s1/filetest/1/2/3/4/5/6/7", 0755) - if fd, err := os.Create("s1/filetest/1/2/3/4/5/6/7/file1.txt"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - if err := sender.RescanSub("default", "filetest/1/2/3/4/5/6/7/file1.txt", 86400); err != nil { - t.Fatal(err) - } - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - // 4 - log.Println("Creating a directory in an unknown directory") - err = os.MkdirAll("s1/dirtest/1/2/3/4/5/6/7", 0755) - if err != nil { - t.Fatal(err) - } - if err := sender.RescanSub("default", "dirtest/1/2/3/4/5/6/7", 86400); err != nil { - t.Fatal(err) - } - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - // 5 - log.Println("Scan a deleted file in a known directory") - if err := os.Remove("s1/filetest/file1.txt"); err != nil { - t.Fatal(err) - } - if err := sender.RescanSub("default", "filetest/file1.txt", 86400); err != nil { - t.Fatal(err) - } - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - // 6 - log.Println("Scan a deleted file in an unknown directory") - if err := sender.RescanSub("default", "rmdirtest/1/2/3/4/5/6/7", 86400); err != nil { - t.Fatal(err) - } - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - // 7 - log.Println("'Accidentally' forget to scan 1 of the 2 files") - if fd, err := os.Create("s1/filetest/1/2/3/4/5/6/7/file2.txt"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - if fd, err := os.Create("s1/filetest/1/2/3/4/5/6/7/file3.txt"); err != nil { - t.Fatal(err) - } else { - fd.Close() - } - if err := sender.RescanSub("default", "filetest/1/2/3/4/5/6/7/file2.txt", 86400); err != nil { - t.Fatal(err) - } - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err == nil { - t.Fatal("filetest/1/2/3/4/5/6/7/file3.txt should not be synced") - } - os.Remove("s1/filetest/1/2/3/4/5/6/7/file3.txt") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } -} diff --git a/test/symlink_test.go b/test/symlink_test.go deleted file mode 100644 index 87cf2ac2672..00000000000 --- a/test/symlink_test.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "log" - "os" - "testing" - - "github.com/syncthing/syncthing/lib/config" - "github.com/syncthing/syncthing/lib/events" - "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/rc" -) - -func TestSymlinks(t *testing.T) { - if !symlinksSupported() { - t.Skip("symlinks unsupported") - } - - // Use no versioning - id, _ := protocol.DeviceIDFromString(id2) - cfg, _, _ := config.Load("h2/config.xml", id, events.NoopLogger) - fld := cfg.Folders()["default"] - fld.Versioning = config.VersioningConfiguration{} - cfg.SetFolder(fld) - os.Rename("h2/config.xml", "h2/config.xml.orig") - defer os.Rename("h2/config.xml.orig", "h2/config.xml") - cfg.Save() - - testSymlinks(t) -} - -func TestSymlinksSimpleVersioning(t *testing.T) { - if !symlinksSupported() { - t.Skip("symlinks unsupported") - } - - // Use simple versioning - id, _ := protocol.DeviceIDFromString(id2) - cfg, _, _ := config.Load("h2/config.xml", id, events.NoopLogger) - fld := cfg.Folders()["default"] - fld.Versioning = config.VersioningConfiguration{ - Type: "simple", - Params: map[string]string{"keep": "5"}, - } - cfg.SetFolder(fld) - os.Rename("h2/config.xml", "h2/config.xml.orig") - defer os.Rename("h2/config.xml.orig", "h2/config.xml") - cfg.Save() - - testSymlinks(t) -} - -func TestSymlinksStaggeredVersioning(t *testing.T) { - if !symlinksSupported() { - t.Skip("symlinks unsupported") - } - - // Use staggered versioning - id, _ := protocol.DeviceIDFromString(id2) - cfg, _, _ := config.Load("h2/config.xml", id, events.NoopLogger) - fld := cfg.Folders()["default"] - fld.Versioning = config.VersioningConfiguration{ - Type: "staggered", - } - cfg.SetFolder(fld) - os.Rename("h2/config.xml", "h2/config.xml.orig") - defer os.Rename("h2/config.xml.orig", "h2/config.xml") - cfg.Save() - - testSymlinks(t) -} - -func testSymlinks(t *testing.T) { - log.Println("Cleaning...") - err := removeAll("s1", "s2", "h1/index*", "h2/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - err = generateFiles("s1", 100, 20, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - // A file that we will replace with a symlink later - - fd, err := os.Create("s1/fileToReplace") - if err != nil { - t.Fatal(err) - } - fd.Close() - - // A directory that we will replace with a symlink later - - err = os.Mkdir("s1/dirToReplace", 0755) - if err != nil { - t.Fatal(err) - } - - // A file and a symlink to that file - - fd, err = os.Create("s1/file") - if err != nil { - t.Fatal(err) - } - fd.Close() - err = os.Symlink("file", "s1/fileLink") - if err != nil { - log.Fatal(err) - } - - // A directory and a symlink to that directory - - err = os.Mkdir("s1/dir", 0755) - if err != nil { - t.Fatal(err) - } - err = os.Symlink("dir", "s1/dirLink") - if err != nil { - log.Fatal(err) - } - - // A link to something in the repo that does not exist - - err = os.Symlink("does/not/exist", "s1/noneLink") - if err != nil { - log.Fatal(err) - } - - // A link we will replace with a file later - - err = os.Symlink("does/not/exist", "s1/repFileLink") - if err != nil { - log.Fatal(err) - } - - // A link we will replace with a directory later - - err = os.Symlink("does/not/exist", "s1/repDirLink") - if err != nil { - log.Fatal(err) - } - - // A link we will remove later - - err = os.Symlink("does/not/exist", "s1/removeLink") - if err != nil { - log.Fatal(err) - } - - // Verify that the files and symlinks sync to the other side - - sender := startInstance(t, 1) - defer checkedStop(t, sender) - - receiver := startInstance(t, 2) - defer checkedStop(t, receiver) - - sender.ResumeAll() - receiver.ResumeAll() - - log.Println("Syncing...") - rc.AwaitSync("default", sender, receiver) - - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } - - log.Println("Making some changes...") - - // Remove one symlink - - err = os.Remove("s1/fileLink") - if err != nil { - log.Fatal(err) - } - - // Change the target of another - - err = os.Remove("s1/dirLink") - if err != nil { - log.Fatal(err) - } - err = os.Symlink("file", "s1/dirLink") - if err != nil { - log.Fatal(err) - } - - // Replace one with a file - - err = os.Remove("s1/repFileLink") - if err != nil { - log.Fatal(err) - } - - fd, err = os.Create("s1/repFileLink") - if err != nil { - log.Fatal(err) - } - fd.Close() - - // Replace one with a directory - - err = os.Remove("s1/repDirLink") - if err != nil { - log.Fatal(err) - } - - err = os.Mkdir("s1/repDirLink", 0755) - if err != nil { - log.Fatal(err) - } - - // Replace a file with a symlink - - err = os.Remove("s1/fileToReplace") - if err != nil { - log.Fatal(err) - } - err = os.Symlink("somewhere/non/existent", "s1/fileToReplace") - if err != nil { - log.Fatal(err) - } - - // Replace a directory with a symlink - - err = os.RemoveAll("s1/dirToReplace") - if err != nil { - log.Fatal(err) - } - err = os.Symlink("somewhere/non/existent", "s1/dirToReplace") - if err != nil { - log.Fatal(err) - } - - // Remove a broken symlink - - err = os.Remove("s1/removeLink") - if err != nil { - log.Fatal(err) - } - - // Sync these changes and recheck - - log.Println("Syncing...") - - if err := sender.Rescan("default"); err != nil { - t.Fatal(err) - } - - rc.AwaitSync("default", sender, receiver) - - log.Println("Comparing directories...") - err = compareDirectories("s1", "s2") - if err != nil { - t.Fatal(err) - } -} diff --git a/test/sync_2dev_test.go b/test/sync_2dev_test.go new file mode 100644 index 00000000000..fa0cb4f8558 --- /dev/null +++ b/test/sync_2dev_test.go @@ -0,0 +1,234 @@ +// Copyright (C) 2023 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 integration + +import ( + "context" + "errors" + "fmt" + "sync" + "testing" + "time" + + "github.com/syncthing/syncthing/lib/config" + "github.com/syncthing/syncthing/lib/events" + "github.com/syncthing/syncthing/lib/fs" + "github.com/syncthing/syncthing/lib/rand" + "github.com/syncthing/syncthing/lib/rc" +) + +// TestSyncOneSideToOther verifies that files on one side get synced to the +// other. The test creates actual files on disk in a temp directory, so that +// the data can be compared after syncing. +func TestSyncOneSideToOther(t *testing.T) { + t.Parallel() + + // Create a source folder with some data in it. + srcDir := generateTree(t, 100) + // Create an empty destination folder to hold the synced data. + dstDir := t.TempDir() + + ctx := context.Background() + if dl, ok := t.Deadline(); ok { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, dl) + defer cancel() + } + + // Spin up two instances to sync the data. + testSyncTwoDevicesFolders(ctx, t, srcDir, dstDir) + + // Check that the destination folder now contains the same files as the source folder. + compareTrees(t, srcDir, dstDir) +} + +// TestSyncMergeTwoDevices verifies that two sets of files, one from each +// device, get merged into a coherent total. The test creates actual files +// on disk in a temp directory, so that the data can be compared after +// syncing. +func TestSyncMergeTwoDevices(t *testing.T) { + t.Parallel() + + // Create a source folder with some data in it. + srcDir := generateTree(t, 50) + // Create a destination folder that also has some data in it. + dstDir := generateTree(t, 50) + + ctx := context.Background() + if dl, ok := t.Deadline(); ok { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, dl) + defer cancel() + } + + // Spin up two instances to sync the data. + testSyncTwoDevicesFolders(ctx, t, srcDir, dstDir) + + // Check that both folders are the same, and the file count should be + // the sum of the two. + if total := compareTrees(t, srcDir, dstDir); total != 100 { + t.Fatalf("expected 100 files, got %d", total) + } +} + +func testSyncTwoDevicesFolders(ctx context.Context, t *testing.T, srcDir, dstDir string) { + t.Helper() + + // The folder needs an ID. + folderID := rand.String(8) + + // Start the source device. + src := startInstance(t) + srcAPI := rc.NewAPI(src.apiAddress, src.apiKey) + + // Start the destination device. + dst := startInstance(t) + dstAPI := rc.NewAPI(dst.apiAddress, dst.apiKey) + + // Add the peer device to each device. Hard code the sync addresses to + // speed things up. + if err := srcAPI.Post("/rest/config/devices", &config.DeviceConfiguration{ + DeviceID: dst.deviceID, + Addresses: []string{fmt.Sprintf("tcp://127.0.0.1:%d", dst.tcpPort)}, + }, nil); err != nil { + t.Fatal(err) + } + if err := dstAPI.Post("/rest/config/devices", &config.DeviceConfiguration{ + DeviceID: src.deviceID, + Addresses: []string{fmt.Sprintf("tcp://127.0.0.1:%d", src.tcpPort)}, + }, nil); err != nil { + t.Fatal(err) + } + + // Add the folder to both devices. + if err := srcAPI.Post("/rest/config/folders", &config.FolderConfiguration{ + ID: folderID, + Path: srcDir, + FilesystemType: fs.FilesystemTypeBasic, + Type: config.FolderTypeSendReceive, + Devices: []config.FolderDeviceConfiguration{ + {DeviceID: src.deviceID}, + {DeviceID: dst.deviceID}, + }, + }, nil); err != nil { + t.Fatal(err) + } + if err := dstAPI.Post("/rest/config/folders", &config.FolderConfiguration{ + ID: folderID, + Path: dstDir, + FilesystemType: fs.FilesystemTypeBasic, + Type: config.FolderTypeSendReceive, + Devices: []config.FolderDeviceConfiguration{ + {DeviceID: src.deviceID}, + {DeviceID: dst.deviceID}, + }, + }, nil); err != nil { + t.Fatal(err) + } + + // Listen to events; we want to know when the folder is fully synced. We + // consider the other side in sync when we've received an index update + // from them and subsequently a completion event with percentage equal + // to 100. At that point they should be done. Wait for both sides to do + // their thing. + + var srcDur, dstDur map[string]time.Duration + + var wg sync.WaitGroup + wg.Add(2) + go func() { + defer wg.Done() + var err error + srcDur, err = waitForSync(ctx, folderID, srcAPI) + if err != nil { + t.Error("src:", err) + } + }() + go func() { + defer wg.Done() + var err error + dstDur, err = waitForSync(ctx, folderID, dstAPI) + if err != nil { + t.Error("dst:", err) + } + }() + wg.Wait() + + t.Log("src durations:", srcDur) + t.Log("dst durations:", dstDur) +} + +// waitForSync waits for the folder with the given ID to be fully synced. +// There is a race condition; if the folder is already in sync when we +// start, the events leading up to that have been forgotten, and nothing +// happens thereafter, we may wait forever. +func waitForSync(ctx context.Context, folderID string, api *rc.API) (map[string]time.Duration, error) { + lastEventID := 0 + indexUpdated := false + completed := false + var completedWhen time.Time + stateTimes := make(map[string]time.Duration) + for { + // Get events, with a five second timeout. + ectx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + evs, err := api.Events(ectx, lastEventID) + if errors.Is(err, context.DeadlineExceeded) { + // Check if the main context is done, or if it was just our + // shorter timeout. + select { + case <-ctx.Done(): + return stateTimes, ctx.Err() + default: + } + } else if err != nil { + return stateTimes, err + } + + // If we're completed and it's been a while without hearing + // otherwise, we're done. + if indexUpdated && completed && time.Since(completedWhen) > 4*time.Second { + return stateTimes, nil + } + + for _, ev := range evs { + lastEventID = ev.ID + switch ev.Type { + case events.StateChanged.String(): + data := ev.Data.(map[string]any) + folder := data["folder"].(string) + if folder != folderID { + continue + } + from := data["from"].(string) + if duration, dok := data["duration"].(float64); dok { + stateTimes[from] += time.Duration(duration * float64(time.Second)) + } + + case events.RemoteIndexUpdated.String(): + data := ev.Data.(map[string]any) + folder := data["folder"].(string) + if folder != folderID { + continue + } + completed = false + indexUpdated = true + + case events.FolderCompletion.String(): + data := ev.Data.(map[string]any) + folder := data["folder"].(string) + if folder != folderID { + continue + } + completed = data["completion"].(float64) == 100.0 + if completed { + completedWhen = ev.Time + } + } + } + } +} diff --git a/test/sync_test.go b/test/sync_test.go deleted file mode 100644 index 0029c7c106b..00000000000 --- a/test/sync_test.go +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration -// +build integration - -package integration - -import ( - "fmt" - "log" - "math/rand" - "os" - "testing" - "time" - - "github.com/syncthing/syncthing/lib/rc" -) - -const ( - longTimeLimit = 1 * time.Minute - shortTimeLimit = 25 * time.Second - s12Folder = `¯\_(ツ)_/¯ Räksmörgås 动作 Адрес` // This was renamed to ensure arbitrary folder IDs are fine. -) - -func TestSyncCluster(t *testing.T) { - // This tests syncing files back and forth between three cluster members. - // Their configs are in h1, h2 and h3. The folder "default" is shared - // between all and stored in s1, s2 and s3 respectively. - // - // Another folder is shared between 1 and 2 only, in s12-1 and s12-2. A - // third folders is shared between 2 and 3, in s23-2 and s23-3. - - // When -short is passed, keep it more reasonable. - timeLimit := longTimeLimit - if testing.Short() { - timeLimit = shortTimeLimit - } - - const ( - numFiles = 100 - fileSizeExp = 20 - ) - rand.Seed(42) - - log.Printf("Testing with numFiles=%d, fileSizeExp=%d, timeLimit=%v", numFiles, fileSizeExp, timeLimit) - - log.Println("Cleaning...") - err := removeAll("s1", "s12-1", - "s2", "s12-2", "s23-2", - "s3", "s23-3", - "h1/index*", "h2/index*", "h3/index*") - if err != nil { - t.Fatal(err) - } - - // Create initial folder contents. All three devices have stuff in - // "default", which should be merged. The other two folders are initially - // empty on one side. - - log.Println("Generating files...") - - err = generateFiles("s1", numFiles, fileSizeExp, "../LICENSE") - if err != nil { - t.Fatal(err) - } - err = generateFiles("s12-1", numFiles, fileSizeExp, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - // We'll use this file for appending data without modifying the time stamp. - fd, err := os.Create("s1/test-appendfile") - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("hello\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - - err = generateFiles("s2", numFiles, fileSizeExp, "../LICENSE") - if err != nil { - t.Fatal(err) - } - err = generateFiles("s23-2", numFiles, fileSizeExp, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - err = generateFiles("s3", numFiles, fileSizeExp, "../LICENSE") - if err != nil { - t.Fatal(err) - } - - // Prepare the expected state of folders after the sync - c1, err := directoryContents("s1") - if err != nil { - t.Fatal(err) - } - c2, err := directoryContents("s2") - if err != nil { - t.Fatal(err) - } - c3, err := directoryContents("s3") - if err != nil { - t.Fatal(err) - } - e1 := mergeDirectoryContents(c1, c2, c3) - e2, err := directoryContents("s12-1") - if err != nil { - t.Fatal(err) - } - e3, err := directoryContents("s23-2") - if err != nil { - t.Fatal(err) - } - expected := [][]fileInfo{e1, e2, e3} - - // Start the syncers - - log.Println("Starting Syncthing...") - - p0 := startInstance(t, 1) - defer checkedStop(t, p0) - p1 := startInstance(t, 2) - defer checkedStop(t, p1) - p2 := startInstance(t, 3) - defer checkedStop(t, p2) - - p0.ResumeAll() - p1.ResumeAll() - p2.ResumeAll() - - p := []*rc.Process{p0, p1, p2} - - start := time.Now() - iteration := 0 - for time.Since(start) < timeLimit { - iteration++ - log.Println("Iteration", iteration) - - log.Println("Forcing rescan...") - - // Force rescan of folders - for i, device := range p { - if err := device.RescanDelay("default", 86400); err != nil { - t.Fatal(err) - } - if i == 0 || i == 1 { - if err := device.RescanDelay(s12Folder, 86400); err != nil { - t.Fatal(err) - } - } - if i == 1 || i == 2 { - if err := device.RescanDelay("s23", 86400); err != nil { - t.Fatal(err) - } - } - } - - // Sync stuff and verify it looks right - err = scSyncAndCompare(p, expected) - if err != nil { - t.Error(err) - break - } - - // Sleep for a little over a second to ensure that this round of - // alterations ends up in a different second than the previous one, - // even if the sync was quick. This is to give Syncthing a visible - // mtime change even on filesystem with whole second resolution. - time.Sleep(1100 * time.Millisecond) - - log.Println("Altering...") - - // Alter the source files for another round - err = alterFiles("s1") - if err != nil { - t.Error(err) - break - } - err = alterFiles("s12-1") - if err != nil { - t.Error(err) - break - } - err = alterFiles("s23-2") - if err != nil { - t.Error(err) - break - } - - // Alter the "test-appendfile" without changing its modification time. Sneaky! - fi, err := os.Stat("s1/test-appendfile") - if err != nil { - t.Fatal(err) - } - fd, err := os.OpenFile("s1/test-appendfile", os.O_APPEND|os.O_WRONLY, 0644) - if err != nil { - t.Fatal(err) - } - _, err = fd.Seek(0, os.SEEK_END) - if err != nil { - t.Fatal(err) - } - _, err = fd.WriteString("more data\n") - if err != nil { - t.Fatal(err) - } - err = fd.Close() - if err != nil { - t.Fatal(err) - } - err = os.Chtimes("s1/test-appendfile", fi.ModTime(), fi.ModTime()) - if err != nil { - t.Fatal(err) - } - - // Prepare the expected state of folders after the sync - e1, err = directoryContents("s1") - if err != nil { - t.Fatal(err) - } - e2, err = directoryContents("s12-1") - if err != nil { - t.Fatal(err) - } - e3, err = directoryContents("s23-2") - if err != nil { - t.Fatal(err) - } - expected = [][]fileInfo{e1, e2, e3} - } -} - -func scSyncAndCompare(p []*rc.Process, expected [][]fileInfo) error { - log.Println("Syncing...") - - for { - time.Sleep(250 * time.Millisecond) - if !rc.InSync("default", p...) { - continue - } - if !rc.InSync(s12Folder, p[0], p[1]) { - continue - } - if !rc.InSync("s23", p[1], p[2]) { - continue - } - break - } - - log.Println("Checking...") - - for _, dir := range []string{"s1", "s2", "s3"} { - actual, err := directoryContents(dir) - if err != nil { - return err - } - if err := compareDirectoryContents(actual, expected[0]); err != nil { - return fmt.Errorf("%s: %w", dir, err) - } - } - - if len(expected) > 1 { - for _, dir := range []string{"s12-1", "s12-2"} { - actual, err := directoryContents(dir) - if err != nil { - return err - } - if err := compareDirectoryContents(actual, expected[1]); err != nil { - return fmt.Errorf("%s: %w", dir, err) - } - } - } - - if len(expected) > 2 { - for _, dir := range []string{"s23-2", "s23-3"} { - actual, err := directoryContents(dir) - if err != nil { - return err - } - if err := compareDirectoryContents(actual, expected[2]); err != nil { - return fmt.Errorf("%s: %w", dir, err) - } - } - } - - if err := checkRemoteInSync("default", p[0], p[1]); err != nil { - return err - } - if err := checkRemoteInSync("default", p[0], p[2]); err != nil { - return err - } - if err := checkRemoteInSync(s12Folder, p[0], p[1]); err != nil { - return err - } - if err := checkRemoteInSync("s23", p[1], p[2]); err != nil { - return err - } - - return nil -} - -func TestSyncSparseFile(t *testing.T) { - // This test verifies that when syncing a file that consists mostly of - // zeroes, those blocks are not transferred. It doesn't verify whether - // the resulting file is actually *sparse* or not. - - log.Println("Cleaning...") - err := removeAll("s1", "s12-1", - "s2", "s12-2", "s23-2", - "s3", "s23-3", - "h1/index*", "h2/index*", "h3/index*") - if err != nil { - t.Fatal(err) - } - - log.Println("Generating files...") - - if err := os.Mkdir("s1", 0755); err != nil { - t.Fatal(err) - } - - fd, err := os.Create("s1/testfile") - if err != nil { - t.Fatal(err) - } - if _, err := fd.Write([]byte("Start")); err != nil { - t.Fatal(err) - } - kib := make([]byte, 1024) - for i := 0; i < 8192; i++ { - if _, err := fd.Write(kib); err != nil { - t.Fatal(err) - } - } - if _, err := fd.Write([]byte("End")); err != nil { - t.Fatal(err) - } - fd.Close() - - // Start the syncers - - log.Println("Syncing...") - - p0 := startInstance(t, 1) - defer checkedStop(t, p0) - p1 := startInstance(t, 2) - defer checkedStop(t, p1) - - p0.ResumeAll() - p1.ResumeAll() - - rc.AwaitSync("default", p0, p1) - - log.Println("Comparing...") - - if err := compareDirectories("s1", "s2"); err != nil { - t.Fatal(err) - } - - conns, err := p0.Connections() - if err != nil { - t.Fatal(err) - } - - tot := conns["total"] - if tot.OutBytesTotal > 256<<10 { - t.Fatal("Sending side has sent", tot.OutBytesTotal, "bytes, which is too much") - } -} diff --git a/test/transfer-bench_test.go b/test/transfer-bench_test.go deleted file mode 100644 index 29a9e5095ef..00000000000 --- a/test/transfer-bench_test.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (C) 2014 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/. - -//go:build integration && benchmark -// +build integration,benchmark - -package integration - -import ( - "log" - "math/rand" - "os" - "testing" - "time" - - "github.com/syncthing/syncthing/lib/rc" -) - -func TestBenchmarkTransferManyFiles(t *testing.T) { - setupAndBenchmarkTransfer(t, 10000, 15) -} - -func TestBenchmarkTransferLargeFile1G(t *testing.T) { - setupAndBenchmarkTransfer(t, 1, 30) -} -func TestBenchmarkTransferLargeFile2G(t *testing.T) { - setupAndBenchmarkTransfer(t, 1, 31) -} -func TestBenchmarkTransferLargeFile4G(t *testing.T) { - setupAndBenchmarkTransfer(t, 1, 32) -} -func TestBenchmarkTransferLargeFile8G(t *testing.T) { - setupAndBenchmarkTransfer(t, 1, 33) -} -func TestBenchmarkTransferLargeFile16G(t *testing.T) { - setupAndBenchmarkTransfer(t, 1, 34) -} -func TestBenchmarkTransferLargeFile32G(t *testing.T) { - setupAndBenchmarkTransfer(t, 1, 35) -} - -func setupAndBenchmarkTransfer(t *testing.T, files, sizeExp int) { - cleanBenchmarkTransfer(t) - - log.Println("Generating files...") - var err error - if files == 1 { - // Special case. Generate one file with the specified size exactly. - var fd *os.File - fd, err = os.Open("../LICENSE") - if err != nil { - t.Fatal(err) - } - err = os.MkdirAll("s1", 0755) - if err != nil { - t.Fatal(err) - } - err = generateOneFile(fd, "s1/onefile", 1< s { - a = s - } - s += rand.Int63n(a) - - if err := generateOneFile(fd, p1, s, t0); err != nil { - return err - } - } - - return nil -} - -func generateOneFile(fd io.ReadSeeker, p1 string, s int64, t0 time.Time) error { - src := io.LimitReader(&infiniteReader{fd}, int64(s)) - dst, err := os.Create(p1) - if err != nil { - return err - } - - _, err = io.Copy(dst, src) - if err != nil { - return err - } - - err = dst.Close() - if err != nil { - return err - } - - os.Chmod(p1, os.FileMode(rand.Intn(0777)|0400)) - - t := t0.Add(-time.Duration(rand.Intn(30*86400)) * time.Second) - err = os.Chtimes(p1, t, t) - if err != nil { - return err - } - - return nil -} - -func alterFiles(dir string) error { - err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if os.IsNotExist(err) { - // Something we deleted. Never mind. - return nil - } - - info, err = os.Stat(path) - if err != nil { - // Something we deleted while walking. Ignore. - return nil - } - - if strings.HasPrefix(filepath.Base(path), "test-") { - return nil - } - - switch filepath.Base(path) { - case ".stfolder": - return nil - case ".stversions": - return nil - } - - // File structure is base/x/xy/xyz12345... - // comps == 1: base (don't touch) - // comps == 2: base/x (must be dir) - // comps == 3: base/x/xy (must be dir) - // comps > 3: base/x/xy/xyz12345... (can be dir or file) - - comps := len(strings.Split(path, string(os.PathSeparator))) - - r := rand.Intn(10) - switch { - case r == 0 && comps > 2: - // Delete every tenth file or directory, except top levels - return removeAll(path) - - case r == 1 && info.Mode().IsRegular(): - if info.Mode()&0200 != 0200 { - // Not owner writable. Fix. - if err = os.Chmod(path, 0644); err != nil { - return err - } - } - - // Overwrite a random kilobyte of every tenth file - fd, err := os.OpenFile(path, os.O_RDWR, 0644) - if err != nil { - return err - } - if info.Size() > 1024 { - _, err = fd.Seek(rand.Int63n(info.Size()), os.SEEK_SET) - if err != nil { - return err - } - } - _, err = io.Copy(fd, io.LimitReader(cr.Reader, 1024)) - if err != nil { - return err - } - return fd.Close() - - // Change capitalization - case r == 2 && comps > 3 && rand.Float64() < 0.2: - if build.IsDarwin || build.IsWindows { - // Syncthing is currently broken for case-only renames on case- - // insensitive platforms. - // https://github.com/syncthing/syncthing/issues/1787 - return nil - } - - base := []rune(filepath.Base(path)) - for i, r := range base { - if rand.Float64() < 0.5 { - base[i] = unicode.ToLower(r) - } else { - base[i] = unicode.ToUpper(r) - } - } - newPath := filepath.Join(filepath.Dir(path), string(base)) - if newPath != path { - return os.Rename(path, newPath) - } - - /* - This doesn't in fact work. Sometimes it appears to. We need to get this sorted... - - // Switch between files and directories - case r == 3 && comps > 3 && rand.Float64() < 0.2: - if !info.Mode().IsRegular() { - err = removeAll(path) - if err != nil { - return err - } - d1 := []byte("I used to be a dir: " + path) - err := os.WriteFile(path, d1, 0644) - if err != nil { - return err - } - } else { - err := os.Remove(path) - if err != nil { - return err - } - err = os.MkdirAll(path, 0755) - if err != nil { - return err - } - generateFiles(path, 10, 20, "../LICENSE") - } - return err - */ - - /* - This fails. Bug? - - // Rename the file, while potentially moving it up in the directory hierarchy - case r == 4 && comps > 2 && (info.Mode().IsRegular() || rand.Float64() < 0.2): - rpath := filepath.Dir(path) - if rand.Float64() < 0.2 { - for move := rand.Intn(comps - 1); move > 0; move-- { - rpath = filepath.Join(rpath, "..") - } - } - return osutil.TryRename(path, filepath.Join(rpath, randomName())) - */ - } - - return nil - }) - if err != nil { - return err - } - - return generateFiles(dir, 25, 20, "../LICENSE") -} - -func ReadRand(bs []byte) (int, error) { - var r uint32 - for i := range bs { - if i%4 == 0 { - r = uint32(rand.Int63()) - } - bs[i] = byte(r >> uint((i%4)*8)) - } - return len(bs), nil -} - -func randomName() string { - var b [16]byte - ReadRand(b[:]) - return fmt.Sprintf("%x", b[:]) -} - -type infiniteReader struct { - rd io.ReadSeeker -} - -func (i *infiniteReader) Read(bs []byte) (int, error) { - n, err := i.rd.Read(bs) - if err == io.EOF { - err = nil - i.rd.Seek(0, 0) - } - return n, err -} - -// rm -rf -func removeAll(dirs ...string) error { - for _, dir := range dirs { - files, err := filepath.Glob(dir) - if err != nil { - return err - } - for _, file := range files { - // Set any non-writeable files and dirs to writeable. This is necessary for os.RemoveAll to work on Windows. - filepath.Walk(file, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.Mode()&0700 != 0700 { - os.Chmod(path, 0777) - } - return nil - }) - os.RemoveAll(file) - } - } - return nil -} - -// Compare a number of directories. Returns nil if the contents are identical, -// otherwise an error describing the first found difference. -func compareDirectories(dirs ...string) error { - chans := make([]chan fileInfo, len(dirs)) - for i := range chans { - chans[i] = make(chan fileInfo) - } - errcs := make([]chan error, len(dirs)) - abort := make(chan struct{}) - - for i := range dirs { - errcs[i] = startWalker(dirs[i], chans[i], abort) - } - - res := make([]fileInfo, len(dirs)) - for { - numDone := 0 - for i := range chans { - fi, ok := <-chans[i] - if !ok { - err, hasError := <-errcs[i] - if hasError { - close(abort) - return err - } - numDone++ - } - res[i] = fi - } - - for i := 1; i < len(res); i++ { - if res[i] != res[0] { - close(abort) - return fmt.Errorf("mismatch; %#v (%s) != %#v (%s)", res[i], dirs[i], res[0], dirs[0]) - } - } - - if numDone == len(dirs) { - return nil - } - } -} - -func directoryContents(dir string) ([]fileInfo, error) { - res := make(chan fileInfo) - errc := startWalker(dir, res, nil) - - var files []fileInfo - for f := range res { - files = append(files, f) - } - - return files, <-errc -} - -func mergeDirectoryContents(c ...[]fileInfo) []fileInfo { - m := make(map[string]fileInfo) - - for _, l := range c { - for _, f := range l { - if cur, ok := m[f.name]; !ok || cur.mod < f.mod { - m[f.name] = f - } - } - } - - res := make([]fileInfo, len(m)) - i := 0 - for _, f := range m { - res[i] = f - i++ - } - - sort.Sort(fileInfoList(res)) - return res -} - -func compareDirectoryContents(actual, expected []fileInfo) error { - if len(actual) != len(expected) { - return fmt.Errorf("len(actual) = %d; len(expected) = %d", len(actual), len(expected)) - } - - for i := range actual { - if actual[i] != expected[i] { - return fmt.Errorf("mismatch; actual %#v != expected %#v", actual[i], expected[i]) - } - } - return nil -} - -type fileInfo struct { - name string - mode os.FileMode - mod int64 - hash [sha256.Size]byte - size int64 -} - -func (f fileInfo) String() string { - return fmt.Sprintf("%s %04o %d %x", f.name, f.mode, f.mod, f.hash) -} - -type fileInfoList []fileInfo - -func (l fileInfoList) Len() int { - return len(l) -} - -func (l fileInfoList) Less(a, b int) bool { - return l[a].name < l[b].name -} - -func (l fileInfoList) Swap(a, b int) { - l[a], l[b] = l[b], l[a] -} - -func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan error { - walker := func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - rn, _ := filepath.Rel(dir, path) - if rn == "." || rn == ".stfolder" { - return nil - } - if rn == ".stversions" { - return filepath.SkipDir - } - - var f fileInfo - if info.Mode()&os.ModeSymlink != 0 { - f = fileInfo{ - name: rn, - mode: os.ModeSymlink, - } - - tgt, err := os.Readlink(path) - if err != nil { - return err - } - f.hash = sha256.Sum256([]byte(tgt)) - } else if info.IsDir() { - f = fileInfo{ - name: rn, - mode: info.Mode(), - // hash and modtime zero for directories - } - } else { - f = fileInfo{ - name: rn, - mode: info.Mode(), - // comparing timestamps with better precision than a second - // is problematic as there is rounding and truncatign going - // on at every level - mod: info.ModTime().Unix(), - size: info.Size(), - } - sum, err := sha256file(path) - if err != nil { - return err - } - f.hash = sum - } - - select { - case res <- f: - return nil - case <-abort: - return errors.New("abort") - } - } - - errc := make(chan error) - go func() { - err := filepath.Walk(dir, walker) - close(res) - if err != nil { - errc <- err - } - close(errc) - }() - return errc -} - -func sha256file(fname string) (hash [sha256.Size]byte, err error) { - f, err := os.Open(fname) - if err != nil { - return - } - defer f.Close() - - h := sha256.New() - io.Copy(h, f) - hb := h.Sum(nil) - copy(hash[:], hb) - - return -} - -func isTimeout(err error) bool { - if err == nil { - return false - } - return strings.Contains(err.Error(), "use of closed network connection") || - strings.Contains(err.Error(), "request canceled while waiting") || - strings.Contains(err.Error(), "operation timed out") -} - -func getTestName() string { - callers := make([]uintptr, 100) - runtime.Callers(1, callers) - for i, caller := range callers { - f := runtime.FuncForPC(caller) - if f != nil { - if f.Name() == "testing.tRunner" { - testf := runtime.FuncForPC(callers[i-1]) - if testf != nil { - path := strings.Split(testf.Name(), ".") - return path[len(path)-1] - } - } - } - } - return time.Now().String() -} - -func checkedStop(t *testing.T, p *rc.Process) { - if _, err := p.Stop(); err != nil { - t.Fatal(err) - } -} - -func startInstance(t *testing.T, i int) *rc.Process { - log.Printf("Starting instance %d...", i) - addr := fmt.Sprintf("127.0.0.1:%d", 8080+i) - log := fmt.Sprintf("logs/%s-%d-%d.out", getTestName(), i, time.Now().Unix()%86400) - - p := rc.NewProcess(addr) - p.LogTo(log) - if err := p.Start("../bin/syncthing", "--home", fmt.Sprintf("h%d", i), "--no-browser"); err != nil { - t.Fatal(err) - } - p.AwaitStartup() - p.PauseAll() - return p -} - -func symlinksSupported() bool { - tmp, err := os.MkdirTemp("", "symlink-test") - if err != nil { - return false - } - defer os.RemoveAll(tmp) - err = os.Symlink("tmp", filepath.Join(tmp, "link")) - return err == nil -} - -// checkRemoteInSync checks if the devices associated twith the given processes -// are in sync according to the remote status on both sides. -func checkRemoteInSync(folder string, p1, p2 *rc.Process) error { - if inSync, err := p1.RemoteInSync(folder, p2.ID()); err != nil { - return err - } else if !inSync { - return fmt.Errorf(`from device %v folder "%v" is not in sync on device %v`, p1.ID(), folder, p2.ID()) - } - if inSync, err := p2.RemoteInSync(folder, p1.ID()); err != nil { - return err - } else if !inSync { - return fmt.Errorf(`from device %v folder "%v" is not in sync on device %v`, p2.ID(), folder, p1.ID()) - } - return nil -}