github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/moby/registry/resumable/resumablerequestreader_test.go (about) 1 package resumable // import "github.com/docker/docker/registry/resumable" 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "net/http" 8 "net/http/httptest" 9 "strings" 10 "testing" 11 "time" 12 13 "gotest.tools/v3/assert" 14 is "gotest.tools/v3/assert/cmp" 15 ) 16 17 func TestResumableRequestHeaderSimpleErrors(t *testing.T) { 18 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 19 fmt.Fprintln(w, "Hello, world !") 20 })) 21 defer ts.Close() 22 23 client := &http.Client{} 24 25 var req *http.Request 26 req, err := http.NewRequest(http.MethodGet, ts.URL, nil) 27 assert.NilError(t, err) 28 29 resreq := &requestReader{} 30 _, err = resreq.Read([]byte{}) 31 assert.Check(t, is.Error(err, "client and request can't be nil")) 32 33 resreq = &requestReader{ 34 client: client, 35 request: req, 36 totalSize: -1, 37 } 38 _, err = resreq.Read([]byte{}) 39 assert.Check(t, is.Error(err, "failed to auto detect content length")) 40 } 41 42 // Not too much failures, bails out after some wait 43 func TestResumableRequestHeaderNotTooMuchFailures(t *testing.T) { 44 client := &http.Client{} 45 46 var badReq *http.Request 47 badReq, err := http.NewRequest(http.MethodGet, "I'm not an url", nil) 48 assert.NilError(t, err) 49 50 resreq := &requestReader{ 51 client: client, 52 request: badReq, 53 failures: 0, 54 maxFailures: 2, 55 waitDuration: 10 * time.Millisecond, 56 } 57 read, err := resreq.Read([]byte{}) 58 assert.NilError(t, err) 59 assert.Check(t, is.Equal(0, read)) 60 } 61 62 // Too much failures, returns the error 63 func TestResumableRequestHeaderTooMuchFailures(t *testing.T) { 64 client := &http.Client{} 65 66 var badReq *http.Request 67 badReq, err := http.NewRequest(http.MethodGet, "I'm not an url", nil) 68 assert.NilError(t, err) 69 70 resreq := &requestReader{ 71 client: client, 72 request: badReq, 73 failures: 0, 74 maxFailures: 1, 75 } 76 defer resreq.Close() 77 78 read, err := resreq.Read([]byte{}) 79 assert.Assert(t, err != nil) 80 assert.Check(t, is.ErrorContains(err, "unsupported protocol scheme")) 81 assert.Check(t, is.ErrorContains(err, "I%27m%20not%20an%20url")) 82 assert.Check(t, is.Equal(0, read)) 83 } 84 85 type errorReaderCloser struct{} 86 87 func (errorReaderCloser) Close() error { return nil } 88 89 func (errorReaderCloser) Read(p []byte) (n int, err error) { 90 return 0, fmt.Errorf("An error occurred") 91 } 92 93 // If an unknown error is encountered, return 0, nil and log it 94 func TestResumableRequestReaderWithReadError(t *testing.T) { 95 var req *http.Request 96 req, err := http.NewRequest(http.MethodGet, "", nil) 97 assert.NilError(t, err) 98 99 client := &http.Client{} 100 101 response := &http.Response{ 102 Status: "500 Internal Server", 103 StatusCode: http.StatusInternalServerError, 104 ContentLength: 0, 105 Close: true, 106 Body: errorReaderCloser{}, 107 } 108 109 resreq := &requestReader{ 110 client: client, 111 request: req, 112 currentResponse: response, 113 lastRange: 1, 114 totalSize: 1, 115 } 116 defer resreq.Close() 117 118 buf := make([]byte, 1) 119 read, err := resreq.Read(buf) 120 assert.NilError(t, err) 121 122 assert.Check(t, is.Equal(0, read)) 123 } 124 125 func TestResumableRequestReaderWithEOFWith416Response(t *testing.T) { 126 var req *http.Request 127 req, err := http.NewRequest(http.MethodGet, "", nil) 128 assert.NilError(t, err) 129 130 client := &http.Client{} 131 132 response := &http.Response{ 133 Status: "416 Requested Range Not Satisfiable", 134 StatusCode: http.StatusRequestedRangeNotSatisfiable, 135 ContentLength: 0, 136 Close: true, 137 Body: ioutil.NopCloser(strings.NewReader("")), 138 } 139 140 resreq := &requestReader{ 141 client: client, 142 request: req, 143 currentResponse: response, 144 lastRange: 1, 145 totalSize: 1, 146 } 147 defer resreq.Close() 148 149 buf := make([]byte, 1) 150 _, err = resreq.Read(buf) 151 assert.Check(t, is.Error(err, io.EOF.Error())) 152 } 153 154 func TestResumableRequestReaderWithServerDoesntSupportByteRanges(t *testing.T) { 155 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 156 if r.Header.Get("Range") == "" { 157 t.Fatalf("Expected a Range HTTP header, got nothing") 158 } 159 })) 160 defer ts.Close() 161 162 var req *http.Request 163 req, err := http.NewRequest(http.MethodGet, ts.URL, nil) 164 assert.NilError(t, err) 165 166 client := &http.Client{} 167 168 resreq := &requestReader{ 169 client: client, 170 request: req, 171 lastRange: 1, 172 } 173 defer resreq.Close() 174 175 buf := make([]byte, 2) 176 _, err = resreq.Read(buf) 177 assert.Check(t, is.Error(err, "the server doesn't support byte ranges")) 178 } 179 180 func TestResumableRequestReaderWithZeroTotalSize(t *testing.T) { 181 srvtxt := "some response text data" 182 183 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 184 fmt.Fprintln(w, srvtxt) 185 })) 186 defer ts.Close() 187 188 var req *http.Request 189 req, err := http.NewRequest(http.MethodGet, ts.URL, nil) 190 assert.NilError(t, err) 191 192 client := &http.Client{} 193 retries := uint32(5) 194 195 resreq := NewRequestReader(client, req, retries, 0) 196 defer resreq.Close() 197 198 data, err := ioutil.ReadAll(resreq) 199 assert.NilError(t, err) 200 201 resstr := strings.TrimSuffix(string(data), "\n") 202 assert.Check(t, is.Equal(srvtxt, resstr)) 203 } 204 205 func TestResumableRequestReader(t *testing.T) { 206 srvtxt := "some response text data" 207 208 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 209 fmt.Fprintln(w, srvtxt) 210 })) 211 defer ts.Close() 212 213 var req *http.Request 214 req, err := http.NewRequest(http.MethodGet, ts.URL, nil) 215 assert.NilError(t, err) 216 217 client := &http.Client{} 218 retries := uint32(5) 219 imgSize := int64(len(srvtxt)) 220 221 resreq := NewRequestReader(client, req, retries, imgSize) 222 defer resreq.Close() 223 224 data, err := ioutil.ReadAll(resreq) 225 assert.NilError(t, err) 226 227 resstr := strings.TrimSuffix(string(data), "\n") 228 assert.Check(t, is.Equal(srvtxt, resstr)) 229 } 230 231 func TestResumableRequestReaderWithInitialResponse(t *testing.T) { 232 srvtxt := "some response text data" 233 234 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 235 fmt.Fprintln(w, srvtxt) 236 })) 237 defer ts.Close() 238 239 var req *http.Request 240 req, err := http.NewRequest(http.MethodGet, ts.URL, nil) 241 assert.NilError(t, err) 242 243 client := &http.Client{} 244 retries := uint32(5) 245 imgSize := int64(len(srvtxt)) 246 247 res, err := client.Do(req) 248 assert.NilError(t, err) 249 250 resreq := NewRequestReaderWithInitialResponse(client, req, retries, imgSize, res) 251 defer resreq.Close() 252 253 data, err := ioutil.ReadAll(resreq) 254 assert.NilError(t, err) 255 256 resstr := strings.TrimSuffix(string(data), "\n") 257 assert.Check(t, is.Equal(srvtxt, resstr)) 258 }