1package vfstest
2
3import (
4	"os"
5	"runtime"
6	"testing"
7
8	"github.com/rclone/rclone/vfs/vfscommon"
9	"github.com/stretchr/testify/assert"
10	"github.com/stretchr/testify/require"
11)
12
13// TestWriteFileNoWrite tests writing a file with no write()'s to it
14func TestWriteFileNoWrite(t *testing.T) {
15	run.skipIfNoFUSE(t)
16
17	fd, err := osCreate(run.path("testnowrite"))
18	assert.NoError(t, err)
19
20	err = fd.Close()
21	assert.NoError(t, err)
22
23	run.waitForWriters()
24
25	run.checkDir(t, "testnowrite 0")
26
27	run.rm(t, "testnowrite")
28}
29
30// FIXMETestWriteOpenFileInDirListing tests open file in directory listing
31func FIXMETestWriteOpenFileInDirListing(t *testing.T) {
32	run.skipIfNoFUSE(t)
33
34	fd, err := osCreate(run.path("testnowrite"))
35	assert.NoError(t, err)
36
37	run.checkDir(t, "testnowrite 0")
38
39	err = fd.Close()
40	assert.NoError(t, err)
41
42	run.waitForWriters()
43
44	run.rm(t, "testnowrite")
45}
46
47// TestWriteFileWrite tests writing a file and reading it back
48func TestWriteFileWrite(t *testing.T) {
49	run.skipIfNoFUSE(t)
50
51	run.createFile(t, "testwrite", "data")
52	run.checkDir(t, "testwrite 4")
53	contents := run.readFile(t, "testwrite")
54	assert.Equal(t, "data", contents)
55	run.rm(t, "testwrite")
56}
57
58// TestWriteFileOverwrite tests overwriting a file
59func TestWriteFileOverwrite(t *testing.T) {
60	run.skipIfNoFUSE(t)
61
62	run.createFile(t, "testwrite", "data")
63	run.checkDir(t, "testwrite 4")
64	run.createFile(t, "testwrite", "potato")
65	contents := run.readFile(t, "testwrite")
66	assert.Equal(t, "potato", contents)
67	run.rm(t, "testwrite")
68}
69
70// TestWriteFileFsync tests Fsync
71//
72// NB the code for this is in file.go rather than write.go
73func TestWriteFileFsync(t *testing.T) {
74	run.skipIfNoFUSE(t)
75
76	filepath := run.path("to be synced")
77	fd, err := osCreate(filepath)
78	require.NoError(t, err)
79	_, err = fd.Write([]byte("hello"))
80	require.NoError(t, err)
81	err = fd.Sync()
82	require.NoError(t, err)
83	err = fd.Close()
84	require.NoError(t, err)
85	run.waitForWriters()
86	run.rm(t, "to be synced")
87}
88
89// TestWriteFileDup tests behavior of mmap() in Python by using dup() on a file handle
90func TestWriteFileDup(t *testing.T) {
91	run.skipIfVFS(t)
92	run.skipIfNoFUSE(t)
93
94	if run.vfs.Opt.CacheMode < vfscommon.CacheModeWrites {
95		t.Skip("not supported on vfs-cache-mode < writes")
96		return
97	}
98
99	filepath := run.path("to be synced")
100	fh, err := osCreate(filepath)
101	require.NoError(t, err)
102
103	testData := []byte("0123456789")
104
105	err = fh.Truncate(int64(len(testData) + 2))
106	require.NoError(t, err)
107
108	err = fh.Sync()
109	require.NoError(t, err)
110
111	var dupFd uintptr
112	dupFd, err = writeTestDup(fh.Fd())
113	require.NoError(t, err)
114
115	dupFile := os.NewFile(dupFd, fh.Name())
116	_, err = dupFile.Write(testData)
117	require.NoError(t, err)
118
119	err = dupFile.Close()
120	require.NoError(t, err)
121
122	_, err = fh.Seek(int64(len(testData)), 0)
123	require.NoError(t, err)
124
125	_, err = fh.Write([]byte("10"))
126	require.NoError(t, err)
127
128	err = fh.Close()
129	require.NoError(t, err)
130
131	run.waitForWriters()
132	run.rm(t, "to be synced")
133}
134
135// TestWriteFileAppend tests that O_APPEND works on cache backends >= writes
136func TestWriteFileAppend(t *testing.T) {
137	run.skipIfNoFUSE(t)
138
139	if run.vfs.Opt.CacheMode < vfscommon.CacheModeWrites {
140		t.Skip("not supported on vfs-cache-mode < writes")
141		return
142	}
143
144	// TODO: Windows needs the v1.5 release of WinFsp to handle O_APPEND properly.
145	// Until it gets released, skip this test on Windows.
146	if runtime.GOOS == "windows" {
147		t.Skip("currently unsupported on Windows")
148	}
149
150	filepath := run.path("to be synced")
151	fh, err := osCreate(filepath)
152	require.NoError(t, err)
153
154	testData := []byte("0123456789")
155	appendData := []byte("10")
156
157	_, err = fh.Write(testData)
158	require.NoError(t, err)
159
160	err = fh.Close()
161	require.NoError(t, err)
162
163	fh, err = osAppend(filepath)
164	require.NoError(t, err)
165
166	_, err = fh.Write(appendData)
167	require.NoError(t, err)
168
169	err = fh.Close()
170	require.NoError(t, err)
171
172	info, err := run.os.Stat(filepath)
173	require.NoError(t, err)
174	require.EqualValues(t, len(testData)+len(appendData), info.Size())
175
176	run.waitForWriters()
177	run.rm(t, "to be synced")
178}
179