github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/internal/resolver/resolver_test.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package resolver 17 18 import ( 19 "runtime" 20 "testing" 21 22 "github.com/stefanmcshane/helm/pkg/chart" 23 "github.com/stefanmcshane/helm/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 // Check fields. 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 }