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