github.com/jenkins-x/jx/v2@v2.1.155/pkg/helm/helm_cli_test.go (about) 1 // +build unit 2 3 package helm_test 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "testing" 11 12 kube_test "github.com/jenkins-x/jx/v2/pkg/kube/mocks" 13 14 "github.com/jenkins-x/jx/v2/pkg/helm" 15 "github.com/stretchr/testify/assert" 16 17 mocks "github.com/jenkins-x/jx/v2/pkg/util/mocks" 18 . "github.com/petergtz/pegomock" 19 ) 20 21 const binary = "helm" 22 const binaryV3 = "helm3" 23 const cwd = "test" 24 const repo = "test-repo" 25 const repoURL = "http://test-repo" 26 const serviceAccount = "test-sa" 27 const namespace = "test-namespace" 28 const chart = "test-chart" 29 const releaseName = "test-release" 30 const listRepoOutput = ` 31 NAME URL 32 stable https://kubernetes-charts.storage.googleapis.com 33 local http://127.0.0.1:8879/charts 34 jenkins-x https://storage.googleapis.com/chartmuseum.jenkins-x.io 35 ` 36 const searchVersionOutput = ` 37 NAME CHART VERSION APP VERSION DESCRIPTION 38 jenkins-x/jenkins-x-platform 0.0.1481 Jenkins X 39 jenkins-x/jenkins-x-platform 0.0.1480 Jenkins X 40 jenkins-x/jenkins-x-platform 0.0.1479 Jenkins X 41 ` 42 const listReleasesOutput = ` 43 NAME REVISION UPDATED STATUS CHART NAMESPACE 44 jenkins-x 1 Mon Jul 2 16:16:20 2018 DEPLOYED jenkins-x-platform-0.0.1655 jx 45 jx-production 1 Mon Jul 2 16:22:47 2018 DEPLOYED env-0.0.1 jx-production 46 jx-staging 1 Mon Jul 2 16:21:06 2018 DEPLOYED env-0.0.1 jx-staging 47 jxing 1 Wed Jun 6 14:24:42 2018 DEPLOYED nginx-ingress-0.20.1 kube-system 48 vault-operator 1 Mon Jun 25 16:09:28 2018 DEPLOYED vault-operator-0.1.0 jx 49 ` 50 51 const listReleasesOutputHelm3 = ` 52 NAME NAMESPACE REVISION UPDATED STATUS CHART 53 jxing jx 2 2019-05-17 15:30:07.629472 +0100 BST deployed nginx-ingress-1.3.1` 54 55 func createHelm(t *testing.T, expectedError error, expectedOutput string) (*helm.HelmCLI, *mocks.MockCommander) { 56 return createHelmWithCwdAndHelmVersion(t, helm.V2, cwd, expectedError, expectedOutput) 57 } 58 59 func createHelmWithVersion(t *testing.T, version helm.Version, expectedError error, expectedOutput string) (*helm.HelmCLI, *mocks.MockCommander) { 60 return createHelmWithCwdAndHelmVersion(t, version, cwd, expectedError, expectedOutput) 61 } 62 63 func createHelmWithCwdAndHelmVersion(t *testing.T, version helm.Version, dir string, expectedError error, expectedOutput string) (*helm.HelmCLI, *mocks.MockCommander) { 64 RegisterMockTestingT(t) 65 runner := mocks.NewMockCommander() 66 When(runner.RunWithoutRetry()).ThenReturn(expectedOutput, expectedError) 67 helmBinary := binary 68 if version == helm.V3 { 69 helmBinary = binaryV3 70 } 71 mockKuber := kube_test.NewMockKuber() 72 cli := helm.NewHelmCLIWithRunner(runner, helmBinary, version, dir, true, mockKuber) 73 return cli, runner 74 } 75 76 func verifyArgs(t *testing.T, cli *helm.HelmCLI, runner *mocks.MockCommander, expectedArgs ...string) { 77 runner.VerifyWasCalledOnce().SetArgs(expectedArgs) 78 } 79 80 func TestNewHelmCLI(t *testing.T) { 81 cli := helm.NewHelmCLI(binary, helm.V2, cwd, true, "arg1 arg2 arg3") 82 assert.Equal(t, binary, cli.Binary) 83 assert.Equal(t, cwd, cli.CWD) 84 assert.Equal(t, helm.V2, cli.BinVersion) 85 assert.Equal(t, true, cli.Debug) 86 assert.NotNil(t, cli.Runner) 87 assert.Equal(t, []string{"arg1", "arg2", "arg3"}, cli.Runner.CurrentArgs()) 88 assert.Equal(t, binary, cli.Runner.CurrentName()) 89 assert.Equal(t, cwd, cli.Runner.CurrentDir()) 90 } 91 92 func TestInit(t *testing.T) { 93 expectedArgs := []string{"init", "--client-only", "--service-account", serviceAccount, 94 "--tiller-namespace", namespace, "--upgrade", "--wait", "--force-upgrade"} 95 helm, runner := createHelm(t, nil, "") 96 97 err := helm.Init(true, serviceAccount, namespace, true) 98 99 assert.NoError(t, err, "should init helm without any error") 100 verifyArgs(t, helm, runner, expectedArgs...) 101 } 102 103 func TestAddRepo(t *testing.T) { 104 expectedArgs := []string{"repo", "add", repo, repoURL} 105 helm, runner := createHelm(t, nil, "") 106 107 err := helm.AddRepo(repo, repoURL, "", "") 108 109 assert.NoError(t, err, "should add helm repo without any error") 110 verifyArgs(t, helm, runner, expectedArgs...) 111 } 112 113 func TestRemoveRepo(t *testing.T) { 114 expectedArgs := []string{"repo", "remove", repo} 115 helm, runner := createHelm(t, nil, "") 116 117 err := helm.RemoveRepo(repo) 118 119 assert.NoError(t, err, "should remove helm repo without any error") 120 verifyArgs(t, helm, runner, expectedArgs...) 121 } 122 123 func TestListRepos(t *testing.T) { 124 expectedArgs := []string{"repo", "list"} 125 helm, runner := createHelm(t, nil, listRepoOutput) 126 127 repos, err := helm.ListRepos() 128 assert.NoError(t, err, "should list helm repos without any error") 129 verifyArgs(t, helm, runner, expectedArgs...) 130 expectedRepos := map[string]string{ 131 "stable": "https://kubernetes-charts.storage.googleapis.com", 132 "local": "http://127.0.0.1:8879/charts", 133 "jenkins-x": "https://storage.googleapis.com/chartmuseum.jenkins-x.io", 134 } 135 assert.Equal(t, len(expectedRepos), len(repos), "should list the same number of repos") 136 for k, v := range repos { 137 assert.Equal(t, expectedRepos[k], v, "should parse correctly the repo URL") 138 } 139 } 140 141 func TestIsRepoMissing(t *testing.T) { 142 expectedArgs := []string{"repo", "list"} 143 helm, runner := createHelm(t, nil, listRepoOutput) 144 145 url := "https://storage.googleapis.com/chartmuseum.jenkins-x.io" 146 missing, _, err := helm.IsRepoMissing(url) 147 148 assert.NoError(t, err, "should search missing repos without any error") 149 verifyArgs(t, helm, runner, expectedArgs...) 150 assert.False(t, missing, "should find url '%s'", url) 151 152 url = "https://test" 153 missing, _, err = helm.IsRepoMissing(url) 154 155 assert.NoError(t, err, "search missing repos should not return an error") 156 assert.True(t, missing, "should not find url '%s'", url) 157 158 url = "http://127.0.0.1:8879/chartsv2" 159 missing, _, err = helm.IsRepoMissing(url) 160 161 assert.NoError(t, err, "search missing repos should not return an error") 162 assert.True(t, missing, "should not find url '%s'", url) 163 } 164 165 func TestUpdateRepo(t *testing.T) { 166 expectedArgs := []string{"repo", "update"} 167 helm, runner := createHelm(t, nil, "") 168 169 err := helm.UpdateRepo() 170 171 assert.NoError(t, err, "should update helm repo without any error") 172 verifyArgs(t, helm, runner, expectedArgs...) 173 } 174 175 func TestRemoveRequirementsLock(t *testing.T) { 176 dir, err := ioutil.TempDir("", "reqtest") 177 assert.NoError(t, err, "should be able to create a temporary dir") 178 defer os.RemoveAll(dir) 179 path := filepath.Join(dir, "requirements.lock") 180 ioutil.WriteFile(path, []byte("test"), 0600) 181 182 helm, _ := createHelmWithCwdAndHelmVersion(t, helm.V2, dir, nil, "") 183 184 err = helm.RemoveRequirementsLock() 185 assert.NoError(t, err, "should remove requirements.lock file") 186 } 187 188 func TestBuildDependency(t *testing.T) { 189 expectedArgs := []string{"dependency", "build"} 190 helm, runner := createHelm(t, nil, "") 191 192 err := helm.BuildDependency() 193 assert.NoError(t, err, "should build helm repo dependencies without any error") 194 verifyArgs(t, helm, runner, expectedArgs...) 195 } 196 197 func TestInstallChart(t *testing.T) { 198 value := []string{"test=true"} 199 valueString := []string{"context=test"} 200 valueFile := []string{"./myvalues.yaml"} 201 expectedArgs := []string{"install", "--wait", "--name", releaseName, "--namespace", namespace, 202 chart, "--set", value[0], "--set-string", valueString[0], "--values", valueFile[0]} 203 helm, runner := createHelm(t, nil, "") 204 205 err := helm.InstallChart(chart, releaseName, namespace, "", -1, value, valueString, valueFile, "", "", "") 206 assert.NoError(t, err, "should install the chart without any error") 207 verifyArgs(t, helm, runner, expectedArgs...) 208 } 209 210 func TestUpgradeChart(t *testing.T) { 211 value := []string{"test=true"} 212 valueString := []string{"context=test"} 213 valueFile := []string{"./myvalues.yaml"} 214 version := "0.0.1" 215 timeout := 600 216 expectedArgs := []string{"upgrade", "--namespace", namespace, "--install", "--wait", "--force", 217 "--timeout", fmt.Sprintf("%d", timeout), "--version", version, "--set", value[0], "--set-string", valueString[0], "--values", valueFile[0], releaseName, chart} 218 helm, runner := createHelm(t, nil, "") 219 220 err := helm.UpgradeChart(chart, releaseName, namespace, version, true, timeout, true, true, value, valueString, valueFile, "", "", "") 221 222 assert.NoError(t, err, "should upgrade the chart without any error") 223 verifyArgs(t, helm, runner, expectedArgs...) 224 } 225 226 func TestDeleteRelaese(t *testing.T) { 227 expectedArgs := []string{"delete", "--purge", releaseName} 228 helm, runner := createHelm(t, nil, "") 229 ns := "default" 230 231 err := helm.DeleteRelease(ns, releaseName, true) 232 233 assert.NoError(t, err, "should delete helm chart release without any error") 234 verifyArgs(t, helm, runner, expectedArgs...) 235 } 236 237 func TestStatusRelease(t *testing.T) { 238 expectedArgs := []string{"status", releaseName} 239 helm, runner := createHelm(t, nil, "") 240 ns := "default" 241 242 err := helm.StatusRelease(ns, releaseName) 243 244 assert.NoError(t, err, "should get the status of a helm chart release without any error") 245 verifyArgs(t, helm, runner, expectedArgs...) 246 } 247 248 func TestStatusReleaseWithOutputNoFormat(t *testing.T) { 249 expectedArgs := []string{"status", releaseName} 250 helm, runner := createHelm(t, nil, "") 251 ns := "default" 252 253 _, err := helm.StatusReleaseWithOutput(ns, releaseName, "") 254 255 assert.NoErrorf(t, err, "should return the status of the helm chart without format") 256 verifyArgs(t, helm, runner, expectedArgs...) 257 } 258 259 func TestStatusReleaseWithOutputWithFormat(t *testing.T) { 260 expectedArgs := []string{"status", releaseName, "--output", "json"} 261 helm, runner := createHelm(t, nil, "") 262 ns := "default" 263 264 _, err := helm.StatusReleaseWithOutput(ns, releaseName, "json") 265 266 assert.NoErrorf(t, err, "should return the status of the helm chart without in Json format") 267 verifyArgs(t, helm, runner, expectedArgs...) 268 } 269 270 func TestStatusReleases(t *testing.T) { 271 expectedArgs := []string{"list", "--all", "--namespace", "default"} 272 expectedStatusMap := map[string]string{ 273 "jenkins-x": "DEPLOYED", 274 "jx-production": "DEPLOYED", 275 "jx-staging": "DEPLOYED", 276 "jxing": "DEPLOYED", 277 "vault-operator": "DEPLOYED", 278 } 279 helm, runner := createHelm(t, nil, listReleasesOutput) 280 ns := "default" 281 282 releaseMap, _, err := helm.ListReleases(ns) 283 284 assert.NoError(t, err, "should list the release statuses without any error") 285 verifyArgs(t, helm, runner, expectedArgs...) 286 for release, details := range releaseMap { 287 assert.Equal(t, expectedStatusMap[release], details.Status, "expected details '%s', got '%s'", 288 expectedStatusMap[release], details) 289 } 290 } 291 292 func TestStatusReleasesForHelm3(t *testing.T) { 293 expectedArgs := []string{"list", "--all", "--namespace", "default"} 294 expectedStatusMap := map[string]string{ 295 "jxing": "DEPLOYED", 296 } 297 helm, runner := createHelmWithVersion(t, helm.V3, nil, listReleasesOutputHelm3) 298 ns := "default" 299 300 releaseMap, _, err := helm.ListReleases(ns) 301 302 assert.NoError(t, err, "should list the release statuses without any error") 303 verifyArgs(t, helm, runner, expectedArgs...) 304 for release, details := range releaseMap { 305 assert.Equal(t, expectedStatusMap[release], details.Status, "expected details '%s', got '%s'", 306 expectedStatusMap[release], details) 307 } 308 } 309 310 func TestLint(t *testing.T) { 311 expectedArgs := []string{"lint", 312 "--set", "tags.jx-lint=true", 313 "--set", "global.jxLint=true", 314 "--set-string", "global.jxTypeEnv=lint", 315 } 316 expectedOutput := "test" 317 helm, runner := createHelm(t, nil, expectedOutput) 318 319 output, err := helm.Lint(nil) 320 321 assert.NoError(t, err, "should lint the chart without any error") 322 verifyArgs(t, helm, runner, expectedArgs...) 323 assert.Equal(t, "test", output) 324 } 325 326 func TestVersion(t *testing.T) { 327 var versionTests = []struct { 328 versionString string 329 expectedSemanticVersion string 330 shouldError bool 331 }{ 332 {"Client: v2.16.3+g1ee0254", "2.16.3", false}, 333 {"v3.0.3+gac925eb", "3.0.3", false}, 334 {"3.0.3+gac925eb", "3.0.3", false}, 335 {"", "", true}, 336 {"foo", "", true}, 337 } 338 339 for _, versionTest := range versionTests { 340 t.Run(versionTest.versionString, func(t *testing.T) { 341 helm, runner := createHelm(t, nil, versionTest.versionString) 342 actualVersion, err := helm.Version(false) 343 344 if versionTest.shouldError { 345 assert.Error(t, err, "should not be able to get semantic version from version output") 346 assert.Equal(t, versionTest.expectedSemanticVersion, actualVersion) 347 } else { 348 assert.NoError(t, err, "should get the version without any error") 349 verifyArgs(t, helm, runner, "version", "--short", "--client") 350 assert.Equal(t, versionTest.expectedSemanticVersion, actualVersion) 351 } 352 }) 353 } 354 } 355 356 func TestSearchChartVersions(t *testing.T) { 357 expectedOutput := searchVersionOutput 358 expectedArgs := []string{"search", chart, "--versions"} 359 helm, runner := createHelm(t, nil, expectedOutput) 360 361 versions, err := helm.SearchCharts(chart, true) 362 363 assert.NoError(t, err, "should search chart versions without any error") 364 verifyArgs(t, helm, runner, expectedArgs...) 365 expectedVersions := []string{"0.0.1481", "0.0.1480", "0.0.1479"} 366 for i, version := range versions { 367 assert.Equal(t, expectedVersions[i], version.ChartVersion, "should parse the version '%s'", version) 368 } 369 } 370 371 func TestFindChart(t *testing.T) { 372 dir, err := ioutil.TempDir("", "charttest") 373 assert.NoError(t, err, "should be able to create a temporary dir") 374 defer os.RemoveAll(dir) 375 path := filepath.Join(dir, helm.ChartFileName) 376 ioutil.WriteFile(path, []byte("test"), 0600) 377 helm, _ := createHelmWithCwdAndHelmVersion(t, helm.V2, dir, nil, "") 378 379 chartFile, err := helm.FindChart() 380 381 assert.NoError(t, err, "should find the chart file") 382 assert.Equal(t, path, chartFile, "should find chart file '%s'", path) 383 } 384 385 func TestPackage(t *testing.T) { 386 expectedArgs := []string{"package", cwd} 387 helm, runner := createHelm(t, nil, "") 388 389 err := helm.PackageChart() 390 391 assert.NoError(t, err, "should package chart without any error") 392 verifyArgs(t, helm, runner, expectedArgs...) 393 }