github.com/npaton/distribution@v2.3.1-rc.0+incompatible/manifest/schema1/config_builder_test.go (about)

     1  package schema1
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"io"
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/docker/distribution"
    11  	"github.com/docker/distribution/context"
    12  	"github.com/docker/distribution/digest"
    13  	"github.com/docker/distribution/reference"
    14  	"github.com/docker/libtrust"
    15  )
    16  
    17  type mockBlobService struct {
    18  	descriptors map[digest.Digest]distribution.Descriptor
    19  }
    20  
    21  func (bs *mockBlobService) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
    22  	if descriptor, ok := bs.descriptors[dgst]; ok {
    23  		return descriptor, nil
    24  	}
    25  	return distribution.Descriptor{}, distribution.ErrBlobUnknown
    26  }
    27  
    28  func (bs *mockBlobService) Get(ctx context.Context, dgst digest.Digest) ([]byte, error) {
    29  	panic("not implemented")
    30  }
    31  
    32  func (bs *mockBlobService) Open(ctx context.Context, dgst digest.Digest) (distribution.ReadSeekCloser, error) {
    33  	panic("not implemented")
    34  }
    35  
    36  func (bs *mockBlobService) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) {
    37  	d := distribution.Descriptor{
    38  		Digest:    digest.FromBytes(p),
    39  		Size:      int64(len(p)),
    40  		MediaType: mediaType,
    41  	}
    42  	bs.descriptors[d.Digest] = d
    43  	return d, nil
    44  }
    45  
    46  func (bs *mockBlobService) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
    47  	panic("not implemented")
    48  }
    49  
    50  func (bs *mockBlobService) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) {
    51  	panic("not implemented")
    52  }
    53  
    54  func TestEmptyTar(t *testing.T) {
    55  	// Confirm that gzippedEmptyTar expands to 1024 NULL bytes.
    56  	var decompressed [2048]byte
    57  	gzipReader, err := gzip.NewReader(bytes.NewReader(gzippedEmptyTar))
    58  	if err != nil {
    59  		t.Fatalf("NewReader returned error: %v", err)
    60  	}
    61  	n, err := gzipReader.Read(decompressed[:])
    62  	if n != 1024 {
    63  		t.Fatalf("read returned %d bytes; expected 1024", n)
    64  	}
    65  	n, err = gzipReader.Read(decompressed[1024:])
    66  	if n != 0 {
    67  		t.Fatalf("read returned %d bytes; expected 0", n)
    68  	}
    69  	if err != io.EOF {
    70  		t.Fatal("read did not return io.EOF")
    71  	}
    72  	gzipReader.Close()
    73  	for _, b := range decompressed[:1024] {
    74  		if b != 0 {
    75  			t.Fatal("nonzero byte in decompressed tar")
    76  		}
    77  	}
    78  
    79  	// Confirm that digestSHA256EmptyTar is the digest of gzippedEmptyTar.
    80  	dgst := digest.FromBytes(gzippedEmptyTar)
    81  	if dgst != digestSHA256GzippedEmptyTar {
    82  		t.Fatalf("digest mismatch for empty tar: expected %s got %s", digestSHA256GzippedEmptyTar, dgst)
    83  	}
    84  }
    85  
    86  func TestConfigBuilder(t *testing.T) {
    87  	imgJSON := `{
    88      "architecture": "amd64",
    89      "config": {
    90          "AttachStderr": false,
    91          "AttachStdin": false,
    92          "AttachStdout": false,
    93          "Cmd": [
    94              "/bin/sh",
    95              "-c",
    96              "echo hi"
    97          ],
    98          "Domainname": "",
    99          "Entrypoint": null,
   100          "Env": [
   101              "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
   102              "derived=true",
   103              "asdf=true"
   104          ],
   105          "Hostname": "23304fc829f9",
   106          "Image": "sha256:4ab15c48b859c2920dd5224f92aabcd39a52794c5b3cf088fb3bbb438756c246",
   107          "Labels": {},
   108          "OnBuild": [],
   109          "OpenStdin": false,
   110          "StdinOnce": false,
   111          "Tty": false,
   112          "User": "",
   113          "Volumes": null,
   114          "WorkingDir": ""
   115      },
   116      "container": "e91032eb0403a61bfe085ff5a5a48e3659e5a6deae9f4d678daa2ae399d5a001",
   117      "container_config": {
   118          "AttachStderr": false,
   119          "AttachStdin": false,
   120          "AttachStdout": false,
   121          "Cmd": [
   122              "/bin/sh",
   123              "-c",
   124              "#(nop) CMD [\"/bin/sh\" \"-c\" \"echo hi\"]"
   125          ],
   126          "Domainname": "",
   127          "Entrypoint": null,
   128          "Env": [
   129              "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
   130              "derived=true",
   131              "asdf=true"
   132          ],
   133          "Hostname": "23304fc829f9",
   134          "Image": "sha256:4ab15c48b859c2920dd5224f92aabcd39a52794c5b3cf088fb3bbb438756c246",
   135          "Labels": {},
   136          "OnBuild": [],
   137          "OpenStdin": false,
   138          "StdinOnce": false,
   139          "Tty": false,
   140          "User": "",
   141          "Volumes": null,
   142          "WorkingDir": ""
   143      },
   144      "created": "2015-11-04T23:06:32.365666163Z",
   145      "docker_version": "1.9.0-dev",
   146      "history": [
   147          {
   148              "created": "2015-10-31T22:22:54.690851953Z",
   149              "created_by": "/bin/sh -c #(nop) ADD file:a3bc1e842b69636f9df5256c49c5374fb4eef1e281fe3f282c65fb853ee171c5 in /"
   150          },
   151          {
   152              "created": "2015-10-31T22:22:55.613815829Z",
   153              "created_by": "/bin/sh -c #(nop) CMD [\"sh\"]"
   154          },
   155          {
   156              "created": "2015-11-04T23:06:30.934316144Z",
   157              "created_by": "/bin/sh -c #(nop) ENV derived=true",
   158              "empty_layer": true
   159          },
   160          {
   161              "created": "2015-11-04T23:06:31.192097572Z",
   162              "created_by": "/bin/sh -c #(nop) ENV asdf=true",
   163              "empty_layer": true
   164          },
   165          {
   166              "created": "2015-11-04T23:06:32.083868454Z",
   167              "created_by": "/bin/sh -c dd if=/dev/zero of=/file bs=1024 count=1024"
   168          },
   169          {
   170              "created": "2015-11-04T23:06:32.365666163Z",
   171              "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\" \"-c\" \"echo hi\"]",
   172              "empty_layer": true
   173          }
   174      ],
   175      "os": "linux",
   176      "rootfs": {
   177          "diff_ids": [
   178              "sha256:c6f988f4874bb0add23a778f753c65efe992244e148a1d2ec2a8b664fb66bbd1",
   179              "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
   180              "sha256:13f53e08df5a220ab6d13c58b2bf83a59cbdc2e04d0a3f041ddf4b0ba4112d49"
   181          ],
   182          "type": "layers"
   183      }
   184  }`
   185  
   186  	descriptors := []distribution.Descriptor{
   187  		{Digest: digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")},
   188  		{Digest: digest.Digest("sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa")},
   189  		{Digest: digest.Digest("sha256:b4ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")},
   190  	}
   191  
   192  	pk, err := libtrust.GenerateECP256PrivateKey()
   193  	if err != nil {
   194  		t.Fatalf("could not generate key for testing: %v", err)
   195  	}
   196  
   197  	bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)}
   198  
   199  	ref, err := reference.ParseNamed("testrepo:testtag")
   200  	if err != nil {
   201  		t.Fatalf("could not parse reference: %v", err)
   202  	}
   203  
   204  	builder := NewConfigManifestBuilder(bs, pk, ref, []byte(imgJSON))
   205  
   206  	for _, d := range descriptors {
   207  		if err := builder.AppendReference(d); err != nil {
   208  			t.Fatalf("AppendReference returned error: %v", err)
   209  		}
   210  	}
   211  
   212  	signed, err := builder.Build(context.Background())
   213  	if err != nil {
   214  		t.Fatalf("Build returned error: %v", err)
   215  	}
   216  
   217  	// Check that the gzipped empty layer tar was put in the blob store
   218  	_, err = bs.Stat(context.Background(), digestSHA256GzippedEmptyTar)
   219  	if err != nil {
   220  		t.Fatal("gzipped empty tar was not put in the blob store")
   221  	}
   222  
   223  	manifest := signed.(*SignedManifest).Manifest
   224  
   225  	if manifest.Versioned.SchemaVersion != 1 {
   226  		t.Fatal("SchemaVersion != 1")
   227  	}
   228  	if manifest.Name != "testrepo" {
   229  		t.Fatal("incorrect name in manifest")
   230  	}
   231  	if manifest.Tag != "testtag" {
   232  		t.Fatal("incorrect tag in manifest")
   233  	}
   234  	if manifest.Architecture != "amd64" {
   235  		t.Fatal("incorrect arch in manifest")
   236  	}
   237  
   238  	expectedFSLayers := []FSLayer{
   239  		{BlobSum: digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")},
   240  		{BlobSum: digest.Digest("sha256:b4ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")},
   241  		{BlobSum: digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")},
   242  		{BlobSum: digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")},
   243  		{BlobSum: digest.Digest("sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa")},
   244  		{BlobSum: digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")},
   245  	}
   246  
   247  	if len(manifest.FSLayers) != len(expectedFSLayers) {
   248  		t.Fatalf("wrong number of FSLayers: %d", len(manifest.FSLayers))
   249  	}
   250  	if !reflect.DeepEqual(manifest.FSLayers, expectedFSLayers) {
   251  		t.Fatal("wrong FSLayers list")
   252  	}
   253  
   254  	expectedV1Compatibility := []string{
   255  		`{"architecture":"amd64","config":{"AttachStderr":false,"AttachStdin":false,"AttachStdout":false,"Cmd":["/bin/sh","-c","echo hi"],"Domainname":"","Entrypoint":null,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","derived=true","asdf=true"],"Hostname":"23304fc829f9","Image":"sha256:4ab15c48b859c2920dd5224f92aabcd39a52794c5b3cf088fb3bbb438756c246","Labels":{},"OnBuild":[],"OpenStdin":false,"StdinOnce":false,"Tty":false,"User":"","Volumes":null,"WorkingDir":""},"container":"e91032eb0403a61bfe085ff5a5a48e3659e5a6deae9f4d678daa2ae399d5a001","container_config":{"AttachStderr":false,"AttachStdin":false,"AttachStdout":false,"Cmd":["/bin/sh","-c","#(nop) CMD [\"/bin/sh\" \"-c\" \"echo hi\"]"],"Domainname":"","Entrypoint":null,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","derived=true","asdf=true"],"Hostname":"23304fc829f9","Image":"sha256:4ab15c48b859c2920dd5224f92aabcd39a52794c5b3cf088fb3bbb438756c246","Labels":{},"OnBuild":[],"OpenStdin":false,"StdinOnce":false,"Tty":false,"User":"","Volumes":null,"WorkingDir":""},"created":"2015-11-04T23:06:32.365666163Z","docker_version":"1.9.0-dev","id":"0850bfdeb7b060b1004a09099846c2f023a3f2ecbf33f56b4774384b00ce0323","os":"linux","parent":"74cf9c92699240efdba1903c2748ef57105d5bedc588084c4e88f3bb1c3ef0b0","throwaway":true}`,
   256  		`{"id":"74cf9c92699240efdba1903c2748ef57105d5bedc588084c4e88f3bb1c3ef0b0","parent":"178be37afc7c49e951abd75525dbe0871b62ad49402f037164ee6314f754599d","created":"2015-11-04T23:06:32.083868454Z","container_config":{"Cmd":["/bin/sh -c dd if=/dev/zero of=/file bs=1024 count=1024"]}}`,
   257  		`{"id":"178be37afc7c49e951abd75525dbe0871b62ad49402f037164ee6314f754599d","parent":"b449305a55a283538c4574856a8b701f2a3d5ec08ef8aec47f385f20339a4866","created":"2015-11-04T23:06:31.192097572Z","container_config":{"Cmd":["/bin/sh -c #(nop) ENV asdf=true"]},"throwaway":true}`,
   258  		`{"id":"b449305a55a283538c4574856a8b701f2a3d5ec08ef8aec47f385f20339a4866","parent":"9e3447ca24cb96d86ebd5960cb34d1299b07e0a0e03801d90b9969a2c187dd6e","created":"2015-11-04T23:06:30.934316144Z","container_config":{"Cmd":["/bin/sh -c #(nop) ENV derived=true"]},"throwaway":true}`,
   259  		`{"id":"9e3447ca24cb96d86ebd5960cb34d1299b07e0a0e03801d90b9969a2c187dd6e","parent":"3690474eb5b4b26fdfbd89c6e159e8cc376ca76ef48032a30fa6aafd56337880","created":"2015-10-31T22:22:55.613815829Z","container_config":{"Cmd":["/bin/sh -c #(nop) CMD [\"sh\"]"]}}`,
   260  		`{"id":"3690474eb5b4b26fdfbd89c6e159e8cc376ca76ef48032a30fa6aafd56337880","created":"2015-10-31T22:22:54.690851953Z","container_config":{"Cmd":["/bin/sh -c #(nop) ADD file:a3bc1e842b69636f9df5256c49c5374fb4eef1e281fe3f282c65fb853ee171c5 in /"]}}`,
   261  	}
   262  
   263  	if len(manifest.History) != len(expectedV1Compatibility) {
   264  		t.Fatalf("wrong number of history entries: %d", len(manifest.History))
   265  	}
   266  	for i := range expectedV1Compatibility {
   267  		if manifest.History[i].V1Compatibility != expectedV1Compatibility[i] {
   268  			t.Errorf("wrong V1Compatibility %d. expected:\n%s\ngot:\n%s", i, expectedV1Compatibility[i], manifest.History[i].V1Compatibility)
   269  		}
   270  	}
   271  }