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