From a4bc4daf3038ef4afa9f2492fdd495936b7c0f73 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 8 Jan 2020 17:14:35 +0000 Subject: [PATCH] mounttest: fix unreliable tests on Windows CI The failure is this which is not reproducable locally, only on the CI servers. --- FAIL: TestMount/CacheMode=minimal/TestWriteFileOverwrite (1.01s) fs.go:351: Error Trace: fs.go:351 write.go:65 Error: Received unexpected error: open E:testwrite: The request could not be performed because of an I/O device error. Test: TestMount/CacheMode=minimal/TestWriteFileOverwrite The corresponding ERROR from the log is this: ERROR : IO error: truncate C:\Users\runneradmin\AppData\Local\rclone\vfs\local\C\Users\RUNNER~1\AppData\Local\Temp\rclone298719627\testwrite: Access is denied. Instead of using ioutil.WriteFile this fix uses an equivalent based on rclone's lib/file which doesn't set the exclusive flag on Windows. This allows files to be deleted that are open. It also deletes existing files if an error is received and retries. --- cmd/mountlib/mounttest/fs.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/cmd/mountlib/mounttest/fs.go b/cmd/mountlib/mounttest/fs.go index b919042c8..38d7fdc92 100644 --- a/cmd/mountlib/mounttest/fs.go +++ b/cmd/mountlib/mounttest/fs.go @@ -6,6 +6,7 @@ import ( "context" "flag" "fmt" + "io" "io/ioutil" "log" "os" @@ -22,6 +23,7 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/walk" "github.com/rclone/rclone/fstest" + "github.com/rclone/rclone/lib/file" "github.com/rclone/rclone/vfs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -345,9 +347,36 @@ func (r *Run) waitForWriters() { run.vfs.WaitForWriters(10 * time.Second) } +// writeFile writes data to a file named by filename. +// If the file does not exist, WriteFile creates it with permissions perm; +// otherwise writeFile truncates it before writing. +// If there is an error writing then writeFile +// deletes it an existing file and tries again. +func writeFile(filename string, data []byte, perm os.FileMode) error { + f, err := file.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil { + err = os.Remove(filename) + if err != nil { + return err + } + f, err = file.OpenFile(filename, os.O_WRONLY|os.O_CREATE, perm) + if err != nil { + return err + } + } + n, err := f.Write(data) + if err == nil && n < len(data) { + err = io.ErrShortWrite + } + if err1 := f.Close(); err == nil { + err = err1 + } + return err +} + func (r *Run) createFile(t *testing.T, filepath string, contents string) { filepath = r.path(filepath) - err := ioutil.WriteFile(filepath, []byte(contents), 0600) + err := writeFile(filepath, []byte(contents), 0600) require.NoError(t, err) r.waitForWriters() }