github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/cmd/serve/restic/restic_appendonly_test.go (about) 1 // +build go1.9 2 3 package restic 4 5 import ( 6 "crypto/rand" 7 "encoding/hex" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "os" 12 "strings" 13 "testing" 14 15 "github.com/ncw/rclone/cmd" 16 "github.com/ncw/rclone/cmd/serve/httplib/httpflags" 17 "github.com/stretchr/testify/require" 18 ) 19 20 // createOverwriteDeleteSeq returns a sequence which will create a new file at 21 // path, and then try to overwrite and delete it. 22 func createOverwriteDeleteSeq(t testing.TB, path string) []TestRequest { 23 // add a file, try to overwrite and delete it 24 req := []TestRequest{ 25 { 26 req: newRequest(t, "GET", path, nil), 27 want: []wantFunc{wantCode(http.StatusNotFound)}, 28 }, 29 { 30 req: newRequest(t, "POST", path, strings.NewReader("foobar test config")), 31 want: []wantFunc{wantCode(http.StatusOK)}, 32 }, 33 { 34 req: newRequest(t, "GET", path, nil), 35 want: []wantFunc{ 36 wantCode(http.StatusOK), 37 wantBody("foobar test config"), 38 }, 39 }, 40 { 41 req: newRequest(t, "POST", path, strings.NewReader("other config")), 42 want: []wantFunc{wantCode(http.StatusForbidden)}, 43 }, 44 { 45 req: newRequest(t, "GET", path, nil), 46 want: []wantFunc{ 47 wantCode(http.StatusOK), 48 wantBody("foobar test config"), 49 }, 50 }, 51 { 52 req: newRequest(t, "DELETE", path, nil), 53 want: []wantFunc{wantCode(http.StatusForbidden)}, 54 }, 55 { 56 req: newRequest(t, "GET", path, nil), 57 want: []wantFunc{ 58 wantCode(http.StatusOK), 59 wantBody("foobar test config"), 60 }, 61 }, 62 } 63 return req 64 } 65 66 // TestResticHandler runs tests on the restic handler code, especially in append-only mode. 67 func TestResticHandler(t *testing.T) { 68 buf := make([]byte, 32) 69 _, err := io.ReadFull(rand.Reader, buf) 70 require.NoError(t, err) 71 randomID := hex.EncodeToString(buf) 72 73 var tests = []struct { 74 seq []TestRequest 75 }{ 76 {createOverwriteDeleteSeq(t, "/config")}, 77 {createOverwriteDeleteSeq(t, "/data/"+randomID)}, 78 { 79 // ensure we can add and remove lock files 80 []TestRequest{ 81 { 82 req: newRequest(t, "GET", "/locks/"+randomID, nil), 83 want: []wantFunc{wantCode(http.StatusNotFound)}, 84 }, 85 { 86 req: newRequest(t, "POST", "/locks/"+randomID, strings.NewReader("lock file")), 87 want: []wantFunc{wantCode(http.StatusOK)}, 88 }, 89 { 90 req: newRequest(t, "GET", "/locks/"+randomID, nil), 91 want: []wantFunc{ 92 wantCode(http.StatusOK), 93 wantBody("lock file"), 94 }, 95 }, 96 { 97 req: newRequest(t, "POST", "/locks/"+randomID, strings.NewReader("other lock file")), 98 want: []wantFunc{wantCode(http.StatusForbidden)}, 99 }, 100 { 101 req: newRequest(t, "DELETE", "/locks/"+randomID, nil), 102 want: []wantFunc{wantCode(http.StatusOK)}, 103 }, 104 { 105 req: newRequest(t, "GET", "/locks/"+randomID, nil), 106 want: []wantFunc{wantCode(http.StatusNotFound)}, 107 }, 108 }, 109 }, 110 } 111 112 // setup rclone with a local backend in a temporary directory 113 tempdir, err := ioutil.TempDir("", "rclone-restic-test-") 114 require.NoError(t, err) 115 116 // make sure the tempdir is properly removed 117 defer func() { 118 err := os.RemoveAll(tempdir) 119 require.NoError(t, err) 120 }() 121 122 // globally set append-only mode 123 prev := appendOnly 124 appendOnly = true 125 defer func() { 126 appendOnly = prev // reset when done 127 }() 128 129 // make a new file system in the temp dir 130 f := cmd.NewFsSrc([]string{tempdir}) 131 srv := newServer(f, &httpflags.Opt) 132 133 // create the repo 134 checkRequest(t, srv.handler, 135 newRequest(t, "POST", "/?create=true", nil), 136 []wantFunc{wantCode(http.StatusOK)}) 137 138 for _, test := range tests { 139 t.Run("", func(t *testing.T) { 140 for i, seq := range test.seq { 141 t.Logf("request %v: %v %v", i, seq.req.Method, seq.req.URL.Path) 142 checkRequest(t, srv.handler, seq.req, seq.want) 143 } 144 }) 145 } 146 }