Browse Source

Refactor and improve integration tests

Jakob Borg 10 years ago
parent
commit
a3cf37cb2e
6 changed files with 135 additions and 75 deletions
  1. 1 0
      test/http_test.go
  2. 4 14
      test/ignore_test.go
  3. 2 11
      test/parallell_scan_test.go
  4. 2 2
      test/reconnect_test.go
  5. 52 43
      test/sync_test.go
  6. 74 5
      test/syncthingprocess.go

+ 1 - 0
test/http_test.go

@@ -78,6 +78,7 @@ func TestGetIndexAuth(t *testing.T) {
 		argv:     []string{"-home", "h1"},
 		port:     8081,
 		instance: "1",
+		apiKey:   "abc123",
 	}
 	err := st.start()
 	if err != nil {

+ 4 - 14
test/ignore_test.go

@@ -42,16 +42,11 @@ func TestIgnores(t *testing.T) {
 	// startup, UPnP etc complete and make sure that we've performed folder
 	// error checking which creates the folder path if it's missing.
 	for i := 0; i < 20; i++ {
-		resp, err := p.post("/rest/scan?folder=default", nil)
+		err := p.rescan("default")
 		if err != nil {
 			time.Sleep(time.Second)
 			continue
 		}
-		if resp.StatusCode != 200 {
-			resp.Body.Close()
-			time.Sleep(time.Second)
-			continue
-		}
 		break
 	}
 
@@ -93,16 +88,11 @@ func TestIgnores(t *testing.T) {
 	// Wait for one scan to succeed, or up to 20 seconds...
 	// This is to let startup, UPnP etc complete.
 	for i := 0; i < 20; i++ {
-		resp, err := p.post("/rest/scan?folder=default", nil)
+		err := p.rescan("default")
 		if err != nil {
 			time.Sleep(time.Second)
 			continue
 		}
-		if resp.StatusCode != 200 {
-			resp.Body.Close()
-			time.Sleep(time.Second)
-			continue
-		}
 		break
 	}
 
@@ -132,7 +122,7 @@ func TestIgnores(t *testing.T) {
 
 	// Rescan and verify that we see them
 
-	p.post("/rest/scan?folder=default", nil)
+	p.rescan("default")
 	m, err = p.model("default")
 	if err != nil {
 		t.Fatal(err)
@@ -159,7 +149,7 @@ func TestIgnores(t *testing.T) {
 
 	// Rescan and verify that we see them
 
-	p.post("/rest/scan?folder=default", nil)
+	p.rescan("default")
 	m, err = p.model("default")
 	if err != nil {
 		t.Fatal(err)

+ 2 - 11
test/parallell_scan_test.go

@@ -50,16 +50,11 @@ func TestParallellScan(t *testing.T) {
 	// Wait for one scan to succeed, or up to 20 seconds...
 	// This is to let startup, UPnP etc complete.
 	for i := 0; i < 20; i++ {
-		resp, err := st.post("/rest/scan?folder=default", nil)
+		err := st.rescan("default")
 		if err != nil {
 			time.Sleep(time.Second)
 			continue
 		}
-		if resp.StatusCode != 200 {
-			resp.Body.Close()
-			time.Sleep(time.Second)
-			continue
-		}
 		break
 	}
 
@@ -73,16 +68,12 @@ func TestParallellScan(t *testing.T) {
 		wg.Add(1)
 		go func() {
 			defer wg.Done()
-			resp, err := st.post("/rest/scan?folder=default", nil)
+			err := st.rescan("default")
 			log.Println(j)
 			if err != nil {
 				log.Println(err)
 				t.Fatal(err)
 			}
-			if resp.StatusCode != 200 {
-				t.Fatalf("%d != 200", resp.StatusCode)
-			}
-			resp.Body.Close()
 		}()
 	}
 

+ 2 - 2
test/reconnect_test.go

@@ -38,7 +38,7 @@ func testRestartDuringTransfer(t *testing.T, restartSender, restartReceiver bool
 	}
 
 	log.Println("Generating files...")
-	err = generateFiles("s1", 1000, 22, "../LICENSE")
+	err = generateFiles("s1", 250, 20, "../LICENSE")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -138,7 +138,7 @@ func testRestartDuringTransfer(t *testing.T, restartSender, restartReceiver bool
 			prevComp = curComp
 		}
 
-		time.Sleep(250 * time.Millisecond)
+		time.Sleep(time.Second)
 	}
 
 	err = sender.stop()

+ 52 - 43
test/sync_test.go

@@ -61,16 +61,20 @@ func TestSyncClusterStaggeredVersioning(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.
+	//
+	// 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.
+
+	const (
+		numFiles    = 100
+		fileSizeExp = 20
+		iterations  = 3
+	)
+	log.Printf("Testing with numFiles=%d, fileSizeExp=%d, iterations=%d", numFiles, fileSizeExp, iterations)
 
-		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.
-
-	*/
 	log.Println("Cleaning...")
 	err := removeAll("s1", "s12-1",
 		"s2", "s12-2", "s23-2",
@@ -86,11 +90,11 @@ func testSyncCluster(t *testing.T) {
 
 	log.Println("Generating files...")
 
-	err = generateFiles("s1", 1000, 21, "../LICENSE")
+	err = generateFiles("s1", numFiles, fileSizeExp, "../LICENSE")
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = generateFiles("s12-1", 1000, 21, "../LICENSE")
+	err = generateFiles("s12-1", numFiles, fileSizeExp, "../LICENSE")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -109,16 +113,16 @@ func testSyncCluster(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	err = generateFiles("s2", 1000, 21, "../LICENSE")
+	err = generateFiles("s2", numFiles, fileSizeExp, "../LICENSE")
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = generateFiles("s23-2", 1000, 21, "../LICENSE")
+	err = generateFiles("s23-2", numFiles, fileSizeExp, "../LICENSE")
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	err = generateFiles("s3", 1000, 21, "../LICENSE")
+	err = generateFiles("s3", numFiles, fileSizeExp, "../LICENSE")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -158,17 +162,37 @@ func testSyncCluster(t *testing.T) {
 		}
 	}()
 
-	for count := 0; count < 5; count++ {
+	log.Println("Waiting for startup...")
+	// Wait for one scan to succeed, or up to 20 seconds...
+	// This is to let startup, UPnP etc complete.
+	for _, device := range p {
+		for i := 0; i < 20; i++ {
+			err := device.rescan("default")
+			if err != nil {
+				time.Sleep(time.Second)
+				continue
+			}
+			break
+		}
+	}
+
+	for count := 0; count < iterations; count++ {
 		log.Println("Forcing rescan...")
 
 		// Force rescan of folders
-		for i := range p {
-			p[i].post("/rest/scan?folder=default", nil)
-			if i < 3 {
-				p[i].post("/rest/scan?folder=s12", nil)
+		for i, device := range p {
+			if err := device.rescan("default"); err != nil {
+				t.Fatal(err)
+			}
+			if i < 2 {
+				if err := device.rescan("s12"); err != nil {
+					t.Fatal(err)
+				}
 			}
 			if i > 1 {
-				p[i].post("/rest/scan?folder=s23", nil)
+				if err := device.rescan("s23"); err != nil {
+					t.Fatal(err)
+				}
 			}
 		}
 
@@ -284,38 +308,23 @@ func scStartProcesses() ([]syncthingProcess, error) {
 }
 
 func scSyncAndCompare(p []syncthingProcess, expected [][]fileInfo) error {
-	ids := []string{id1, id2, id3}
-
 	log.Println("Syncing...")
 
-mainLoop:
 	for {
-		time.Sleep(2500 * time.Millisecond)
+		time.Sleep(2 * time.Second)
 
-		for i := range p {
-			comp, err := p[i].peerCompletion()
-			if err != nil {
-				if isTimeout(err) {
-					continue mainLoop
-				}
-				return err
-			}
-
-			for id, pct := range comp {
-				if id == ids[i] {
-					// Don't check for self, which will be 0%
-					continue
-				}
-				if pct != 100 {
-					log.Printf("%s not done yet: %d%%", id, pct)
-					continue mainLoop
-				}
-			}
+		if err := allDevicesInSync(p); err != nil {
+			log.Println(err)
+			continue
 		}
 
 		break
 	}
 
+	// This is necessary, or all files won't be in place even when everything
+	// is already reported in sync. Why?!
+	time.Sleep(5 * time.Second)
+
 	log.Println("Checking...")
 
 	for _, dir := range []string{"s1", "s2", "s3"} {

+ 74 - 5
test/syncthingprocess.go

@@ -15,10 +15,14 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"io/ioutil"
+	"log"
 	"net/http"
 	"os"
 	"os/exec"
 	"time"
+
+	"github.com/syncthing/protocol"
 )
 
 var env = []string{
@@ -34,6 +38,7 @@ type syncthingProcess struct {
 	apiKey    string
 	csrfToken string
 	lastEvent int
+	id        protocol.DeviceID
 
 	cmd   *exec.Cmd
 	logfd *os.File
@@ -72,12 +77,32 @@ func (p *syncthingProcess) start() error {
 	p.cmd = cmd
 
 	for {
-		resp, err := p.get("/")
-		if err == nil {
-			resp.Body.Close()
-			return nil
-		}
 		time.Sleep(250 * time.Millisecond)
+
+		resp, err := p.get("/rest/system")
+		if err != nil {
+			continue
+		}
+
+		var sysData map[string]interface{}
+		err = json.NewDecoder(resp.Body).Decode(&sysData)
+		resp.Body.Close()
+		if err != nil {
+			// This one is unexpected. Print it.
+			log.Println("/rest/system (JSON):", err)
+			continue
+		}
+
+		id, err := protocol.DeviceIDFromString(sysData["myID"].(string))
+		if err != nil {
+			// This one is unexpected. Print it.
+			log.Println("/rest/system (myID):", err)
+			continue
+		}
+
+		p.id = id
+
+		return nil
 	}
 }
 
@@ -173,9 +198,31 @@ func (p *syncthingProcess) peerCompletion() (map[string]int, error) {
 
 	comp := map[string]int{}
 	err = json.NewDecoder(resp.Body).Decode(&comp)
+
+	// Remove ourselves from the set. In the remaining map, all peers should
+	// be att 100% if we're in sync.
+	for id := range comp {
+		if id == p.id.String() {
+			delete(comp, id)
+		}
+	}
+
 	return comp, err
 }
 
+func (p *syncthingProcess) allPeersInSync() error {
+	comp, err := p.peerCompletion()
+	if err != nil {
+		return err
+	}
+	for id, val := range comp {
+		if val != 100 {
+			return fmt.Errorf("%.7s at %d%%", id, val)
+		}
+	}
+	return nil
+}
+
 type model struct {
 	GlobalBytes   int
 	GlobalDeleted int
@@ -249,3 +296,25 @@ func (p *syncthingProcess) version() (string, error) {
 	}
 	return v.Version, nil
 }
+
+func (p *syncthingProcess) rescan(folder string) error {
+	resp, err := p.post("/rest/scan?folder="+folder, nil)
+	if err != nil {
+		return err
+	}
+	data, _ := ioutil.ReadAll(resp.Body)
+	resp.Body.Close()
+	if resp.StatusCode != 200 {
+		return fmt.Errorf("Rescan %q: status code %d: %s", folder, resp.StatusCode, data)
+	}
+	return nil
+}
+
+func allDevicesInSync(p []syncthingProcess) error {
+	for _, device := range p {
+		if err := device.allPeersInSync(); err != nil {
+			return fmt.Errorf("%.7s: %v", device.id.String(), err)
+		}
+	}
+	return nil
+}