Implement Repository ServeBlob
Signed-off-by: Damien Mathieu <dmathieu@salesforce.com>master
							parent
							
								
									79f6bcbe16
								
							
						
					
					
						commit
						3800c47fd2
					
				|  | @ -667,7 +667,24 @@ func (bs *blobs) Open(ctx context.Context, dgst digest.Digest) (distribution.Rea | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (bs *blobs) ServeBlob(ctx context.Context, w http.ResponseWriter, r *http.Request, dgst digest.Digest) error { | func (bs *blobs) ServeBlob(ctx context.Context, w http.ResponseWriter, r *http.Request, dgst digest.Digest) error { | ||||||
| 	panic("not implemented") | 	desc, err := bs.statter.Stat(ctx, dgst) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	blob, err := bs.Open(ctx, dgst) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer blob.Close() | ||||||
|  | 
 | ||||||
|  | 	w.Header().Set("Content-Length", strconv.FormatInt(desc.Size, 10)) | ||||||
|  | 	w.Header().Set("Content-Type", desc.MediaType) | ||||||
|  | 	w.Header().Set("Docker-Content-Digest", dgst.String()) | ||||||
|  | 	w.Header().Set("Etag", dgst.String()) | ||||||
|  | 
 | ||||||
|  | 	_, err = io.CopyN(w, blob, desc.Size) | ||||||
|  | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (bs *blobs) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) { | func (bs *blobs) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) { | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
| 	"log" | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -57,6 +58,7 @@ func addTestFetch(repo string, dgst digest.Digest, content []byte, m *testutil.R | ||||||
| 			Body:       content, | 			Body:       content, | ||||||
| 			Headers: http.Header(map[string][]string{ | 			Headers: http.Header(map[string][]string{ | ||||||
| 				"Content-Length": {fmt.Sprint(len(content))}, | 				"Content-Length": {fmt.Sprint(len(content))}, | ||||||
|  | 				"Content-Type":   {"application/octet-stream"}, | ||||||
| 				"Last-Modified":  {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, | 				"Last-Modified":  {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, | ||||||
| 			}), | 			}), | ||||||
| 		}, | 		}, | ||||||
|  | @ -71,6 +73,7 @@ func addTestFetch(repo string, dgst digest.Digest, content []byte, m *testutil.R | ||||||
| 			StatusCode: http.StatusOK, | 			StatusCode: http.StatusOK, | ||||||
| 			Headers: http.Header(map[string][]string{ | 			Headers: http.Header(map[string][]string{ | ||||||
| 				"Content-Length": {fmt.Sprint(len(content))}, | 				"Content-Length": {fmt.Sprint(len(content))}, | ||||||
|  | 				"Content-Type":   {"application/octet-stream"}, | ||||||
| 				"Last-Modified":  {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, | 				"Last-Modified":  {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, | ||||||
| 			}), | 			}), | ||||||
| 		}, | 		}, | ||||||
|  | @ -99,6 +102,56 @@ func addTestCatalog(route string, content []byte, link string, m *testutil.Reque | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestBlobServeBlob(t *testing.T) { | ||||||
|  | 	dgst, blob := newRandomBlob(1024) | ||||||
|  | 	var m testutil.RequestResponseMap | ||||||
|  | 	addTestFetch("test.example.com/repo1", dgst, blob, &m) | ||||||
|  | 
 | ||||||
|  | 	e, c := testServer(m) | ||||||
|  | 	defer c() | ||||||
|  | 
 | ||||||
|  | 	ctx := context.Background() | ||||||
|  | 	repo, _ := reference.WithName("test.example.com/repo1") | ||||||
|  | 	r, err := NewRepository(repo, e, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	l := r.Blobs(ctx) | ||||||
|  | 
 | ||||||
|  | 	resp := httptest.NewRecorder() | ||||||
|  | 	req := httptest.NewRequest("GET", "/", nil) | ||||||
|  | 
 | ||||||
|  | 	err = l.ServeBlob(ctx, resp, req, dgst) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Error serving blob: %s", err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	body, err := ioutil.ReadAll(resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Error reading response body: %s", err.Error()) | ||||||
|  | 	} | ||||||
|  | 	if string(body) != string(blob) { | ||||||
|  | 		t.Errorf("Unexpected response body. Got %q, expected %q", string(body), string(blob)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	expectedHeaders := []struct { | ||||||
|  | 		Name  string | ||||||
|  | 		Value string | ||||||
|  | 	}{ | ||||||
|  | 		{Name: "Content-Length", Value: "1024"}, | ||||||
|  | 		{Name: "Content-Type", Value: "application/octet-stream"}, | ||||||
|  | 		{Name: "Docker-Content-Digest", Value: dgst.String()}, | ||||||
|  | 		{Name: "Etag", Value: dgst.String()}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, h := range expectedHeaders { | ||||||
|  | 		if resp.Header().Get(h.Name) != h.Value { | ||||||
|  | 			t.Errorf("Unexpected %s. Got %s, expected %s", h.Name, resp.Header().Get(h.Name), h.Value) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestBlobDelete(t *testing.T) { | func TestBlobDelete(t *testing.T) { | ||||||
| 	dgst, _ := newRandomBlob(1024) | 	dgst, _ := newRandomBlob(1024) | ||||||
| 	var m testutil.RequestResponseMap | 	var m testutil.RequestResponseMap | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue