cache_test.go 4.27 KB
Newer Older
1 2 3
package fuse

import (
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
4
	"bytes"
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
5
	"github.com/hanwen/go-fuse/raw"
6
	"io/ioutil"
7
	"log"
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
8
	"os"
9
	"sync"
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
10
	"testing"
11
)
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
12

13
var _ = log.Println
14 15 16 17 18

type cacheFs struct {
	*LoopbackFileSystem
}

19 20
func (fs *cacheFs) Open(name string, flags uint32, context *Context) (fuseFile File, status Status) {
	f, c := fs.LoopbackFileSystem.Open(name, flags, context)
21 22 23 24
	if !c.Ok() {
		return f, c
	}
	return &WithFlags{
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
25
		File:      f,
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
26
		FuseFlags: raw.FOPEN_KEEP_CACHE,
27 28 29 30
	}, c

}

31
func setupCacheTest(t *testing.T) (string, *PathNodeFs, func()) {
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
32
	dir, err := ioutil.TempDir("", "go-fuse")
33 34 35
	if err != nil {
		t.Fatalf("TempDir failed: %v", err)
	}
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
36 37
	os.Mkdir(dir+"/mnt", 0755)
	os.Mkdir(dir+"/orig", 0755)
38 39 40 41

	fs := &cacheFs{
		LoopbackFileSystem: NewLoopbackFileSystem(dir + "/orig"),
	}
42
	pfs := NewPathNodeFs(fs, nil)
43
	state, conn, err := MountNodeFileSystem(dir+"/mnt", pfs, nil)
44 45 46
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
47 48 49
	state.Debug = VerboseTest()
	conn.Debug = VerboseTest()
	pfs.Debug = VerboseTest()
50
	go state.Loop()
51

52
	return dir, pfs, func() {
53 54 55 56 57 58 59 60
		err := state.Unmount()
		if err == nil {
			os.RemoveAll(dir)
		}
	}
}

func TestCacheFs(t *testing.T) {
61
	wd, pathfs, clean := setupCacheTest(t)
62 63
	defer clean()

64 65 66
	content1 := "hello"
	content2 := "qqqq"
	err := ioutil.WriteFile(wd+"/orig/file.txt", []byte(content1), 0644)
67 68 69
	if err != nil {
		t.Fatalf("WriteFile failed: %v", err)
	}
70

Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
71
	c, err := ioutil.ReadFile(wd + "/mnt/file.txt")
72 73 74
	if err != nil {
		t.Fatalf("ReadFile failed: %v", err)
	}
75 76 77 78 79

	if string(c) != "hello" {
		t.Fatalf("expect 'hello' %q", string(c))
	}

80
	err = ioutil.WriteFile(wd+"/orig/file.txt", []byte(content2), 0644)
81 82 83
	if err != nil {
		t.Fatalf("WriteFile failed: %v", err)
	}
84

Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
85
	c, err = ioutil.ReadFile(wd + "/mnt/file.txt")
86 87 88
	if err != nil {
		t.Fatalf("ReadFile failed: %v", err)
	}
89 90

	if string(c) != "hello" {
91
		t.Fatalf("Page cache skipped: expect 'hello' %q", string(c))
92
	}
93

94
	code := pathfs.EntryNotify("", "file.txt")
95 96 97 98 99
	if !code.Ok() {
		t.Errorf("Entry notify failed: %v", code)
	}

	c, err = ioutil.ReadFile(wd + "/mnt/file.txt")
100 101 102
	if err != nil {
		t.Fatalf("ReadFile failed: %v", err)
	}
103
	if string(c) != string(content2) {
104
		t.Fatalf("Mismatch after notify expect '%s' %q", content2, string(c))
105
	}
106
}
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
107 108 109

type nonseekFs struct {
	DefaultFileSystem
110
	Length int
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
111 112
}

113
func (fs *nonseekFs) GetAttr(name string, context *Context) (fi *Attr, status Status) {
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
114
	if name == "file" {
115
		return &Attr{Mode: S_IFREG | 0644}, OK
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
116 117 118 119
	}
	return nil, ENOENT
}

120
func (fs *nonseekFs) Open(name string, flags uint32, context *Context) (fuseFile File, status Status) {
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
121 122 123 124
	if name != "file" {
		return nil, ENOENT
	}

125
	data := bytes.Repeat([]byte{42}, fs.Length)
126
	f := NewDataFile(data)
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
127
	return &WithFlags{
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
128
		File:      f,
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
129
		FuseFlags: raw.FOPEN_NONSEEKABLE,
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
130 131 132 133 134
	}, OK
}

func TestNonseekable(t *testing.T) {
	fs := &nonseekFs{}
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
135
	fs.Length = 200 * 1024
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
136

Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
137
	dir, err := ioutil.TempDir("", "go-fuse")
138 139 140
	if err != nil {
		t.Fatalf("failed: %v", err)
	}
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
141
	defer os.RemoveAll(dir)
142 143
	nfs := NewPathNodeFs(fs, nil)
	state, _, err := MountNodeFileSystem(dir, nfs, nil)
144 145 146
	if err != nil {
		t.Fatalf("failed: %v", err)
	}
147
	state.Debug = VerboseTest()
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
148 149
	defer state.Unmount()

150
	go state.Loop()
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
151 152

	f, err := os.Open(dir + "/file")
153 154 155
	if err != nil {
		t.Fatalf("failed: %v", err)
	}
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
156
	defer f.Close()
157

Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
158 159 160 161 162 163
	b := make([]byte, 200)
	n, err := f.ReadAt(b, 20)
	if err == nil || n > 0 {
		t.Errorf("file was opened nonseekable, but seek successful")
	}
}
164 165 166

func TestGetAttrRace(t *testing.T) {
	dir, err := ioutil.TempDir("", "go-fuse")
167 168 169
	if err != nil {
		t.Fatalf("failed: %v", err)
	}
170 171 172 173 174 175 176 177
	defer os.RemoveAll(dir)
	os.Mkdir(dir+"/mnt", 0755)
	os.Mkdir(dir+"/orig", 0755)

	fs := NewLoopbackFileSystem(dir + "/orig")
	pfs := NewPathNodeFs(fs, nil)
	state, conn, err := MountNodeFileSystem(dir+"/mnt", pfs,
		&FileSystemOptions{})
178 179 180
	if err != nil {
		t.Fatalf("MountNodeFileSystem failed: %v", err)
	}
181 182 183 184 185 186 187 188 189 190 191
	state.Debug = VerboseTest()
	conn.Debug = VerboseTest()
	pfs.Debug = VerboseTest()
	go state.Loop()

	defer state.Unmount()

	var wg sync.WaitGroup

	n := 100
	wg.Add(n)
192
	var statErr error
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	for i := 0; i < n; i++ {
		go func() {
			defer wg.Done()
			fn := dir + "/mnt/file"
			err := ioutil.WriteFile(fn, []byte{42}, 0644)
			if err != nil {
				statErr = err
				return
			}
			_, err = os.Lstat(fn)
			if err != nil {
				statErr = err
			}
		}()
	}
	wg.Wait()
	if statErr != nil {
		t.Error(statErr)
	}
}