Allows layers to be partially pulled and resumed

Adds a sort of contrived test for resumable pulls
This commit is contained in:
Brian Bland 2014-11-18 15:44:39 -08:00
parent 73d6e8af84
commit 50d64ac63a
4 changed files with 271 additions and 59 deletions

View file

@ -117,6 +117,7 @@ func TestPush(t *testing.T) {
t.Fatal(err)
}
writer.SetSize(len(blob.contents))
writer.Write(blob.contents)
writer.Close()
}
@ -235,3 +236,133 @@ func TestPull(t *testing.T) {
}
}
}
func TestPullResume(t *testing.T) {
name := "hello/world"
tag := "sometag"
testBlobs := []testBlob{
{
digest: "12345",
contents: []byte("some contents"),
},
{
digest: "98765",
contents: []byte("some other contents"),
},
}
layers := make([]registry.FSLayer, len(testBlobs))
history := make([]registry.ManifestHistory, len(testBlobs))
for i, layer := range testBlobs {
layers[i] = registry.FSLayer{BlobSum: layer.digest}
history[i] = registry.ManifestHistory{V1Compatibility: layer.digest.String()}
}
manifest := &registry.ImageManifest{
Name: name,
Tag: tag,
Architecture: "x86",
FSLayers: layers,
History: history,
SchemaVersion: 1,
}
manifestBytes, err := json.Marshal(manifest)
layerRequestResponseMappings := make([]testutil.RequestResponseMapping, 2*len(testBlobs))
for i, blob := range testBlobs {
layerRequestResponseMappings[2*i] = testutil.RequestResponseMapping{
Request: testutil.Request{
Method: "GET",
Route: "/v2/" + name + "/blob/" + blob.digest.String(),
},
Response: testutil.Response{
StatusCode: http.StatusOK,
Body: blob.contents[:len(blob.contents)/2],
Headers: http.Header(map[string][]string{
"Content-Length": {fmt.Sprint(len(blob.contents))},
}),
},
}
layerRequestResponseMappings[2*i+1] = testutil.RequestResponseMapping{
Request: testutil.Request{
Method: "GET",
Route: "/v2/" + name + "/blob/" + blob.digest.String(),
},
Response: testutil.Response{
StatusCode: http.StatusOK,
Body: blob.contents[len(blob.contents)/2:],
},
}
}
for i := 0; i < 3; i++ {
layerRequestResponseMappings = append(layerRequestResponseMappings, testutil.RequestResponseMap{
testutil.RequestResponseMapping{
Request: testutil.Request{
Method: "GET",
Route: "/v2/" + name + "/manifest/" + tag,
},
Response: testutil.Response{
StatusCode: http.StatusOK,
Body: manifestBytes,
},
},
}...)
}
handler := testutil.NewHandler(layerRequestResponseMappings)
server := httptest.NewServer(handler)
client := New(server.URL)
objectStore := &memoryObjectStore{
mutex: new(sync.Mutex),
manifestStorage: make(map[string]*registry.ImageManifest),
layerStorage: make(map[digest.Digest]Layer),
}
for attempts := 0; attempts < 3; attempts++ {
err = Pull(client, objectStore, name, tag)
if err == nil {
break
}
}
if err != nil {
t.Fatal(err)
}
m, err := objectStore.Manifest(name, tag)
if err != nil {
t.Fatal(err)
}
mBytes, err := json.Marshal(m)
if err != nil {
t.Fatal(err)
}
if string(mBytes) != string(manifestBytes) {
t.Fatal("Incorrect manifest")
}
for _, blob := range testBlobs {
l, err := objectStore.Layer(blob.digest)
if err != nil {
t.Fatal(err)
}
reader, err := l.Reader()
if err != nil {
t.Fatal(err)
}
defer reader.Close()
layerBytes, err := ioutil.ReadAll(reader)
if err != nil {
t.Fatal(err)
}
if string(layerBytes) != string(blob.contents) {
t.Fatal("Incorrect blob")
}
}
}