Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into model/emptySummary
Browse files Browse the repository at this point in the history
  • Loading branch information
imsodin committed Feb 12, 2020
2 parents 19826a5 + 0df39dd commit ea96eea
Show file tree
Hide file tree
Showing 22 changed files with 191 additions and 93 deletions.
43 changes: 37 additions & 6 deletions lib/fs/fakefs.go
Expand Up @@ -52,9 +52,10 @@ const randomBlockShift = 14 // 128k
// - Two fakefs:s pointing at the same root path see the same files.
//
type fakefs struct {
mut sync.Mutex
root *fakeEntry
insens bool
mut sync.Mutex
root *fakeEntry
insens bool
withContent bool
}

var (
Expand Down Expand Up @@ -93,9 +94,9 @@ func newFakeFilesystem(root string) *fakefs {
sizeavg, _ := strconv.Atoi(params.Get("sizeavg"))
seed, _ := strconv.Atoi(params.Get("seed"))

if params.Get("insens") == "true" {
fs.insens = true
}
fs.insens = params.Get("insens") == "true"
fs.withContent = params.Get("content") == "true"

if sizeavg == 0 {
sizeavg = 1 << 20
}
Expand Down Expand Up @@ -151,6 +152,7 @@ type fakeEntry struct {
gid int
mtime time.Time
children map[string]*fakeEntry
content []byte
}

func (fs *fakefs) entryForName(name string) *fakeEntry {
Expand Down Expand Up @@ -227,6 +229,10 @@ func (fs *fakefs) create(name string) (*fakeEntry, error) {
entry.size = 0
entry.mtime = time.Now()
entry.mode = 0666
entry.content = nil
if fs.withContent {
entry.content = make([]byte, 0)
}
return entry, nil
}

Expand All @@ -246,6 +252,10 @@ func (fs *fakefs) create(name string) (*fakeEntry, error) {
base = UnicodeLowercase(base)
}

if fs.withContent {
new.content = make([]byte, 0)
}

entry.children[base] = new
return new, nil
}
Expand Down Expand Up @@ -417,6 +427,9 @@ func (fs *fakefs) OpenFile(name string, flags int, mode FileMode) (File, error)
mode: mode,
mtime: time.Now(),
}
if fs.withContent {
newEntry.content = make([]byte, 0)
}

entry.children[key] = newEntry
return &fakeFile{fakeEntry: newEntry}, nil
Expand Down Expand Up @@ -660,6 +673,12 @@ func (f *fakeFile) readShortAt(p []byte, offs int64) (int, error) {
return 0, io.EOF
}

if f.content != nil {
n := copy(p, f.content[int(offs):])
f.offset = offs + int64(n)
return n, nil
}

// Lazily calculate our main seed, a simple 64 bit FNV hash our file
// name.
if f.seed == 0 {
Expand Down Expand Up @@ -746,6 +765,15 @@ func (f *fakeFile) WriteAt(p []byte, off int64) (int, error) {
return 0, errors.New("is a directory")
}

if f.content != nil {
if len(f.content) < int(off)+len(p) {
newc := make([]byte, int(off)+len(p))
copy(newc, f.content)
f.content = newc
}
copy(f.content[int(off):], p)
}

f.rng = nil
f.offset = off + int64(len(p))
if f.offset > f.size {
Expand All @@ -765,6 +793,9 @@ func (f *fakeFile) Truncate(size int64) error {
f.mut.Lock()
defer f.mut.Unlock()

if f.content != nil {
f.content = f.content[:int(size)]
}
f.rng = nil
f.size = size
if f.offset > size {
Expand Down
29 changes: 29 additions & 0 deletions lib/fs/fakefs_test.go
Expand Up @@ -896,6 +896,35 @@ func testFakeFSCreateInsens(t *testing.T, fs Filesystem) {
assertDir(t, fs, "/", []string{"FOO"})
}

func TestReadWriteContent(t *testing.T) {
fs := newFakeFilesystem("foo?content=true")
fd, err := fs.Create("file")
if err != nil {
t.Fatal(err)
}

if _, err := fd.Write([]byte("foo")); err != nil {
t.Fatal(err)
}
if _, err := fd.WriteAt([]byte("bar"), 5); err != nil {
t.Fatal(err)
}
expected := []byte("foo\x00\x00bar")

buf := make([]byte, len(expected)-1)
n, err := fd.ReadAt(buf, 1) // note offset one byte
if err != nil {
t.Fatal(err)
}
if n != len(expected)-1 {
t.Fatal("wrong number of bytes read")
}
if !bytes.Equal(buf[:n], expected[1:]) {
fmt.Printf("%d %q\n", n, buf[:n])
t.Error("wrong data in file")
}
}

func cleanup(fs Filesystem) error {
filenames, _ := fs.DirNames("/")
for _, filename := range filenames {
Expand Down
109 changes: 54 additions & 55 deletions lib/model/folder_recvonly_test.go
Expand Up @@ -9,8 +9,6 @@ package model
import (
"bytes"
"context"
"io/ioutil"
"path/filepath"
"testing"
"time"

Expand All @@ -28,18 +26,18 @@ func TestRecvOnlyRevertDeletes(t *testing.T) {

// Get us a model up and running

m, f := setupROFolder()
m, f := setupROFolder(t)
ffs := f.Filesystem()
defer cleanupModelAndRemoveDir(m, ffs.URI())
defer cleanupModel(m)

// Create some test data

for _, dir := range []string{".stfolder", "ignDir", "unknownDir"} {
must(t, ffs.MkdirAll(dir, 0755))
}
must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "ignDir/ignFile"), []byte("hello\n"), 0644))
must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "unknownDir/unknownFile"), []byte("hello\n"), 0644))
must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), ".stignore"), []byte("ignDir\n"), 0644))
must(t, writeFile(ffs, "ignDir/ignFile", []byte("hello\n"), 0644))
must(t, writeFile(ffs, "unknownDir/unknownFile", []byte("hello\n"), 0644))
must(t, writeFile(ffs, ".stignore", []byte("ignDir\n"), 0644))

knownFiles := setupKnownFiles(t, ffs, []byte("hello\n"))

Expand All @@ -48,15 +46,18 @@ func TestRecvOnlyRevertDeletes(t *testing.T) {
m.Index(device1, "ro", knownFiles)
f.updateLocalsFromScanning(knownFiles)

size := globalSize(t, m, "ro")
m.fmut.RLock()
snap := m.folderFiles["ro"].Snapshot()
m.fmut.RUnlock()
size := snap.GlobalSize()
snap.Release()
if size.Files != 1 || size.Directories != 1 {
t.Fatalf("Global: expected 1 file and 1 directory: %+v", size)
}

// Start the folder. This will cause a scan, should discover the other stuff in the folder
// Scan, should discover the other stuff in the folder

m.startFolder("ro")
m.ScanFolder("ro")
must(t, m.ScanFolder("ro"))

// We should now have two files and two directories.

Expand Down Expand Up @@ -109,9 +110,9 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {

// Get us a model up and running

m, f := setupROFolder()
m, f := setupROFolder(t)
ffs := f.Filesystem()
defer cleanupModelAndRemoveDir(m, ffs.URI())
defer cleanupModel(m)

// Create some test data

Expand All @@ -124,10 +125,9 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
m.Index(device1, "ro", knownFiles)
f.updateLocalsFromScanning(knownFiles)

// Start the folder. This will cause a scan.
// Scan the folder.

m.startFolder("ro")
m.ScanFolder("ro")
must(t, m.ScanFolder("ro"))

// Everything should be in sync.

Expand All @@ -151,7 +151,7 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
// Update the file.

newData := []byte("totally different data\n")
must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "knownDir/knownFile"), newData, 0644))
must(t, writeFile(ffs, "knownDir/knownFile", newData, 0644))

// Rescan.

Expand Down Expand Up @@ -196,34 +196,26 @@ func TestRecvOnlyRevertNeeds(t *testing.T) {
}

func TestRecvOnlyUndoChanges(t *testing.T) {
testOs := &fatalOs{t}

// Get us a model up and running

m, f := setupROFolder()
m, f := setupROFolder(t)
ffs := f.Filesystem()
defer cleanupModelAndRemoveDir(m, ffs.URI())
defer cleanupModel(m)

// Create some test data

must(t, ffs.MkdirAll(".stfolder", 0755))
oldData := []byte("hello\n")
knownFiles := setupKnownFiles(t, ffs, oldData)

m.fmut.Lock()
fset := m.folderFiles["ro"]
m.fmut.Unlock()
folderFs := fset.MtimeFS()

// Send and index update for the known stuff
// Send an index update for the known stuff

m.Index(device1, "ro", knownFiles)
f.updateLocalsFromScanning(knownFiles)

// Start the folder. This will cause a scan.
// Scan the folder.

m.startFolder("ro")
m.ScanFolder("ro")
must(t, m.ScanFolder("ro"))

// Everything should be in sync.

Expand All @@ -246,12 +238,11 @@ func TestRecvOnlyUndoChanges(t *testing.T) {

// Create a file and modify another

file := filepath.Join(ffs.URI(), "foo")
must(t, ioutil.WriteFile(file, []byte("hello\n"), 0644))
const file = "foo"
must(t, writeFile(ffs, file, []byte("hello\n"), 0644))
must(t, writeFile(ffs, "knownDir/knownFile", []byte("bye\n"), 0644))

must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "knownDir/knownFile"), []byte("bye\n"), 0644))

m.ScanFolder("ro")
must(t, m.ScanFolder("ro"))

size = receiveOnlyChangedSize(t, m, "ro")
if size.Files != 2 {
Expand All @@ -260,11 +251,11 @@ func TestRecvOnlyUndoChanges(t *testing.T) {

// Remove the file again and undo the modification

testOs.Remove(file)
must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "knownDir/knownFile"), oldData, 0644))
folderFs.Chtimes("knownDir/knownFile", knownFiles[1].ModTime(), knownFiles[1].ModTime())
must(t, ffs.Remove(file))
must(t, writeFile(ffs, "knownDir/knownFile", oldData, 0644))
must(t, ffs.Chtimes("knownDir/knownFile", knownFiles[1].ModTime(), knownFiles[1].ModTime()))

m.ScanFolder("ro")
must(t, m.ScanFolder("ro"))

size = receiveOnlyChangedSize(t, m, "ro")
if size.Files+size.Directories+size.Deleted != 0 {
Expand All @@ -276,7 +267,7 @@ func setupKnownFiles(t *testing.T, ffs fs.Filesystem, data []byte) []protocol.Fi
t.Helper()

must(t, ffs.MkdirAll("knownDir", 0755))
must(t, ioutil.WriteFile(filepath.Join(ffs.URI(), "knownDir/knownFile"), data, 0644))
must(t, writeFile(ffs, "knownDir/knownFile", data, 0644))

t0 := time.Now().Add(-1 * time.Minute)
must(t, ffs.Chtimes("knownDir/knownFile", t0, t0))
Expand Down Expand Up @@ -310,30 +301,38 @@ func setupKnownFiles(t *testing.T, ffs fs.Filesystem, data []byte) []protocol.Fi
return knownFiles
}

func setupROFolder() (*model, *sendOnlyFolder) {
func setupROFolder(t *testing.T) (*model, *receiveOnlyFolder) {
t.Helper()

w := createTmpWrapper(defaultCfg)
fcfg := testFolderConfigTmp()
fcfg := testFolderConfigFake()
fcfg.ID = "ro"
fcfg.Label = "ro"
fcfg.Type = config.FolderTypeReceiveOnly
w.SetFolder(fcfg)

m := newModel(w, myID, "syncthing", "dev", db.NewLowlevel(backend.OpenMemory()), nil)

m.ServeBackground()

// Folder should only be added, not started.
m.removeFolder(fcfg)
m.addFolder(fcfg)
must(t, m.ScanFolder("ro"))

m.fmut.RLock()
f := &sendOnlyFolder{
folder: folder{
stateTracker: newStateTracker(fcfg.ID, m.evLogger),
fset: m.folderFiles[fcfg.ID],
FolderConfiguration: fcfg,
},
}
m.fmut.RUnlock()
defer m.fmut.RUnlock()
f := m.folderRunners["ro"].(*receiveOnlyFolder)

return m, f
}

func writeFile(fs fs.Filesystem, filename string, data []byte, perm fs.FileMode) error {
fd, err := fs.Create(filename)
if err != nil {
return err
}
_, err = fd.Write(data)
if err != nil {
return err
}
if err := fd.Close(); err != nil {
return err
}
return fs.Chmod(filename, perm)
}

0 comments on commit ea96eea

Please sign in to comment.