瀏覽代碼

Override needs to twiddle the version a bit more (fixes #1564)

Jakob Borg 10 年之前
父節點
當前提交
a17333d73e
共有 2 個文件被更改,包括 224 次插入1 次删除
  1. 2 1
      internal/model/model.go
  2. 222 0
      test/override_test.go

+ 2 - 1
internal/model/model.go

@@ -1370,11 +1370,12 @@ func (m *Model) Override(folder string) {
 			// We are missing the file
 			need.Flags |= protocol.FlagDeleted
 			need.Blocks = nil
+			need.Version = need.Version.Update(m.shortID)
 		} else {
 			// We have the file, replace with our version
+			have.Version = have.Version.Merge(need.Version).Update(m.shortID)
 			need = have
 		}
-		need.Version = need.Version.Update(m.shortID)
 		need.LocalVersion = 0
 		batch = append(batch, need)
 		return true

+ 222 - 0
test/override_test.go

@@ -0,0 +1,222 @@
+// Copyright (C) 2015 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build integration
+
+package integration
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/syncthing/protocol"
+	"github.com/syncthing/syncthing/internal/config"
+)
+
+func TestOverride(t *testing.T) {
+	// Enable "Master" on s1/default
+	id, _ := protocol.DeviceIDFromString(id1)
+	cfg, _ := config.Load("h1/config.xml", id)
+	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", 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)
+	}
+
+	log.Println("Starting master...")
+	master := syncthingProcess{ // id1
+		instance: "1",
+		argv:     []string{"-home", "h1"},
+		port:     8081,
+		apiKey:   apiKey,
+	}
+	err = master.start()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer master.stop()
+
+	// Wait for one scan to succeed, or up to 20 seconds... This is to let
+	// startup, UPnP etc complete and make sure the master has the full index
+	// before they connect.
+	for i := 0; i < 20; i++ {
+		err := master.rescan("default")
+		if err != nil {
+			time.Sleep(time.Second)
+			continue
+		}
+		break
+	}
+
+	log.Println("Starting slave...")
+	slave := syncthingProcess{ // id2
+		instance: "2",
+		argv:     []string{"-home", "h2"},
+		port:     8082,
+		apiKey:   apiKey,
+	}
+	err = slave.start()
+	if err != nil {
+		master.stop()
+		t.Fatal(err)
+	}
+	defer slave.stop()
+
+	log.Println("Syncing...")
+
+	if err = ovCompletion(100, master, slave); 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("Changing file on slave 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)
+	}
+
+	err = slave.rescan("default")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	log.Println("Syncing...")
+
+	time.Sleep(5 * time.Second)
+
+	// Expect ~99% completion since the change will be rejected by the master side
+	if err = ovCompletion(99, master, slave); err != nil {
+		t.Fatal(err)
+	}
+
+	log.Println("Hitting Override on master...")
+
+	resp, err := master.post("/rest/model/override?folder=default", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if resp.StatusCode != 200 {
+		t.Fatal(resp.Status)
+	}
+
+	log.Println("Syncing...")
+
+	if err = ovCompletion(100, master, slave); err != nil {
+		t.Fatal(err)
+	}
+
+	// Verify that the override worked
+
+	fd, err = os.Open("s1/testfile.txt")
+	if err != nil {
+		t.Fatal(err)
+	}
+	bs, err := ioutil.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 master")
+	}
+
+	fd, err = os.Open("s2/testfile.txt")
+	if err != nil {
+		t.Fatal(err)
+	}
+	bs, err = ioutil.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 slave")
+	}
+}
+
+func ovCompletion(expected int, p ...syncthingProcess) error {
+mainLoop:
+	for {
+		time.Sleep(2500 * time.Millisecond)
+
+		tot := 0
+		for i := range p {
+			comp, err := p[i].peerCompletion()
+			if err != nil {
+				if isTimeout(err) {
+					continue mainLoop
+				}
+				return err
+			}
+
+			for _, pct := range comp {
+				tot += pct
+			}
+		}
+
+		if tot >= expected*len(p) {
+			return nil
+		}
+
+		log.Printf("%d / %d...", tot, expected*len(p))
+	}
+}