2015-07-10 18:36:04 +00:00
package reference
2015-09-08 23:00:48 +00:00
import (
2016-12-16 06:38:38 +00:00
_ "crypto/sha256"
_ "crypto/sha512"
2015-09-30 22:36:19 +00:00
"encoding/json"
2015-09-08 23:00:48 +00:00
"strings"
"testing"
2015-07-10 18:36:04 +00:00
2016-12-17 00:28:34 +00:00
"github.com/opencontainers/go-digest"
2015-09-08 23:00:48 +00:00
)
func TestReferenceParse ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
// tests is a unified set of testcases for
2015-09-08 23:00:48 +00:00
// testing the parsing of references
2023-04-30 12:48:09 +00:00
tests := [ ] struct {
2015-09-08 23:00:48 +00:00
// input is the repository name or name component testcase
input string
// err is the error expected from Parse, or nil
err error
// repository is the string representation for the reference
repository string
2016-06-09 18:32:23 +00:00
// domain is the domain expected in the reference
domain string
2015-09-08 23:00:48 +00:00
// tag is the tag for the reference
tag string
// digest is the digest for the reference (enforces digest reference)
digest string
} {
{
input : "test_com" ,
repository : "test_com" ,
} ,
{
input : "test.com:tag" ,
repository : "test.com" ,
tag : "tag" ,
} ,
{
input : "test.com:5000" ,
repository : "test.com" ,
tag : "5000" ,
} ,
{
input : "test.com/repo:tag" ,
2016-06-09 18:32:23 +00:00
domain : "test.com" ,
2015-09-08 23:00:48 +00:00
repository : "test.com/repo" ,
tag : "tag" ,
} ,
{
input : "test:5000/repo" ,
2016-06-09 18:32:23 +00:00
domain : "test:5000" ,
2015-09-08 23:00:48 +00:00
repository : "test:5000/repo" ,
} ,
{
input : "test:5000/repo:tag" ,
2016-06-09 18:32:23 +00:00
domain : "test:5000" ,
2015-09-08 23:00:48 +00:00
repository : "test:5000/repo" ,
tag : "tag" ,
} ,
{
input : "test:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
2016-06-09 18:32:23 +00:00
domain : "test:5000" ,
2015-09-08 23:00:48 +00:00
repository : "test:5000/repo" ,
digest : "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
} ,
{
input : "test:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
2016-06-09 18:32:23 +00:00
domain : "test:5000" ,
2015-09-08 23:00:48 +00:00
repository : "test:5000/repo" ,
tag : "tag" ,
digest : "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
} ,
{
input : "test:5000/repo" ,
2016-06-09 18:32:23 +00:00
domain : "test:5000" ,
2015-09-08 23:00:48 +00:00
repository : "test:5000/repo" ,
} ,
{
input : "" ,
err : ErrNameEmpty ,
} ,
{
input : ":justtag" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : "@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
err : ErrReferenceInvalidFormat ,
} ,
2015-12-02 23:57:47 +00:00
{
input : "repo@sha256:ffffffffffffffffffffffffffffffffff" ,
err : digest . ErrDigestInvalidLength ,
} ,
2015-09-08 23:00:48 +00:00
{
input : "validname@invaliddigest:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
err : digest . ErrDigestUnsupported ,
} ,
2016-08-11 13:30:17 +00:00
{
input : "Uppercase:tag" ,
err : ErrNameContainsUppercase ,
} ,
// FIXME "Uppercase" is incorrectly handled as a domain-name here, therefore passes.
2020-08-24 11:18:39 +00:00
// See https://github.com/distribution/distribution/pull/1778, and https://github.com/docker/docker/pull/20175
2022-11-10 14:14:53 +00:00
// {
2016-08-11 13:30:17 +00:00
// input: "Uppercase/lowercase:tag",
// err: ErrNameContainsUppercase,
2022-11-10 14:14:53 +00:00
// },
2016-08-11 13:30:17 +00:00
{
input : "test:5000/Uppercase/lowercase:tag" ,
err : ErrNameContainsUppercase ,
} ,
{
input : "lowercase:Uppercase" ,
repository : "lowercase" ,
tag : "Uppercase" ,
} ,
2015-09-08 23:00:48 +00:00
{
input : strings . Repeat ( "a/" , 128 ) + "a:tag" ,
err : ErrNameTooLong ,
} ,
{
input : strings . Repeat ( "a/" , 127 ) + "a:tag-puts-this-over-max" ,
2016-06-09 18:32:23 +00:00
domain : "a" ,
2015-09-08 23:00:48 +00:00
repository : strings . Repeat ( "a/" , 127 ) + "a" ,
tag : "tag-puts-this-over-max" ,
} ,
{
input : "aa/asdf$$^/aa" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : "sub-dom1.foo.com/bar/baz/quux" ,
2016-06-09 18:32:23 +00:00
domain : "sub-dom1.foo.com" ,
2015-09-08 23:00:48 +00:00
repository : "sub-dom1.foo.com/bar/baz/quux" ,
} ,
{
input : "sub-dom1.foo.com/bar/baz/quux:some-long-tag" ,
2016-06-09 18:32:23 +00:00
domain : "sub-dom1.foo.com" ,
2015-09-08 23:00:48 +00:00
repository : "sub-dom1.foo.com/bar/baz/quux" ,
tag : "some-long-tag" ,
} ,
{
input : "b.gcr.io/test.example.com/my-app:test.example.com" ,
2016-06-09 18:32:23 +00:00
domain : "b.gcr.io" ,
2015-09-08 23:00:48 +00:00
repository : "b.gcr.io/test.example.com/my-app" ,
tag : "test.example.com" ,
} ,
{
input : "xn--n3h.com/myimage:xn--n3h.com" , // ☃.com in punycode
2016-06-09 18:32:23 +00:00
domain : "xn--n3h.com" ,
2015-09-08 23:00:48 +00:00
repository : "xn--n3h.com/myimage" ,
tag : "xn--n3h.com" ,
} ,
{
2015-12-02 23:57:47 +00:00
input : "xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" , // 🐳.com in punycode
2016-06-09 18:32:23 +00:00
domain : "xn--7o8h.com" ,
2015-09-08 23:00:48 +00:00
repository : "xn--7o8h.com/myimage" ,
tag : "xn--7o8h.com" ,
2015-12-02 23:57:47 +00:00
digest : "sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
2015-09-08 23:00:48 +00:00
} ,
{
input : "foo_bar.com:8080" ,
repository : "foo_bar.com" ,
tag : "8080" ,
} ,
{
input : "foo/foo_bar.com:8080" ,
2016-06-09 18:32:23 +00:00
domain : "foo" ,
2015-09-08 23:00:48 +00:00
repository : "foo/foo_bar.com" ,
tag : "8080" ,
} ,
2022-06-25 10:23:38 +00:00
{
input : "192.168.1.1" ,
repository : "192.168.1.1" ,
} ,
{
input : "192.168.1.1:tag" ,
repository : "192.168.1.1" ,
tag : "tag" ,
} ,
{
input : "192.168.1.1:5000" ,
repository : "192.168.1.1" ,
tag : "5000" ,
} ,
{
input : "192.168.1.1/repo" ,
domain : "192.168.1.1" ,
repository : "192.168.1.1/repo" ,
} ,
{
input : "192.168.1.1:5000/repo" ,
domain : "192.168.1.1:5000" ,
repository : "192.168.1.1:5000/repo" ,
} ,
{
input : "192.168.1.1:5000/repo:5050" ,
domain : "192.168.1.1:5000" ,
repository : "192.168.1.1:5000/repo" ,
tag : "5050" ,
} ,
{
input : "[2001:db8::1]" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : "[2001:db8::1]:5000" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : "[2001:db8::1]:tag" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : "[2001:db8::1]/repo" ,
domain : "[2001:db8::1]" ,
repository : "[2001:db8::1]/repo" ,
} ,
{
input : "[2001:db8:1:2:3:4:5:6]/repo:tag" ,
domain : "[2001:db8:1:2:3:4:5:6]" ,
repository : "[2001:db8:1:2:3:4:5:6]/repo" ,
tag : "tag" ,
} ,
{
input : "[2001:db8::1]:5000/repo" ,
domain : "[2001:db8::1]:5000" ,
repository : "[2001:db8::1]:5000/repo" ,
} ,
{
input : "[2001:db8::1]:5000/repo:tag" ,
domain : "[2001:db8::1]:5000" ,
repository : "[2001:db8::1]:5000/repo" ,
tag : "tag" ,
} ,
{
input : "[2001:db8::1]:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
domain : "[2001:db8::1]:5000" ,
repository : "[2001:db8::1]:5000/repo" ,
digest : "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
} ,
{
input : "[2001:db8::1]:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
domain : "[2001:db8::1]:5000" ,
repository : "[2001:db8::1]:5000/repo" ,
tag : "tag" ,
digest : "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
} ,
{
input : "[2001:db8::]:5000/repo" ,
domain : "[2001:db8::]:5000" ,
repository : "[2001:db8::]:5000/repo" ,
} ,
{
input : "[::1]:5000/repo" ,
domain : "[::1]:5000" ,
repository : "[::1]:5000/repo" ,
} ,
{
input : "[fe80::1%eth0]:5000/repo" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : "[fe80::1%@invalidzone]:5000/repo" ,
err : ErrReferenceInvalidFormat ,
} ,
2015-07-10 18:36:04 +00:00
}
2023-04-30 12:48:09 +00:00
for _ , tc := range tests {
tc := tc
t . Run ( tc . input , func ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
repo , err := Parse ( tc . input )
if tc . err != nil {
2022-11-10 14:14:53 +00:00
if err == nil {
2023-04-30 12:48:09 +00:00
t . Errorf ( "missing expected error: %v" , tc . err )
} else if tc . err != err {
t . Errorf ( "mismatched error: got %v, expected %v" , err , tc . err )
2022-11-10 14:14:53 +00:00
}
return
} else if err != nil {
t . Errorf ( "unexpected parse error: %v" , err )
return
2015-09-08 23:00:48 +00:00
}
2023-04-30 12:48:09 +00:00
if repo . String ( ) != tc . input {
t . Errorf ( "mismatched repo: got %q, expected %q" , repo . String ( ) , tc . input )
2015-09-08 23:00:48 +00:00
}
2022-11-10 14:14:53 +00:00
if named , ok := repo . ( Named ) ; ok {
2023-04-30 12:48:09 +00:00
if named . Name ( ) != tc . repository {
t . Errorf ( "unexpected repository: got %q, expected %q" , named . Name ( ) , tc . repository )
2022-11-10 14:14:53 +00:00
}
domain , _ := SplitHostname ( named )
2023-04-30 12:48:09 +00:00
if domain != tc . domain {
t . Errorf ( "unexpected domain: got %q, expected %q" , domain , tc . domain )
2015-09-08 23:00:48 +00:00
}
2023-04-30 12:48:09 +00:00
} else if tc . repository != "" || tc . domain != "" {
2022-11-10 14:14:53 +00:00
t . Errorf ( "expected named type, got %T" , repo )
2015-09-08 23:00:48 +00:00
}
2022-11-10 14:14:53 +00:00
tagged , ok := repo . ( Tagged )
2023-04-30 12:48:09 +00:00
if tc . tag != "" {
2022-11-10 14:14:53 +00:00
if ok {
2023-04-30 12:48:09 +00:00
if tagged . Tag ( ) != tc . tag {
t . Errorf ( "unexpected tag: got %q, expected %q" , tagged . Tag ( ) , tc . tag )
2022-11-10 14:14:53 +00:00
}
} else {
t . Errorf ( "expected tagged type, got %T" , repo )
2015-09-08 23:00:48 +00:00
}
2022-11-10 14:14:53 +00:00
} else if ok {
t . Errorf ( "unexpected tagged type" )
2015-09-08 23:00:48 +00:00
}
2015-07-10 18:36:04 +00:00
2022-11-10 14:14:53 +00:00
digested , ok := repo . ( Digested )
2023-04-30 12:48:09 +00:00
if tc . digest != "" {
2022-11-10 14:14:53 +00:00
if ok {
2023-04-30 12:48:09 +00:00
if digested . Digest ( ) . String ( ) != tc . digest {
t . Errorf ( "unexpected digest: got %q, expected %q" , digested . Digest ( ) . String ( ) , tc . digest )
2022-11-10 14:14:53 +00:00
}
} else {
t . Errorf ( "expected digested type, got %T" , repo )
}
} else if ok {
t . Errorf ( "unexpected digested type" )
}
} )
2015-07-10 18:36:04 +00:00
}
}
2015-11-02 17:12:21 +00:00
// TestWithNameFailure tests cases where WithName should fail. Cases where it
// should succeed are covered by TestSplitHostname, below.
func TestWithNameFailure ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
tests := [ ] struct {
2015-11-02 17:12:21 +00:00
input string
err error
} {
{
input : "" ,
err : ErrNameEmpty ,
} ,
{
input : ":justtag" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : "@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : "validname@invaliddigest:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
err : ErrReferenceInvalidFormat ,
} ,
{
input : strings . Repeat ( "a/" , 128 ) + "a:tag" ,
err : ErrNameTooLong ,
} ,
{
input : "aa/asdf$$^/aa" ,
err : ErrReferenceInvalidFormat ,
} ,
}
2023-04-30 12:48:09 +00:00
for _ , tc := range tests {
tc := tc
t . Run ( tc . input , func ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
_ , err := WithName ( tc . input )
2022-11-10 14:14:53 +00:00
if err == nil {
2023-04-30 12:48:09 +00:00
t . Errorf ( "no error parsing name. expected: %s" , tc . err )
2022-11-10 14:14:53 +00:00
}
} )
2015-11-02 17:12:21 +00:00
}
}
2015-09-08 23:00:48 +00:00
func TestSplitHostname ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
tests := [ ] struct {
2016-06-09 18:32:23 +00:00
input string
domain string
name string
2015-09-08 23:00:48 +00:00
} {
{
2016-06-09 18:32:23 +00:00
input : "test.com/foo" ,
domain : "test.com" ,
name : "foo" ,
2015-09-08 23:00:48 +00:00
} ,
{
2016-06-09 18:32:23 +00:00
input : "test_com/foo" ,
domain : "" ,
name : "test_com/foo" ,
2015-09-08 23:00:48 +00:00
} ,
{
2016-06-09 18:32:23 +00:00
input : "test:8080/foo" ,
domain : "test:8080" ,
name : "foo" ,
2015-09-08 23:00:48 +00:00
} ,
{
2016-06-09 18:32:23 +00:00
input : "test.com:8080/foo" ,
domain : "test.com:8080" ,
name : "foo" ,
2015-09-08 23:00:48 +00:00
} ,
{
2016-06-09 18:32:23 +00:00
input : "test-com:8080/foo" ,
domain : "test-com:8080" ,
name : "foo" ,
2015-09-08 23:00:48 +00:00
} ,
{
2016-06-09 18:32:23 +00:00
input : "xn--n3h.com:18080/foo" ,
domain : "xn--n3h.com:18080" ,
name : "foo" ,
2015-09-08 23:00:48 +00:00
} ,
2015-07-10 18:36:04 +00:00
}
2023-04-30 12:48:09 +00:00
for _ , tc := range tests {
tc := tc
t . Run ( tc . input , func ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
named , err := WithName ( tc . input )
2022-11-10 14:14:53 +00:00
if err != nil {
t . Errorf ( "error parsing name: %s" , err )
}
domain , name := SplitHostname ( named )
2023-04-30 12:48:09 +00:00
if domain != tc . domain {
t . Errorf ( "unexpected domain: got %q, expected %q" , domain , tc . domain )
2022-11-10 14:14:53 +00:00
}
2023-04-30 12:48:09 +00:00
if name != tc . name {
t . Errorf ( "unexpected name: got %q, expected %q" , name , tc . name )
2022-11-10 14:14:53 +00:00
}
} )
2015-07-10 18:36:04 +00:00
}
}
2015-09-30 22:36:19 +00:00
type serializationType struct {
Description string
Field Field
}
func TestSerialization ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
tests := [ ] struct {
2015-09-30 22:36:19 +00:00
description string
input string
name string
tag string
digest string
err error
} {
{
description : "empty value" ,
err : ErrNameEmpty ,
} ,
{
description : "just a name" ,
input : "example.com:8000/named" ,
name : "example.com:8000/named" ,
} ,
{
description : "name with a tag" ,
input : "example.com:8000/named:tagged" ,
name : "example.com:8000/named" ,
tag : "tagged" ,
} ,
{
description : "name with digest" ,
2015-12-02 23:57:47 +00:00
input : "other.com/named@sha256:1234567890098765432112345667890098765432112345667890098765432112" ,
2015-09-30 22:36:19 +00:00
name : "other.com/named" ,
2015-12-02 23:57:47 +00:00
digest : "sha256:1234567890098765432112345667890098765432112345667890098765432112" ,
2015-09-30 22:36:19 +00:00
} ,
}
2023-04-30 12:48:09 +00:00
for _ , tc := range tests {
tc := tc
t . Run ( tc . description , func ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2022-11-10 14:14:53 +00:00
m := map [ string ] string {
2023-04-30 12:48:09 +00:00
"Description" : tc . description ,
"Field" : tc . input ,
2015-09-30 22:36:19 +00:00
}
2022-11-10 14:14:53 +00:00
b , err := json . Marshal ( m )
if err != nil {
t . Errorf ( "error marshalling: %v" , err )
2015-09-30 22:36:19 +00:00
}
2022-11-10 14:14:53 +00:00
st := serializationType { }
2015-09-30 22:36:19 +00:00
2022-11-10 14:14:53 +00:00
if err := json . Unmarshal ( b , & st ) ; err != nil {
2023-04-30 12:48:09 +00:00
if tc . err == nil {
2022-11-10 14:14:53 +00:00
t . Errorf ( "error unmarshalling: %v" , err )
}
2023-04-30 12:48:09 +00:00
if err != tc . err {
t . Errorf ( "wrong error, expected %v, got %v" , tc . err , err )
2022-11-10 14:14:53 +00:00
}
2015-09-30 22:36:19 +00:00
2022-11-10 14:14:53 +00:00
return
2023-04-30 12:48:09 +00:00
} else if tc . err != nil {
t . Errorf ( "expected error unmarshalling: %v" , tc . err )
2022-11-10 14:14:53 +00:00
}
2015-09-30 22:36:19 +00:00
2023-04-30 12:48:09 +00:00
if st . Description != tc . description {
t . Errorf ( "wrong description, expected %q, got %q" , tc . description , st . Description )
2015-09-30 22:36:19 +00:00
}
2022-11-10 14:14:53 +00:00
ref := st . Field . Reference ( )
if named , ok := ref . ( Named ) ; ok {
2023-04-30 12:48:09 +00:00
if named . Name ( ) != tc . name {
t . Errorf ( "unexpected repository: got %q, expected %q" , named . Name ( ) , tc . name )
2015-09-30 22:36:19 +00:00
}
2023-04-30 12:48:09 +00:00
} else if tc . name != "" {
2022-11-10 14:14:53 +00:00
t . Errorf ( "expected named type, got %T" , ref )
2015-09-30 22:36:19 +00:00
}
2022-11-10 14:14:53 +00:00
tagged , ok := ref . ( Tagged )
2023-04-30 12:48:09 +00:00
if tc . tag != "" {
2022-11-10 14:14:53 +00:00
if ok {
2023-04-30 12:48:09 +00:00
if tagged . Tag ( ) != tc . tag {
t . Errorf ( "unexpected tag: got %q, expected %q" , tagged . Tag ( ) , tc . tag )
2022-11-10 14:14:53 +00:00
}
} else {
t . Errorf ( "expected tagged type, got %T" , ref )
2015-09-30 22:36:19 +00:00
}
2022-11-10 14:14:53 +00:00
} else if ok {
t . Errorf ( "unexpected tagged type" )
2015-09-30 22:36:19 +00:00
}
2022-11-10 14:14:53 +00:00
digested , ok := ref . ( Digested )
2023-04-30 12:48:09 +00:00
if tc . digest != "" {
2022-11-10 14:14:53 +00:00
if ok {
2023-04-30 12:48:09 +00:00
if digested . Digest ( ) . String ( ) != tc . digest {
t . Errorf ( "unexpected digest: got %q, expected %q" , digested . Digest ( ) . String ( ) , tc . digest )
2022-11-10 14:14:53 +00:00
}
} else {
t . Errorf ( "expected digested type, got %T" , ref )
}
} else if ok {
t . Errorf ( "unexpected digested type" )
}
2015-09-30 22:36:19 +00:00
2022-11-10 14:14:53 +00:00
st = serializationType {
2023-04-30 12:48:09 +00:00
Description : tc . description ,
2022-11-10 14:14:53 +00:00
Field : AsField ( ref ) ,
}
2015-09-30 22:36:19 +00:00
2022-11-10 14:14:53 +00:00
b2 , err := json . Marshal ( st )
if err != nil {
t . Errorf ( "error marshing serialization type: %v" , err )
}
2015-09-30 22:36:19 +00:00
2022-11-10 14:14:53 +00:00
if string ( b ) != string ( b2 ) {
t . Errorf ( "unexpected serialized value: expected %q, got %q" , string ( b ) , string ( b2 ) )
}
2015-09-30 22:36:19 +00:00
2022-11-10 14:14:53 +00:00
// Ensure st.Field is not implementing "Reference" directly, getting
// around the Reference type system
var fieldInterface interface { } = st . Field
if _ , ok := fieldInterface . ( Reference ) ; ok {
t . Errorf ( "field should not implement Reference interface" )
}
} )
2015-09-30 22:36:19 +00:00
}
}
2015-10-10 00:09:54 +00:00
func TestWithTag ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
tests := [ ] struct {
2015-10-10 00:09:54 +00:00
name string
2016-11-08 22:47:33 +00:00
digest digest . Digest
2015-10-10 00:09:54 +00:00
tag string
combined string
} {
{
name : "test.com/foo" ,
tag : "tag" ,
combined : "test.com/foo:tag" ,
} ,
{
name : "foo" ,
tag : "tag2" ,
combined : "foo:tag2" ,
} ,
{
name : "test.com:8000/foo" ,
tag : "tag4" ,
combined : "test.com:8000/foo:tag4" ,
} ,
2015-10-29 01:22:00 +00:00
{
name : "test.com:8000/foo" ,
tag : "TAG5" ,
combined : "test.com:8000/foo:TAG5" ,
} ,
2016-11-08 22:47:33 +00:00
{
name : "test.com:8000/foo" ,
digest : "sha256:1234567890098765432112345667890098765" ,
tag : "TAG5" ,
combined : "test.com:8000/foo:TAG5@sha256:1234567890098765432112345667890098765" ,
} ,
2015-10-10 00:09:54 +00:00
}
2023-04-30 12:48:09 +00:00
for _ , tc := range tests {
tc := tc
t . Run ( tc . combined , func ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
named , err := WithName ( tc . name )
2016-11-08 22:47:33 +00:00
if err != nil {
2022-11-10 14:14:53 +00:00
t . Errorf ( "error parsing name: %s" , err )
}
2023-04-30 12:48:09 +00:00
if tc . digest != "" {
canonical , err := WithDigest ( named , tc . digest )
2022-11-10 14:14:53 +00:00
if err != nil {
t . Errorf ( "error adding digest" )
}
named = canonical
2016-11-08 22:47:33 +00:00
}
2023-04-30 12:48:09 +00:00
tagged , err := WithTag ( named , tc . tag )
2022-11-10 14:14:53 +00:00
if err != nil {
t . Errorf ( "WithTag failed: %s" , err )
}
2023-04-30 12:48:09 +00:00
if tagged . String ( ) != tc . combined {
t . Errorf ( "unexpected: got %q, expected %q" , tagged . String ( ) , tc . combined )
2022-11-10 14:14:53 +00:00
}
} )
2015-10-10 00:09:54 +00:00
}
}
func TestWithDigest ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
tests := [ ] struct {
2015-10-10 00:09:54 +00:00
name string
digest digest . Digest
2016-11-08 22:47:33 +00:00
tag string
2015-10-10 00:09:54 +00:00
combined string
} {
{
name : "test.com/foo" ,
digest : "sha256:1234567890098765432112345667890098765" ,
combined : "test.com/foo@sha256:1234567890098765432112345667890098765" ,
} ,
{
name : "foo" ,
digest : "sha256:1234567890098765432112345667890098765" ,
combined : "foo@sha256:1234567890098765432112345667890098765" ,
} ,
{
name : "test.com:8000/foo" ,
digest : "sha256:1234567890098765432112345667890098765" ,
combined : "test.com:8000/foo@sha256:1234567890098765432112345667890098765" ,
} ,
2016-11-08 22:47:33 +00:00
{
name : "test.com:8000/foo" ,
digest : "sha256:1234567890098765432112345667890098765" ,
tag : "latest" ,
combined : "test.com:8000/foo:latest@sha256:1234567890098765432112345667890098765" ,
} ,
2015-10-10 00:09:54 +00:00
}
2023-04-30 12:48:09 +00:00
for _ , tc := range tests {
tc := tc
t . Run ( tc . combined , func ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
named , err := WithName ( tc . name )
2022-11-10 14:14:53 +00:00
if err != nil {
t . Errorf ( "error parsing name: %s" , err )
}
2023-04-30 12:48:09 +00:00
if tc . tag != "" {
tagged , err := WithTag ( named , tc . tag )
2022-11-10 14:14:53 +00:00
if err != nil {
t . Errorf ( "error adding tag" )
}
named = tagged
}
2023-04-30 12:48:09 +00:00
digested , err := WithDigest ( named , tc . digest )
2016-11-08 22:47:33 +00:00
if err != nil {
2022-11-10 14:14:53 +00:00
t . Errorf ( "WithDigest failed: %s" , err )
2016-11-08 22:47:33 +00:00
}
2023-04-30 12:48:09 +00:00
if digested . String ( ) != tc . combined {
t . Errorf ( "unexpected: got %q, expected %q" , digested . String ( ) , tc . combined )
2022-11-10 14:14:53 +00:00
}
} )
2015-10-10 00:09:54 +00:00
}
}
2017-01-14 00:19:24 +00:00
func TestParseNamed ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
tests := [ ] struct {
2017-01-14 00:19:24 +00:00
input string
domain string
name string
err error
} {
{
input : "test.com/foo" ,
domain : "test.com" ,
name : "foo" ,
} ,
{
input : "test:8080/foo" ,
domain : "test:8080" ,
name : "foo" ,
} ,
{
input : "test_com/foo" ,
err : ErrNameNotCanonical ,
} ,
{
input : "test.com" ,
err : ErrNameNotCanonical ,
} ,
{
input : "foo" ,
err : ErrNameNotCanonical ,
} ,
{
input : "library/foo" ,
err : ErrNameNotCanonical ,
} ,
{
input : "docker.io/library/foo" ,
domain : "docker.io" ,
name : "library/foo" ,
} ,
// Ambiguous case, parser will add "library/" to foo
{
input : "docker.io/foo" ,
err : ErrNameNotCanonical ,
} ,
}
2023-04-30 12:48:09 +00:00
for _ , tc := range tests {
tc := tc
t . Run ( tc . input , func ( t * testing . T ) {
2022-11-18 19:04:23 +00:00
t . Parallel ( )
2023-04-30 12:48:09 +00:00
named , err := ParseNamed ( tc . input )
if err != nil && tc . err == nil {
2022-11-10 14:14:53 +00:00
t . Errorf ( "error parsing name: %s" , err )
return
2023-04-30 12:48:09 +00:00
} else if err == nil && tc . err != nil {
t . Errorf ( "parsing succeeded: expected error %v" , tc . err )
2022-11-10 14:14:53 +00:00
return
2023-04-30 12:48:09 +00:00
} else if err != tc . err {
t . Errorf ( "unexpected error %v, expected %v" , err , tc . err )
2022-11-10 14:14:53 +00:00
return
} else if err != nil {
return
}
2017-01-14 00:19:24 +00:00
2022-11-10 14:14:53 +00:00
domain , name := SplitHostname ( named )
2023-04-30 12:48:09 +00:00
if domain != tc . domain {
t . Errorf ( "unexpected domain: got %q, expected %q" , domain , tc . domain )
2022-11-10 14:14:53 +00:00
}
2023-04-30 12:48:09 +00:00
if name != tc . name {
t . Errorf ( "unexpected name: got %q, expected %q" , name , tc . name )
2022-11-10 14:14:53 +00:00
}
} )
2017-01-14 00:19:24 +00:00
}
}