github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/cmd/serve/webdav/webdav_test.go (about) 1 // Serve webdav tests set up a server and run the integration tests 2 // for the webdav remote against it. 3 // 4 // We skip tests on platforms with troublesome character mappings 5 6 //+build !windows,!darwin,go1.9 7 8 package webdav 9 10 import ( 11 "context" 12 "flag" 13 "io/ioutil" 14 "net/http" 15 "os" 16 "os/exec" 17 "strings" 18 "testing" 19 "time" 20 21 _ "github.com/ncw/rclone/backend/local" 22 "github.com/ncw/rclone/cmd/serve/httplib" 23 "github.com/ncw/rclone/fs" 24 "github.com/ncw/rclone/fs/filter" 25 "github.com/ncw/rclone/fstest" 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/require" 28 "golang.org/x/net/webdav" 29 ) 30 31 const ( 32 testBindAddress = "localhost:0" 33 ) 34 35 // check interfaces 36 var ( 37 _ os.FileInfo = FileInfo{nil} 38 _ webdav.ETager = FileInfo{nil} 39 _ webdav.ContentTyper = FileInfo{nil} 40 ) 41 42 // TestWebDav runs the webdav server then runs the unit tests for the 43 // webdav remote against it. 44 func TestWebDav(t *testing.T) { 45 opt := httplib.DefaultOpt 46 opt.ListenAddr = testBindAddress 47 48 fstest.Initialise() 49 50 fremote, _, clean, err := fstest.RandomRemote(*fstest.RemoteName, *fstest.SubDir) 51 assert.NoError(t, err) 52 defer clean() 53 54 err = fremote.Mkdir(context.Background(), "") 55 assert.NoError(t, err) 56 57 // Start the server 58 w := newWebDAV(fremote, &opt) 59 assert.NoError(t, w.serve()) 60 defer func() { 61 w.Close() 62 w.Wait() 63 }() 64 65 // Change directory to run the tests 66 err = os.Chdir("../../../backend/webdav") 67 assert.NoError(t, err, "failed to cd to webdav remote") 68 69 // Run the webdav tests with an on the fly remote 70 args := []string{"test"} 71 if testing.Verbose() { 72 args = append(args, "-v") 73 } 74 if *fstest.Verbose { 75 args = append(args, "-verbose") 76 } 77 args = append(args, "-remote", "webdavtest:") 78 cmd := exec.Command("go", args...) 79 cmd.Env = append(os.Environ(), 80 "RCLONE_CONFIG_WEBDAVTEST_TYPE=webdav", 81 "RCLONE_CONFIG_WEBDAVTEST_URL="+w.Server.URL(), 82 "RCLONE_CONFIG_WEBDAVTEST_VENDOR=other", 83 ) 84 out, err := cmd.CombinedOutput() 85 if len(out) != 0 { 86 t.Logf("\n----------\n%s----------\n", string(out)) 87 } 88 assert.NoError(t, err, "Running webdav integration tests") 89 } 90 91 // Test serve http functionality in serve webdav 92 // While similar to http serve, there are some inconsistencies 93 // in the handling of some requests such as POST requests 94 95 var ( 96 updateGolden = flag.Bool("updategolden", false, "update golden files for regression test") 97 ) 98 99 func TestHTTPFunction(t *testing.T) { 100 // cd to correct directory for testing 101 err := os.Chdir("../../cmd/serve/webdav") 102 assert.NoError(t, err, "failed to cd to webdav cmd directory") 103 104 // exclude files called hidden.txt and directories called hidden 105 require.NoError(t, filter.Active.AddRule("- hidden.txt")) 106 require.NoError(t, filter.Active.AddRule("- hidden/**")) 107 108 // Uses the same test files as http tests but with different golden. 109 f, err := fs.NewFs("../http/testdata/files") 110 assert.NoError(t, err) 111 112 opt := httplib.DefaultOpt 113 opt.ListenAddr = testBindAddress 114 115 // Start the server 116 w := newWebDAV(f, &opt) 117 assert.NoError(t, w.serve()) 118 defer func() { 119 w.Close() 120 w.Wait() 121 }() 122 testURL := w.Server.URL() 123 pause := time.Millisecond 124 i := 0 125 for ; i < 10; i++ { 126 resp, err := http.Head(testURL) 127 if err == nil { 128 _ = resp.Body.Close() 129 break 130 } 131 // t.Logf("couldn't connect, sleeping for %v: %v", pause, err) 132 time.Sleep(pause) 133 pause *= 2 134 } 135 if i >= 10 { 136 t.Fatal("couldn't connect to server") 137 } 138 139 HelpTestGET(t, testURL) 140 } 141 142 // check body against the file, or re-write body if -updategolden is 143 // set. 144 func checkGolden(t *testing.T, fileName string, got []byte) { 145 if *updateGolden { 146 t.Logf("Updating golden file %q", fileName) 147 err := ioutil.WriteFile(fileName, got, 0666) 148 require.NoError(t, err) 149 } else { 150 want, err := ioutil.ReadFile(fileName) 151 require.NoError(t, err, "problem") 152 wants := strings.Split(string(want), "\n") 153 gots := strings.Split(string(got), "\n") 154 assert.Equal(t, wants, gots, fileName) 155 } 156 } 157 158 func HelpTestGET(t *testing.T, testURL string) { 159 for _, test := range []struct { 160 URL string 161 Status int 162 Golden string 163 Method string 164 Range string 165 }{ 166 { 167 URL: "", 168 Status: http.StatusOK, 169 Golden: "testdata/golden/index.html", 170 }, 171 { 172 URL: "notfound", 173 Status: http.StatusNotFound, 174 Golden: "testdata/golden/notfound.html", 175 }, 176 { 177 URL: "dirnotfound/", 178 Status: http.StatusNotFound, 179 Golden: "testdata/golden/dirnotfound.html", 180 }, 181 { 182 URL: "hidden/", 183 Status: http.StatusNotFound, 184 Golden: "testdata/golden/hiddendir.html", 185 }, 186 { 187 URL: "one%25.txt", 188 Status: http.StatusOK, 189 Golden: "testdata/golden/one.txt", 190 }, 191 { 192 URL: "hidden.txt", 193 Status: http.StatusNotFound, 194 Golden: "testdata/golden/hidden.txt", 195 }, 196 { 197 URL: "three/", 198 Status: http.StatusOK, 199 Golden: "testdata/golden/three.html", 200 }, 201 { 202 URL: "three/a.txt", 203 Status: http.StatusOK, 204 Golden: "testdata/golden/a.txt", 205 }, 206 { 207 URL: "", 208 Method: "HEAD", 209 Status: http.StatusOK, 210 Golden: "testdata/golden/indexhead.txt", 211 }, 212 { 213 URL: "one%25.txt", 214 Method: "HEAD", 215 Status: http.StatusOK, 216 Golden: "testdata/golden/onehead.txt", 217 }, 218 { 219 URL: "", 220 Method: "POST", 221 Status: http.StatusMethodNotAllowed, 222 Golden: "testdata/golden/indexpost.txt", 223 }, 224 { 225 URL: "one%25.txt", 226 Method: "POST", 227 Status: http.StatusOK, 228 Golden: "testdata/golden/onepost.txt", 229 }, 230 { 231 URL: "two.txt", 232 Status: http.StatusOK, 233 Golden: "testdata/golden/two.txt", 234 }, 235 { 236 URL: "two.txt", 237 Status: http.StatusPartialContent, 238 Range: "bytes=2-5", 239 Golden: "testdata/golden/two2-5.txt", 240 }, 241 { 242 URL: "two.txt", 243 Status: http.StatusPartialContent, 244 Range: "bytes=0-6", 245 Golden: "testdata/golden/two-6.txt", 246 }, 247 { 248 URL: "two.txt", 249 Status: http.StatusPartialContent, 250 Range: "bytes=3-", 251 Golden: "testdata/golden/two3-.txt", 252 }, 253 } { 254 method := test.Method 255 if method == "" { 256 method = "GET" 257 } 258 req, err := http.NewRequest(method, testURL+test.URL, nil) 259 require.NoError(t, err) 260 if test.Range != "" { 261 req.Header.Add("Range", test.Range) 262 } 263 resp, err := http.DefaultClient.Do(req) 264 require.NoError(t, err) 265 assert.Equal(t, test.Status, resp.StatusCode, test.Golden) 266 body, err := ioutil.ReadAll(resp.Body) 267 require.NoError(t, err) 268 269 checkGolden(t, test.Golden, body) 270 } 271 }