Skip to content

Commit e02725b

Browse files
committed
Adding some tests and fixtures
1 parent 5c0fa91 commit e02725b

8 files changed

Lines changed: 242 additions & 28 deletions

File tree

internal/docker/client.go

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package docker
22

33
import (
4-
"errors"
54
"fmt"
6-
"io/fs"
75
"net/http"
86
"os"
97
"strings"
@@ -16,40 +14,26 @@ import (
1614
func GetClient() (*client.Client, error) {
1715
_, found := os.LookupEnv("DOCKER_HOST")
1816
if !found {
19-
2017
log.Debugf("no explicit DOCKER_HOST defined")
2118

2219
log.Debugf("reading docker configuration: %s", configFileName)
2320

2421
cfg, err := loadConfig(configFileName)
25-
if err != nil && errors.Is(err, fs.ErrNotExist) {
26-
log.Debugf("no docker configuration found", configFileName)
27-
28-
err = nil
29-
}
30-
31-
if err != nil {
32-
return nil, fmt.Errorf("cant parse docker config: %w", err)
33-
}
34-
35-
if cfg != nil {
36-
dockerContext := resolveContextName(cfg)
37-
38-
log.Debugf("current docker context: %s", dockerContext)
39-
40-
host, err := endpointFromContext(dockerContext)
22+
if err == nil {
23+
host, err := processConfig(os.Getenv(envOverrideContext), contextsDir, cfg)
4124
if err != nil {
4225
return nil, err
4326
}
44-
4527
log.Debugf("using host from docker configuration: %s", host)
4628

4729
err = os.Setenv("DOCKER_HOST", host)
4830
if err != nil {
4931
return nil, err
5032
}
51-
33+
} else {
34+
log.Debugf("cant parse docker config, ignoring: %v", err)
5235
}
36+
5337
}
5438

5539
clientOpts := []client.Opt{

internal/docker/config.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"os"
77
"path/filepath"
88

9-
"github.com/docker/cli/cli/config"
9+
"github.com/anchore/stereoscope/internal/log"
1010
"github.com/docker/cli/cli/config/configfile"
1111
"github.com/docker/cli/cli/context/store"
1212
"github.com/docker/docker/pkg/homedir"
@@ -25,13 +25,23 @@ var (
2525
configFileName = filepath.Join(configFileDir, "config.json")
2626
)
2727

28-
func resolveContextName(config *configfile.ConfigFile) string {
29-
if ctxName := os.Getenv(envOverrideContext); ctxName != "" {
30-
return ctxName
28+
func processConfig(overrideContext, dir string, cfg *configfile.ConfigFile) (string, error) {
29+
dockerContext := resolveContextName(overrideContext, cfg)
30+
31+
log.Debugf("current docker context: %s", dockerContext)
32+
33+
return endpointFromContext(dir, dockerContext)
34+
}
35+
36+
func resolveContextName(contextOverride string, config *configfile.ConfigFile) string {
37+
if contextOverride != "" {
38+
return contextOverride
3139
}
40+
3241
if config != nil && config.CurrentContext != "" {
3342
return config.CurrentContext
3443
}
44+
3545
return defaultContextName
3646
}
3747

@@ -51,10 +61,10 @@ func loadConfig(filename string) (*configfile.ConfigFile, error) {
5161
return cfg, err
5262
}
5363

54-
func endpointFromContext(ctx string) (string, error) {
55-
st := store.New(config.ContextStoreDir(), store.Config{})
64+
func endpointFromContext(dir, ctxName string) (string, error) {
65+
st := store.New(dir, store.Config{})
5666

57-
meta, err := st.GetMetadata(ctx)
67+
meta, err := st.GetMetadata(ctxName)
5868
if err != nil {
5969
return "", fmt.Errorf("cant get docker config metadata: %w", err)
6070
}

internal/docker/config_test.go

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
package docker
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/docker/cli/cli/config/configfile"
9+
"github.com/opencontainers/go-digest"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func Test_loadConfig(t *testing.T) {
14+
root := "test-fixtures"
15+
16+
prepareConfig := func(t *testing.T, context, fname string) *configfile.ConfigFile {
17+
t.Helper()
18+
cfg := configfile.New(fname)
19+
cfg.CurrentContext = context
20+
21+
return cfg
22+
}
23+
24+
tests := []struct {
25+
name string
26+
filename string
27+
want *configfile.ConfigFile
28+
err error
29+
wantErr bool
30+
}{
31+
{
32+
name: "config file not found",
33+
filename: "some-nonexisting-file",
34+
wantErr: true,
35+
},
36+
{
37+
name: "config file parsed normally",
38+
filename: filepath.Join(root, "config0.json"),
39+
wantErr: false,
40+
want: prepareConfig(t, "colima", filepath.Join(root, "config0.json")),
41+
},
42+
{
43+
name: "config file cannot be parsed",
44+
filename: filepath.Join(root, "config1.json"),
45+
wantErr: true,
46+
},
47+
}
48+
for _, tt := range tests {
49+
t.Run(tt.name, func(t *testing.T) {
50+
got, err := loadConfig(tt.filename)
51+
if tt.wantErr {
52+
assert.NotNil(t, err)
53+
} else {
54+
assert.Nil(t, err)
55+
}
56+
57+
assert.Equal(t, tt.want, got)
58+
})
59+
}
60+
}
61+
62+
func Test_resolveContextName(t *testing.T) {
63+
type args struct {
64+
contextOverride string
65+
config *configfile.ConfigFile
66+
}
67+
tests := []struct {
68+
name string
69+
args args
70+
want string
71+
}{
72+
{
73+
name: "respect contextOverride",
74+
args: args{
75+
contextOverride: "contextFromEnvironment",
76+
},
77+
want: "contextFromEnvironment",
78+
},
79+
{
80+
name: "returns default context name if config is nil",
81+
args: args{},
82+
want: "default",
83+
},
84+
{
85+
name: "returns context from the config",
86+
args: args{
87+
config: &configfile.ConfigFile{
88+
CurrentContext: "colima",
89+
},
90+
},
91+
want: "colima",
92+
},
93+
}
94+
for _, tt := range tests {
95+
t.Run(tt.name, func(t *testing.T) {
96+
got := resolveContextName(tt.args.contextOverride, tt.args.config)
97+
98+
assert.Equal(t, tt.want, got)
99+
})
100+
}
101+
}
102+
103+
func Test_endpointFromContext(t *testing.T) {
104+
root := "test-fixtures"
105+
106+
tmpCtxDir := func(t *testing.T) string {
107+
t.Helper()
108+
d, err := os.MkdirTemp("", "tests")
109+
if err != nil {
110+
t.Fatalf("cant setup test: %v", err)
111+
}
112+
113+
ctxDir := filepath.Join(d, "contexts")
114+
err = os.MkdirAll(ctxDir, 0o755)
115+
if err != nil {
116+
t.Fatalf("cant setup test: %v", err)
117+
}
118+
119+
return ctxDir
120+
}
121+
122+
readFixture := func(t *testing.T, name string) []byte {
123+
t.Helper()
124+
data, err := os.ReadFile(filepath.Join(root, name))
125+
if err != nil {
126+
t.Fatalf("cant setup test: %v", err)
127+
}
128+
129+
return data
130+
}
131+
132+
// meta files stored under ~/.docker with names like
133+
// ~/.docker/contexts/meta/f24fd3749c1368328e2b149bec149cb6795619f244c5b584e844961215dadd16/meta.json
134+
writeTestMeta := func(t *testing.T, fixture, dir, contextName string) {
135+
t.Helper()
136+
data := readFixture(t, fixture)
137+
dd := digest.FromString(contextName)
138+
139+
base := filepath.Join(dir, "meta", dd.Encoded())
140+
141+
err := os.MkdirAll(base, 0o755)
142+
if err != nil {
143+
t.Fatalf("cant setup test: %v", err)
144+
}
145+
146+
outFname := filepath.Join(base, "meta.json")
147+
148+
err = os.WriteFile(outFname, data, 0o600)
149+
if err != nil {
150+
t.Fatalf("cant setup test: %v", err)
151+
}
152+
153+
t.Logf("fixture %s written to: %s", fixture, outFname)
154+
}
155+
156+
tests := []struct {
157+
name string
158+
ctxName string
159+
want string
160+
fixture string
161+
wantErr bool
162+
}{
163+
{
164+
name: "reads docker host from the meta data",
165+
want: "unix:///some_weird_location/.colima/docker.sock",
166+
ctxName: "colima",
167+
fixture: "meta0.json",
168+
},
169+
{
170+
name: "cant read docker host from the meta data",
171+
want: "",
172+
ctxName: "colima",
173+
fixture: "",
174+
wantErr: true,
175+
},
176+
{
177+
name: "invalid endpoint name",
178+
want: "",
179+
ctxName: "colima",
180+
fixture: "meta1.json",
181+
wantErr: true,
182+
},
183+
{
184+
name: "no host defined",
185+
want: "",
186+
ctxName: "colima",
187+
fixture: "meta2.json",
188+
wantErr: true,
189+
},
190+
}
191+
for _, tt := range tests {
192+
t.Run(tt.name, func(t *testing.T) {
193+
dir := tmpCtxDir(t)
194+
if tt.fixture != "" {
195+
writeTestMeta(t, tt.fixture, dir, tt.ctxName)
196+
}
197+
198+
got, err := endpointFromContext(dir, tt.ctxName)
199+
if tt.wantErr {
200+
assert.NotNil(t, err)
201+
} else {
202+
assert.Nil(t, err)
203+
}
204+
205+
assert.Equal(t, tt.want, got)
206+
})
207+
}
208+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"auths": {},
3+
"currentContext": "colima"
4+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
BROKEN_JSON_FILE
2+
{
3+
"auths": {},
4+
"currentContext": "colima"
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"Name":"colima","Metadata":{"Description":"colima"},"Endpoints":{"docker":{"Host":"unix:///some_weird_location/.colima/docker.sock","SkipTLSVerify":false}}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"Name":"colima","Metadata":{"Description":"colima"},"Endpoints":{"INVALID-NONDOCKER-ENDPOINT":{"Host":"unix:///some_weird_location/.colima/docker.sock","SkipTLSVerify":false}}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"Name":"colima","Metadata":{"Description":"colima"},"Endpoints":{"docker":{"NO-HOSTNAME-DEFINED":"unix:///some_weird_location/.colima/docker.sock","SkipTLSVerify":false}}}

0 commit comments

Comments
 (0)