|
|
@@ -10,15 +10,12 @@ package integration
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
- "io/ioutil"
|
|
|
"log"
|
|
|
"math/rand"
|
|
|
"os"
|
|
|
"testing"
|
|
|
"time"
|
|
|
|
|
|
- "github.com/syncthing/syncthing/lib/config"
|
|
|
- "github.com/syncthing/syncthing/lib/protocol"
|
|
|
"github.com/syncthing/syncthing/lib/rc"
|
|
|
)
|
|
|
|
|
|
@@ -28,75 +25,7 @@ const (
|
|
|
s12Folder = `¯\_(ツ)_/¯ Räksmörgås 动作 Адрес` // This was renamed to ensure arbitrary folder IDs are fine.
|
|
|
)
|
|
|
|
|
|
-func TestSyncClusterWithoutVersioning(t *testing.T) {
|
|
|
- // Use no versioning
|
|
|
- id, _ := protocol.DeviceIDFromString(id2)
|
|
|
- cfg, _ := config.Load("h2/config.xml", id)
|
|
|
- fld := cfg.Folders()["default"]
|
|
|
- fld.Versioning = config.VersioningConfiguration{}
|
|
|
- cfg.SetFolder(fld)
|
|
|
- cfg.Save()
|
|
|
-
|
|
|
- testSyncCluster(t)
|
|
|
-}
|
|
|
-
|
|
|
-func TestSyncClusterSimpleVersioning(t *testing.T) {
|
|
|
- // Use simple versioning
|
|
|
- id, _ := protocol.DeviceIDFromString(id2)
|
|
|
- cfg, _ := config.Load("h2/config.xml", id)
|
|
|
- fld := cfg.Folders()["default"]
|
|
|
- fld.Versioning = config.VersioningConfiguration{
|
|
|
- Type: "simple",
|
|
|
- Params: map[string]string{"keep": "5"},
|
|
|
- }
|
|
|
- cfg.SetFolder(fld)
|
|
|
- cfg.Save()
|
|
|
-
|
|
|
- testSyncCluster(t)
|
|
|
-}
|
|
|
-
|
|
|
-func TestSyncClusterTrashcanVersioning(t *testing.T) {
|
|
|
- // Use simple versioning
|
|
|
- id, _ := protocol.DeviceIDFromString(id2)
|
|
|
- cfg, _ := config.Load("h2/config.xml", id)
|
|
|
- fld := cfg.Folders()["default"]
|
|
|
- fld.Versioning = config.VersioningConfiguration{
|
|
|
- Type: "trashcan",
|
|
|
- Params: map[string]string{"cleanoutDays": "1"},
|
|
|
- }
|
|
|
- cfg.SetFolder(fld)
|
|
|
- cfg.Save()
|
|
|
-
|
|
|
- testSyncCluster(t)
|
|
|
-}
|
|
|
-
|
|
|
-func TestSyncClusterStaggeredVersioning(t *testing.T) {
|
|
|
- // Use staggered versioning
|
|
|
- id, _ := protocol.DeviceIDFromString(id2)
|
|
|
- cfg, _ := config.Load("h2/config.xml", id)
|
|
|
- fld := cfg.Folders()["default"]
|
|
|
- fld.Versioning = config.VersioningConfiguration{
|
|
|
- Type: "staggered",
|
|
|
- }
|
|
|
- cfg.SetFolder(fld)
|
|
|
- cfg.Save()
|
|
|
-
|
|
|
- testSyncCluster(t)
|
|
|
-}
|
|
|
-
|
|
|
-func TestSyncClusterForcedRescan(t *testing.T) {
|
|
|
- // Use no versioning
|
|
|
- id, _ := protocol.DeviceIDFromString(id2)
|
|
|
- cfg, _ := config.Load("h2/config.xml", id)
|
|
|
- fld := cfg.Folders()["default"]
|
|
|
- fld.Versioning = config.VersioningConfiguration{}
|
|
|
- cfg.SetFolder(fld)
|
|
|
- cfg.Save()
|
|
|
-
|
|
|
- testSyncClusterForcedRescan(t)
|
|
|
-}
|
|
|
-
|
|
|
-func testSyncCluster(t *testing.T) {
|
|
|
+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.
|
|
|
@@ -243,6 +172,12 @@ func testSyncCluster(t *testing.T) {
|
|
|
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
|
|
|
@@ -305,120 +240,6 @@ func testSyncCluster(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func testSyncClusterForcedRescan(t *testing.T) {
|
|
|
- // During this test, we create 1K files, remove and then create them
|
|
|
- // again. However, during these operations we will perform scan operations
|
|
|
- // such that other nodes will retrieve these options while data is
|
|
|
- // changing.
|
|
|
-
|
|
|
- // When -short is passed, keep it more reasonable.
|
|
|
- timeLimit := longTimeLimit
|
|
|
- if testing.Short() {
|
|
|
- timeLimit = shortTimeLimit
|
|
|
- }
|
|
|
-
|
|
|
- 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...")
|
|
|
- if err := os.MkdirAll("s1/test-stable-files", 0755); err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- for i := 0; i < 1000; i++ {
|
|
|
- name := fmt.Sprintf("s1/test-stable-files/%d", i)
|
|
|
- if err := ioutil.WriteFile(name, []byte(time.Now().Format(time.RFC3339Nano)), 0644); err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Prepare the expected state of folders after the sync
|
|
|
- expected, err := directoryContents("s1")
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
-
|
|
|
- // Start the syncers
|
|
|
- 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()
|
|
|
- for time.Since(start) < timeLimit {
|
|
|
- rescan := func() {
|
|
|
- for i := range p {
|
|
|
- if err := p[i].Rescan("default"); err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- log.Println("Forcing rescan...")
|
|
|
- rescan()
|
|
|
-
|
|
|
- // Sync stuff and verify it looks right
|
|
|
- err = scSyncAndCompare(p, [][]fileInfo{expected})
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
-
|
|
|
- log.Println("Altering...")
|
|
|
-
|
|
|
- // Delete and recreate stable files while scanners and pullers are active
|
|
|
- for i := 0; i < 1000; i++ {
|
|
|
- name := fmt.Sprintf("s1/test-stable-files/%d", i)
|
|
|
- if err := os.Remove(name); err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- if rand.Intn(10) == 0 {
|
|
|
- rescan()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- rescan()
|
|
|
-
|
|
|
- time.Sleep(50 * time.Millisecond)
|
|
|
- for i := 0; i < 1000; i++ {
|
|
|
- name := fmt.Sprintf("s1/test-stable-files/%d", i)
|
|
|
- if err := ioutil.WriteFile(name, []byte(time.Now().Format(time.RFC3339Nano)), 0644); err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- if rand.Intn(10) == 0 {
|
|
|
- rescan()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- rescan()
|
|
|
-
|
|
|
- // Prepare the expected state of folders after the sync
|
|
|
- expected, err = directoryContents("s1")
|
|
|
- if err != nil {
|
|
|
- t.Fatal(err)
|
|
|
- }
|
|
|
- if len(expected) != 1001 {
|
|
|
- t.Fatal("s1 does not have 1001 files;", len(expected))
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
func scSyncAndCompare(p []*rc.Process, expected [][]fileInfo) error {
|
|
|
log.Println("Syncing...")
|
|
|
|
|
|
@@ -478,7 +299,7 @@ func scSyncAndCompare(p []*rc.Process, expected [][]fileInfo) error {
|
|
|
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.alterFiles
|
|
|
+ // the resulting file is actually *sparse* or not.
|
|
|
|
|
|
log.Println("Cleaning...")
|
|
|
err := removeAll("s1", "s12-1",
|