1
15
16 package resolver
17
18 import (
19 "runtime"
20 "testing"
21
22 "helm.sh/helm/v3/pkg/chart"
23 "helm.sh/helm/v3/pkg/registry"
24 )
25
26 func TestResolve(t *testing.T) {
27 tests := []struct {
28 name string
29 req []*chart.Dependency
30 expect *chart.Lock
31 err bool
32 }{
33 {
34 name: "repo from invalid version",
35 req: []*chart.Dependency{
36 {Name: "base", Repository: "file://base", Version: "1.1.0"},
37 },
38 expect: &chart.Lock{
39 Dependencies: []*chart.Dependency{
40 {Name: "base", Repository: "file://base", Version: "0.1.0"},
41 },
42 },
43 err: true,
44 },
45 {
46 name: "version failure",
47 req: []*chart.Dependency{
48 {Name: "oedipus-rex", Repository: "http://example.com", Version: ">a1"},
49 },
50 err: true,
51 },
52 {
53 name: "cache index failure",
54 req: []*chart.Dependency{
55 {Name: "oedipus-rex", Repository: "http://example.com", Version: "1.0.0"},
56 },
57 expect: &chart.Lock{
58 Dependencies: []*chart.Dependency{
59 {Name: "oedipus-rex", Repository: "http://example.com", Version: "1.0.0"},
60 },
61 },
62 },
63 {
64 name: "chart not found failure",
65 req: []*chart.Dependency{
66 {Name: "redis", Repository: "http://example.com", Version: "1.0.0"},
67 },
68 err: true,
69 },
70 {
71 name: "constraint not satisfied failure",
72 req: []*chart.Dependency{
73 {Name: "alpine", Repository: "http://example.com", Version: ">=1.0.0"},
74 },
75 err: true,
76 },
77 {
78 name: "valid lock",
79 req: []*chart.Dependency{
80 {Name: "alpine", Repository: "http://example.com", Version: ">=0.1.0"},
81 },
82 expect: &chart.Lock{
83 Dependencies: []*chart.Dependency{
84 {Name: "alpine", Repository: "http://example.com", Version: "0.2.0"},
85 },
86 },
87 },
88 {
89 name: "repo from valid local path",
90 req: []*chart.Dependency{
91 {Name: "base", Repository: "file://base", Version: "0.1.0"},
92 },
93 expect: &chart.Lock{
94 Dependencies: []*chart.Dependency{
95 {Name: "base", Repository: "file://base", Version: "0.1.0"},
96 },
97 },
98 },
99 {
100 name: "repo from valid local path with range resolution",
101 req: []*chart.Dependency{
102 {Name: "base", Repository: "file://base", Version: "^0.1.0"},
103 },
104 expect: &chart.Lock{
105 Dependencies: []*chart.Dependency{
106 {Name: "base", Repository: "file://base", Version: "0.1.0"},
107 },
108 },
109 },
110 {
111 name: "repo from invalid local path",
112 req: []*chart.Dependency{
113 {Name: "nonexistent", Repository: "file://testdata/nonexistent", Version: "0.1.0"},
114 },
115 err: true,
116 },
117 {
118 name: "repo from valid path under charts path",
119 req: []*chart.Dependency{
120 {Name: "localdependency", Repository: "", Version: "0.1.0"},
121 },
122 expect: &chart.Lock{
123 Dependencies: []*chart.Dependency{
124 {Name: "localdependency", Repository: "", Version: "0.1.0"},
125 },
126 },
127 },
128 {
129 name: "repo from invalid path under charts path",
130 req: []*chart.Dependency{
131 {Name: "nonexistentdependency", Repository: "", Version: "0.1.0"},
132 },
133 expect: &chart.Lock{
134 Dependencies: []*chart.Dependency{
135 {Name: "nonexistentlocaldependency", Repository: "", Version: "0.1.0"},
136 },
137 },
138 err: true,
139 },
140 }
141
142 repoNames := map[string]string{"alpine": "kubernetes-charts", "redis": "kubernetes-charts"}
143 registryClient, _ := registry.NewClient()
144 r := New("testdata/chartpath", "testdata/repository", registryClient)
145 for _, tt := range tests {
146 t.Run(tt.name, func(t *testing.T) {
147 l, err := r.Resolve(tt.req, repoNames)
148 if err != nil {
149 if tt.err {
150 return
151 }
152 t.Fatal(err)
153 }
154
155 if tt.err {
156 t.Fatalf("Expected error in test %q", tt.name)
157 }
158
159 if h, err := HashReq(tt.req, tt.expect.Dependencies); err != nil {
160 t.Fatal(err)
161 } else if h != l.Digest {
162 t.Errorf("%q: hashes don't match.", tt.name)
163 }
164
165
166 if len(l.Dependencies) != len(tt.req) {
167 t.Errorf("%s: wrong number of dependencies in lock", tt.name)
168 }
169 d0 := l.Dependencies[0]
170 e0 := tt.expect.Dependencies[0]
171 if d0.Name != e0.Name {
172 t.Errorf("%s: expected name %s, got %s", tt.name, e0.Name, d0.Name)
173 }
174 if d0.Repository != e0.Repository {
175 t.Errorf("%s: expected repo %s, got %s", tt.name, e0.Repository, d0.Repository)
176 }
177 if d0.Version != e0.Version {
178 t.Errorf("%s: expected version %s, got %s", tt.name, e0.Version, d0.Version)
179 }
180 })
181 }
182 }
183
184 func TestHashReq(t *testing.T) {
185 expect := "sha256:fb239e836325c5fa14b29d1540a13b7d3ba13151b67fe719f820e0ef6d66aaaf"
186
187 tests := []struct {
188 name string
189 chartVersion string
190 lockVersion string
191 wantError bool
192 }{
193 {
194 name: "chart with the expected digest",
195 chartVersion: "0.1.0",
196 lockVersion: "0.1.0",
197 wantError: false,
198 },
199 {
200 name: "ranged version but same resolved lock version",
201 chartVersion: "^0.1.0",
202 lockVersion: "0.1.0",
203 wantError: true,
204 },
205 {
206 name: "ranged version resolved as higher version",
207 chartVersion: "^0.1.0",
208 lockVersion: "0.1.2",
209 wantError: true,
210 },
211 {
212 name: "different version",
213 chartVersion: "0.1.2",
214 lockVersion: "0.1.2",
215 wantError: true,
216 },
217 {
218 name: "different version with a range",
219 chartVersion: "^0.1.2",
220 lockVersion: "0.1.2",
221 wantError: true,
222 },
223 }
224
225 for _, tt := range tests {
226 t.Run(tt.name, func(t *testing.T) {
227 req := []*chart.Dependency{
228 {Name: "alpine", Version: tt.chartVersion, Repository: "http://localhost:8879/charts"},
229 }
230 lock := []*chart.Dependency{
231 {Name: "alpine", Version: tt.lockVersion, Repository: "http://localhost:8879/charts"},
232 }
233 h, err := HashReq(req, lock)
234 if err != nil {
235 t.Fatal(err)
236 }
237 if !tt.wantError && expect != h {
238 t.Errorf("Expected %q, got %q", expect, h)
239 } else if tt.wantError && expect == h {
240 t.Errorf("Expected not %q, but same", expect)
241 }
242 })
243 }
244 }
245
246 func TestGetLocalPath(t *testing.T) {
247 tests := []struct {
248 name string
249 repo string
250 chartpath string
251 expect string
252 winExpect string
253 err bool
254 }{
255 {
256 name: "absolute path",
257 repo: "file:////",
258 expect: "/",
259 winExpect: "\\",
260 },
261 {
262 name: "relative path",
263 repo: "file://../../testdata/chartpath/base",
264 chartpath: "foo/bar",
265 expect: "testdata/chartpath/base",
266 winExpect: "testdata\\chartpath\\base",
267 },
268 {
269 name: "current directory path",
270 repo: "../charts/localdependency",
271 chartpath: "testdata/chartpath/charts",
272 expect: "testdata/chartpath/charts/localdependency",
273 winExpect: "testdata\\chartpath\\charts\\localdependency",
274 },
275 {
276 name: "invalid local path",
277 repo: "file://testdata/nonexistent",
278 chartpath: "testdata/chartpath",
279 err: true,
280 },
281 {
282 name: "invalid path under current directory",
283 repo: "charts/nonexistentdependency",
284 chartpath: "testdata/chartpath/charts",
285 err: true,
286 },
287 }
288
289 for _, tt := range tests {
290 t.Run(tt.name, func(t *testing.T) {
291 p, err := GetLocalPath(tt.repo, tt.chartpath)
292 if err != nil {
293 if tt.err {
294 return
295 }
296 t.Fatal(err)
297 }
298 if tt.err {
299 t.Fatalf("Expected error in test %q", tt.name)
300 }
301 expect := tt.expect
302 if runtime.GOOS == "windows" {
303 expect = tt.winExpect
304 }
305 if p != expect {
306 t.Errorf("%q: expected %q, got %q", tt.name, expect, p)
307 }
308 })
309 }
310 }
311
View as plain text