0e1b1cc04e
These methods rely on an ObjectStore interface, which is meant to approximate the storage behavior of the docker engine. This is very much subject to change.
239 lines
5.2 KiB
Go
239 lines
5.2 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/docker/docker-registry"
|
|
"github.com/docker/docker-registry/test"
|
|
)
|
|
|
|
type testLayer struct {
|
|
tarSum string
|
|
contents []byte
|
|
}
|
|
|
|
func TestPush(t *testing.T) {
|
|
name := "hello/world"
|
|
tag := "sometag"
|
|
testLayers := []testLayer{
|
|
{
|
|
tarSum: "12345",
|
|
contents: []byte("some contents"),
|
|
},
|
|
{
|
|
tarSum: "98765",
|
|
contents: []byte("some other contents"),
|
|
},
|
|
}
|
|
uploadLocations := make([]string, len(testLayers))
|
|
layers := make([]registry.FSLayer, len(testLayers))
|
|
history := make([]registry.ManifestHistory, len(testLayers))
|
|
|
|
for i, layer := range testLayers {
|
|
uploadLocations[i] = fmt.Sprintf("/v2/%s/layer/%s/upload-location-%d", name, layer.tarSum, i)
|
|
layers[i] = registry.FSLayer{BlobSum: layer.tarSum}
|
|
history[i] = registry.ManifestHistory{V1Compatibility: layer.tarSum}
|
|
}
|
|
|
|
manifest := ®istry.ImageManifest{
|
|
Name: name,
|
|
Tag: tag,
|
|
Architecture: "x86",
|
|
FSLayers: layers,
|
|
History: history,
|
|
SchemaVersion: 1,
|
|
}
|
|
manifestBytes, err := json.Marshal(manifest)
|
|
|
|
layerRequestResponseMappings := make([]test.RequestResponseMapping, 2*len(testLayers))
|
|
for i, layer := range testLayers {
|
|
layerRequestResponseMappings[2*i] = test.RequestResponseMapping{
|
|
Request: test.Request{
|
|
Method: "POST",
|
|
Route: "/v2/" + name + "/layer/" + layer.tarSum + "/upload/",
|
|
},
|
|
Responses: []test.Response{
|
|
{
|
|
StatusCode: http.StatusAccepted,
|
|
Headers: http.Header(map[string][]string{
|
|
"Location": {uploadLocations[i]},
|
|
}),
|
|
},
|
|
},
|
|
}
|
|
layerRequestResponseMappings[2*i+1] = test.RequestResponseMapping{
|
|
Request: test.Request{
|
|
Method: "PUT",
|
|
Route: uploadLocations[i],
|
|
Body: layer.contents,
|
|
},
|
|
Responses: []test.Response{
|
|
{
|
|
StatusCode: http.StatusCreated,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
handler := test.NewHandler(append(layerRequestResponseMappings, test.RequestResponseMap{
|
|
test.RequestResponseMapping{
|
|
Request: test.Request{
|
|
Method: "PUT",
|
|
Route: "/v2/" + name + "/image/" + tag,
|
|
Body: manifestBytes,
|
|
},
|
|
Responses: []test.Response{
|
|
{
|
|
StatusCode: http.StatusOK,
|
|
},
|
|
},
|
|
},
|
|
}...))
|
|
server := httptest.NewServer(handler)
|
|
client := New(server.URL)
|
|
objectStore := &memoryObjectStore{
|
|
mutex: new(sync.Mutex),
|
|
manifestStorage: make(map[string]*registry.ImageManifest),
|
|
layerStorage: make(map[string]Layer),
|
|
}
|
|
|
|
for _, layer := range testLayers {
|
|
l, err := objectStore.Layer(layer.tarSum)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
writer, err := l.Writer()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
writer.Write(layer.contents)
|
|
writer.Close()
|
|
}
|
|
|
|
objectStore.WriteManifest(name, tag, manifest)
|
|
|
|
err = Push(client, objectStore, name, tag)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestPull(t *testing.T) {
|
|
name := "hello/world"
|
|
tag := "sometag"
|
|
testLayers := []testLayer{
|
|
{
|
|
tarSum: "12345",
|
|
contents: []byte("some contents"),
|
|
},
|
|
{
|
|
tarSum: "98765",
|
|
contents: []byte("some other contents"),
|
|
},
|
|
}
|
|
layers := make([]registry.FSLayer, len(testLayers))
|
|
history := make([]registry.ManifestHistory, len(testLayers))
|
|
|
|
for i, layer := range testLayers {
|
|
layers[i] = registry.FSLayer{BlobSum: layer.tarSum}
|
|
history[i] = registry.ManifestHistory{V1Compatibility: layer.tarSum}
|
|
}
|
|
|
|
manifest := ®istry.ImageManifest{
|
|
Name: name,
|
|
Tag: tag,
|
|
Architecture: "x86",
|
|
FSLayers: layers,
|
|
History: history,
|
|
SchemaVersion: 1,
|
|
}
|
|
manifestBytes, err := json.Marshal(manifest)
|
|
|
|
layerRequestResponseMappings := make([]test.RequestResponseMapping, len(testLayers))
|
|
for i, layer := range testLayers {
|
|
layerRequestResponseMappings[i] = test.RequestResponseMapping{
|
|
Request: test.Request{
|
|
Method: "GET",
|
|
Route: "/v2/" + name + "/layer/" + layer.tarSum,
|
|
},
|
|
Responses: []test.Response{
|
|
{
|
|
StatusCode: http.StatusOK,
|
|
Body: layer.contents,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
handler := test.NewHandler(append(layerRequestResponseMappings, test.RequestResponseMap{
|
|
test.RequestResponseMapping{
|
|
Request: test.Request{
|
|
Method: "GET",
|
|
Route: "/v2/" + name + "/image/" + tag,
|
|
},
|
|
Responses: []test.Response{
|
|
{
|
|
StatusCode: http.StatusOK,
|
|
Body: manifestBytes,
|
|
},
|
|
},
|
|
},
|
|
}...))
|
|
server := httptest.NewServer(handler)
|
|
client := New(server.URL)
|
|
objectStore := &memoryObjectStore{
|
|
mutex: new(sync.Mutex),
|
|
manifestStorage: make(map[string]*registry.ImageManifest),
|
|
layerStorage: make(map[string]Layer),
|
|
}
|
|
|
|
err = Pull(client, objectStore, name, tag)
|
|
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 _, layer := range testLayers {
|
|
l, err := objectStore.Layer(layer.tarSum)
|
|
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(layer.contents) {
|
|
t.Fatal("Incorrect layer")
|
|
}
|
|
}
|
|
}
|