github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/vfs/write_test.go (about) 1 package vfs 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/pkg/errors" 12 "github.com/rclone/rclone/fs" 13 "github.com/rclone/rclone/fstest" 14 "github.com/rclone/rclone/lib/random" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 // Open a file for write 20 func writeHandleCreate(t *testing.T, r *fstest.Run) (*VFS, *WriteFileHandle) { 21 vfs := New(r.Fremote, nil) 22 23 h, err := vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE, 0777) 24 require.NoError(t, err) 25 fh, ok := h.(*WriteFileHandle) 26 require.True(t, ok) 27 28 return vfs, fh 29 } 30 31 func TestWriteFileHandleMethods(t *testing.T) { 32 r := fstest.NewRun(t) 33 defer r.Finalise() 34 vfs, fh := writeHandleCreate(t, r) 35 36 // String 37 assert.Equal(t, "file1 (w)", fh.String()) 38 assert.Equal(t, "<nil *WriteFileHandle>", (*WriteFileHandle)(nil).String()) 39 assert.Equal(t, "<nil *WriteFileHandle.file>", new(WriteFileHandle).String()) 40 41 // Node 42 node := fh.Node() 43 assert.Equal(t, "file1", node.Name()) 44 45 // Offset #1 46 assert.Equal(t, int64(0), fh.Offset()) 47 assert.Equal(t, int64(0), node.Size()) 48 49 // Write (smoke test only since heavy lifting done in WriteAt) 50 n, err := fh.Write([]byte("hello")) 51 assert.NoError(t, err) 52 assert.Equal(t, 5, n) 53 54 // Offset #2 55 assert.Equal(t, int64(5), fh.Offset()) 56 assert.Equal(t, int64(5), node.Size()) 57 58 // Stat 59 var fi os.FileInfo 60 fi, err = fh.Stat() 61 assert.NoError(t, err) 62 assert.Equal(t, int64(5), fi.Size()) 63 assert.Equal(t, "file1", fi.Name()) 64 65 // Read 66 var buf = make([]byte, 16) 67 _, err = fh.Read(buf) 68 assert.Equal(t, EPERM, err) 69 70 // ReadAt 71 _, err = fh.ReadAt(buf, 0) 72 assert.Equal(t, EPERM, err) 73 74 // Sync 75 err = fh.Sync() 76 assert.NoError(t, err) 77 78 // Truncate - can only truncate where the file pointer is 79 err = fh.Truncate(5) 80 assert.NoError(t, err) 81 err = fh.Truncate(6) 82 assert.Equal(t, EPERM, err) 83 84 // Close 85 assert.NoError(t, fh.Close()) 86 87 // Check double close 88 err = fh.Close() 89 assert.Equal(t, ECLOSED, err) 90 91 // check vfs 92 root, err := vfs.Root() 93 require.NoError(t, err) 94 checkListing(t, root, []string{"file1,5,false"}) 95 96 // check the underlying r.Fremote but not the modtime 97 file1 := fstest.NewItem("file1", "hello", t1) 98 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{}, fs.ModTimeNotSupported) 99 100 // Check trying to open the file now it exists then closing it 101 // immediately is OK 102 h, err := vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE, 0777) 103 require.NoError(t, err) 104 assert.NoError(t, h.Close()) 105 checkListing(t, root, []string{"file1,5,false"}) 106 107 // Check trying to open the file and writing it now it exists 108 // returns an error 109 h, err = vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE, 0777) 110 require.NoError(t, err) 111 _, err = h.Write([]byte("hello1")) 112 require.Equal(t, EPERM, err) 113 assert.NoError(t, h.Close()) 114 checkListing(t, root, []string{"file1,5,false"}) 115 116 // Check opening the file with O_TRUNC does actually truncate 117 // it even if we don't write to it 118 h, err = vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777) 119 require.NoError(t, err) 120 err = h.Close() 121 if errors.Cause(err) != fs.ErrorCantUploadEmptyFiles { 122 assert.NoError(t, err) 123 checkListing(t, root, []string{"file1,0,false"}) 124 } 125 126 // Check opening the file with O_TRUNC and writing does work 127 h, err = vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777) 128 require.NoError(t, err) 129 _, err = h.WriteString("hello12") 130 require.NoError(t, err) 131 assert.NoError(t, h.Close()) 132 checkListing(t, root, []string{"file1,7,false"}) 133 } 134 135 func TestWriteFileHandleWriteAt(t *testing.T) { 136 r := fstest.NewRun(t) 137 defer r.Finalise() 138 vfs, fh := writeHandleCreate(t, r) 139 140 // Preconditions 141 assert.Equal(t, int64(0), fh.offset) 142 assert.False(t, fh.writeCalled) 143 144 // Write the data 145 n, err := fh.WriteAt([]byte("hello"), 0) 146 assert.NoError(t, err) 147 assert.Equal(t, 5, n) 148 149 // After write 150 assert.Equal(t, int64(5), fh.offset) 151 assert.True(t, fh.writeCalled) 152 153 // Check can't seek 154 n, err = fh.WriteAt([]byte("hello"), 100) 155 assert.Equal(t, ESPIPE, err) 156 assert.Equal(t, 0, n) 157 158 // Write more data 159 n, err = fh.WriteAt([]byte(" world"), 5) 160 assert.NoError(t, err) 161 assert.Equal(t, 6, n) 162 163 // Close 164 assert.NoError(t, fh.Close()) 165 166 // Check can't write on closed handle 167 n, err = fh.WriteAt([]byte("hello"), 0) 168 assert.Equal(t, ECLOSED, err) 169 assert.Equal(t, 0, n) 170 171 // check vfs 172 root, err := vfs.Root() 173 require.NoError(t, err) 174 checkListing(t, root, []string{"file1,11,false"}) 175 176 // check the underlying r.Fremote but not the modtime 177 file1 := fstest.NewItem("file1", "hello world", t1) 178 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{}, fs.ModTimeNotSupported) 179 } 180 181 func TestWriteFileHandleFlush(t *testing.T) { 182 r := fstest.NewRun(t) 183 defer r.Finalise() 184 vfs, fh := writeHandleCreate(t, r) 185 186 // Check Flush already creates file for unwritten handles, without closing it 187 err := fh.Flush() 188 assert.NoError(t, err) 189 assert.False(t, fh.closed) 190 root, err := vfs.Root() 191 assert.NoError(t, err) 192 checkListing(t, root, []string{"file1,0,false"}) 193 194 // Write some data 195 n, err := fh.Write([]byte("hello")) 196 assert.NoError(t, err) 197 assert.Equal(t, 5, n) 198 199 // Check Flush closes file if write called 200 err = fh.Flush() 201 assert.NoError(t, err) 202 assert.True(t, fh.closed) 203 204 // Check flush does nothing if called again 205 err = fh.Flush() 206 assert.NoError(t, err) 207 assert.True(t, fh.closed) 208 209 // Check file was written properly 210 root, err = vfs.Root() 211 assert.NoError(t, err) 212 checkListing(t, root, []string{"file1,5,false"}) 213 } 214 215 func TestWriteFileHandleRelease(t *testing.T) { 216 r := fstest.NewRun(t) 217 defer r.Finalise() 218 _, fh := writeHandleCreate(t, r) 219 220 // Check Release closes file 221 err := fh.Release() 222 if errors.Cause(err) == fs.ErrorCantUploadEmptyFiles { 223 t.Logf("skipping test: %v", err) 224 return 225 } 226 assert.NoError(t, err) 227 assert.True(t, fh.closed) 228 229 // Check Release does nothing if called again 230 err = fh.Release() 231 assert.NoError(t, err) 232 assert.True(t, fh.closed) 233 } 234 235 var ( 236 canSetModTimeOnce sync.Once 237 canSetModTimeValue = true 238 ) 239 240 // returns whether the remote can set modtime 241 func canSetModTime(t *testing.T, r *fstest.Run) bool { 242 canSetModTimeOnce.Do(func() { 243 mtime1 := time.Date(2008, time.November, 18, 17, 32, 31, 0, time.UTC) 244 _ = r.WriteObject(context.Background(), "time_test", "stuff", mtime1) 245 obj, err := r.Fremote.NewObject(context.Background(), "time_test") 246 require.NoError(t, err) 247 mtime2 := time.Date(2009, time.November, 18, 17, 32, 31, 0, time.UTC) 248 err = obj.SetModTime(context.Background(), mtime2) 249 switch err { 250 case nil: 251 canSetModTimeValue = true 252 case fs.ErrorCantSetModTime, fs.ErrorCantSetModTimeWithoutDelete: 253 canSetModTimeValue = false 254 default: 255 require.NoError(t, err) 256 } 257 require.NoError(t, obj.Remove(context.Background())) 258 fs.Debugf(nil, "Can set mod time: %v", canSetModTimeValue) 259 }) 260 return canSetModTimeValue 261 } 262 263 // tests mod time on open files 264 func TestWriteFileModTimeWithOpenWriters(t *testing.T) { 265 r := fstest.NewRun(t) 266 defer r.Finalise() 267 if !canSetModTime(t, r) { 268 return 269 } 270 vfs, fh := writeHandleCreate(t, r) 271 272 mtime := time.Date(2012, time.November, 18, 17, 32, 31, 0, time.UTC) 273 274 _, err := fh.Write([]byte{104, 105}) 275 require.NoError(t, err) 276 277 err = fh.Node().SetModTime(mtime) 278 require.NoError(t, err) 279 280 err = fh.Close() 281 require.NoError(t, err) 282 283 info, err := vfs.Stat("file1") 284 require.NoError(t, err) 285 286 if r.Fremote.Precision() != fs.ModTimeNotSupported { 287 // avoid errors because of timezone differences 288 assert.Equal(t, info.ModTime().Unix(), mtime.Unix()) 289 } 290 } 291 292 func testFileReadAt(t *testing.T, n int) { 293 r := fstest.NewRun(t) 294 defer r.Finalise() 295 vfs, fh := writeHandleCreate(t, r) 296 297 contents := []byte(random.String(n)) 298 if n != 0 { 299 written, err := fh.Write(contents) 300 require.NoError(t, err) 301 assert.Equal(t, n, written) 302 } 303 304 // Close the file without writing to it if n==0 305 err := fh.Close() 306 if errors.Cause(err) == fs.ErrorCantUploadEmptyFiles { 307 t.Logf("skipping test: %v", err) 308 return 309 } 310 assert.NoError(t, err) 311 312 // read the file back in using ReadAt into a buffer 313 // this simulates what mount does 314 rd, err := vfs.OpenFile("file1", os.O_RDONLY, 0) 315 require.NoError(t, err) 316 317 buf := make([]byte, 1024) 318 read, err := rd.ReadAt(buf, 0) 319 if err != io.EOF { 320 assert.NoError(t, err) 321 } 322 assert.Equal(t, read, n) 323 assert.Equal(t, contents, buf[:read]) 324 325 err = rd.Close() 326 assert.NoError(t, err) 327 } 328 329 func TestFileReadAtZeroLength(t *testing.T) { 330 testFileReadAt(t, 0) 331 } 332 333 func TestFileReadAtNonZeroLength(t *testing.T) { 334 testFileReadAt(t, 100) 335 }