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