Skip to content

Commit d1dcf1e

Browse files
author
David Collom
committed
Test Docker client Tag
1 parent 9067768 commit d1dcf1e

File tree

4 files changed

+160
-8
lines changed

4 files changed

+160
-8
lines changed

pkg/client/docker/docker.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
"github.com/hashicorp/go-retryablehttp"
1818
"github.com/jetstack/version-checker/pkg/api"
19+
"github.com/jetstack/version-checker/pkg/client/util"
1920
)
2021

2122
// Ensure that we are an ImageClient
@@ -119,11 +120,18 @@ func (c *Client) Tags(ctx context.Context, _, repo, image string) ([]api.ImageTa
119120
}
120121

121122
tag := api.ImageTag{
122-
Tag: result.Name,
123-
Timestamp: timestamp,
124-
SHA: result.Digest,
123+
Tag: result.Name,
124+
Timestamp: timestamp,
125125
}
126126

127+
// If we have a Digest, lets set it..
128+
if result.Digest != "" {
129+
tag.SHA = result.Digest
130+
}
131+
132+
// Attempt to get OS/Arch, from the Tag Name
133+
tag.OS, tag.Architecture = util.OSArchFromTag(result.Name)
134+
127135
for _, image := range result.Images {
128136
// Image without digest contains no real image.
129137
if len(image.Digest) == 0 {

pkg/client/docker/docker_test.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package docker
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"net/http"
8+
"net/http/httptest"
9+
"strings"
10+
"testing"
11+
"time"
12+
13+
"github.com/jetstack/version-checker/pkg/api"
14+
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
16+
17+
"github.com/sirupsen/logrus"
18+
)
19+
20+
type hostnameOverride struct {
21+
Host string
22+
RT http.RoundTripper
23+
}
24+
25+
func (r *hostnameOverride) RoundTrip(req *http.Request) (*http.Response, error) {
26+
if req.Host != r.Host {
27+
if testing.Verbose() {
28+
fmt.Printf("Overriding URI from: %s to %s\n", req.Host, strings.TrimPrefix(r.Host, "http://"))
29+
}
30+
req.Host = strings.TrimPrefix(r.Host, "http://")
31+
req.URL.Host = strings.TrimPrefix(r.Host, "http://")
32+
req.URL.Scheme = "http"
33+
}
34+
// fmt.Printf("Req: %+v", req)
35+
return r.RT.RoundTrip(req)
36+
}
37+
38+
func TestTags(t *testing.T) {
39+
log := logrus.NewEntry(logrus.New())
40+
ctx := context.Background()
41+
42+
t.Run("successful Tags fetch", func(t *testing.T) {
43+
44+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+
require.NotEmpty(t, r.Header.Get("Authorization"))
46+
47+
require.Equal(t, "/v2/repositories/testrepo/testimage/tags", r.URL.Path)
48+
w.WriteHeader(http.StatusOK)
49+
_ = json.NewEncoder(w).Encode(TagResponse{
50+
Results: []Result{
51+
{
52+
Name: "v1.0.0",
53+
Timestamp: time.Now().Add(-24 * time.Hour).Format(time.RFC3339Nano),
54+
Digest: "sha256:abcdef",
55+
Images: []Image{
56+
{Digest: "sha256:child1", OS: "linux", Architecture: "amd64"},
57+
},
58+
},
59+
{
60+
Name: "v2.0.0",
61+
Timestamp: time.Now().Add(-48 * time.Hour).Format(time.RFC3339Nano),
62+
Images: []Image{
63+
{Digest: "sha256:child2", OS: "linux", Architecture: "amd64"},
64+
},
65+
},
66+
},
67+
})
68+
}))
69+
defer server.Close()
70+
71+
client := &Client{
72+
Client: server.Client(),
73+
log: log,
74+
Options: Options{
75+
Token: "testtoken",
76+
},
77+
}
78+
79+
client.Transport = &hostnameOverride{RT: server.Client().Transport, Host: server.URL}
80+
81+
tags, err := client.Tags(ctx, "NOT USED!", "testrepo", "testimage")
82+
require.NoError(t, err)
83+
require.Len(t, tags, 2)
84+
85+
assert.Equal(t, "v1.0.0", tags[0].Tag)
86+
assert.Equal(t, "sha256:abcdef", tags[0].SHA)
87+
assert.Equal(t, api.OS("linux"), tags[0].Children[0].OS)
88+
assert.Equal(t, api.Architecture("amd64"), tags[0].Children[0].Architecture)
89+
90+
assert.Equal(t, "v2.0.0", tags[1].Tag)
91+
assert.NotEmpty(t, tags[1].SHA)
92+
})
93+
94+
t.Run("error on invalid response", func(t *testing.T) {
95+
96+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
97+
w.WriteHeader(http.StatusOK)
98+
_, _ = w.Write([]byte("invalid json"))
99+
}))
100+
defer server.Close()
101+
102+
client := &Client{
103+
Client: server.Client(),
104+
log: log,
105+
Options: Options{
106+
Token: "testtoken",
107+
},
108+
}
109+
client.Transport = &hostnameOverride{RT: server.Client().Transport, Host: server.URL}
110+
111+
tags, err := client.Tags(ctx, "NOT USED!", "testrepo", "testimage")
112+
assert.Nil(t, tags)
113+
assert.Error(t, err)
114+
assert.Contains(t, err.Error(), "unexpected image tags response")
115+
})
116+
117+
t.Run("error on non-200 status code", func(t *testing.T) {
118+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
119+
w.WriteHeader(http.StatusNotFound)
120+
_, _ = w.Write([]byte("not found"))
121+
}))
122+
defer server.Close()
123+
124+
client := &Client{
125+
Client: server.Client(),
126+
log: log,
127+
Options: Options{
128+
Token: "testtoken",
129+
},
130+
}
131+
client.Transport = &hostnameOverride{RT: server.Client().Transport, Host: server.URL}
132+
133+
tags, err := client.Tags(ctx, "NOT USED!", "testrepo", "testimage")
134+
assert.Nil(t, tags)
135+
assert.Error(t, err)
136+
assert.Contains(t, err.Error(), "unexpected image")
137+
})
138+
}

pkg/client/oci/oci.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,20 @@ func (c *Client) Manifests(ctx context.Context, repo name.Repository, tags []str
128128
Timestamp: ts,
129129
}
130130

131-
// We have a suitable Image Index!
132-
if manifest.MediaType == types.OCIImageIndex || manifest.MediaType == types.DockerManifestList {
131+
switch manifest.MediaType {
132+
133+
case types.OCIImageIndex, types.DockerManifestList:
133134
children := []*api.ImageTag{}
134135
imgidx, err := manifest.ImageIndex()
135136
if err != nil {
136-
log.Errorf("getting imageindex: %s", err)
137+
log.Errorf("getting ImageIndex: %s", err)
137138
return
138139
}
139140
idxman, err := imgidx.IndexManifest()
141+
if err != nil {
142+
log.Errorf("getting IndexManifest: %s", err)
143+
return
144+
}
140145
for _, img := range idxman.Manifests {
141146

142147
children = append(children, &api.ImageTag{
@@ -145,7 +150,8 @@ func (c *Client) Manifests(ctx context.Context, repo name.Repository, tags []str
145150
})
146151
}
147152
baseTag.Children = children
148-
} else if manifest.MediaType == types.OCIManifestSchema1 || manifest.MediaType == types.DockerManifestSchema2 {
153+
154+
case types.OCIManifestSchema1, types.DockerManifestSchema2:
149155
img, err := manifest.Image()
150156
if err != nil {
151157
log.Errorf("unable to collect image from manifest: %s", err)

pkg/client/selfhosted/selfhosted.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ func (c *Client) Tags(ctx context.Context, host, repo, image string) ([]api.Imag
228228
}
229229

230230
if len(manifestListResponse.Manifests) == 0 {
231-
231+
// TODO:
232232
}
233233

234234
for _, manifest := range manifestListResponse.Manifests {

0 commit comments

Comments
 (0)