diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d8e8e3379..1b1de9e55 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -37,9 +37,17 @@ updates: directory: "/" schedule: interval: "daily" + groups: + github-actions: + patterns: + - "*" - # Keep dev-v3 GitHub Actions up to date, while Helm v3 is within support package-ecosystem: "github-actions" target-branch: "dev-v3" directory: "/" schedule: interval: "daily" + groups: + github-actions: + patterns: + - "*" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..46d20af9c --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,2 @@ +"v4.x": + - base-branch: "main" diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index b4ce89f26..9503674ed 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -18,11 +18,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e87ec8ec2..d8c1a9d12 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -44,11 +44,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 + uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -59,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 + uses: github/codeql-action/autobuild@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -73,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # pinv4.37.0 + uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # pinv4.37.3 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 6355db230..955f12002 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -13,11 +13,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index c7c9b3d53..0fae0be3a 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -19,13 +19,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 with: persist-credentials: false - name: Add variables to environment file run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml new file mode 100644 index 000000000..11f0f5d00 --- /dev/null +++ b/.github/workflows/label-pr.yml @@ -0,0 +1,16 @@ +name: Label PRs +on: + pull_request_target: + branches: [main] + types: [opened, reopened, edited, synchronize] +permissions: {} +jobs: + label: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # pin@v7.0.0 + with: + sync-labels: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ee2612917..2b2f93f4d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest-16-cores steps: - name: Checkout source code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 with: fetch-depth: 0 @@ -28,7 +28,7 @@ jobs: run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true @@ -85,7 +85,7 @@ jobs: if: github.ref == 'refs/heads/main' && github.repository == 'helm/helm' steps: - name: Checkout source code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # pin@v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # pin@v7.0.1 with: fetch-depth: 0 @@ -93,7 +93,7 @@ jobs: run: cat ".github/env" >> "$GITHUB_ENV" - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # pin@6.5.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # pin@7.0.0 with: go-version: '${{ env.GOLANG_VERSION }}' check-latest: true diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 343669859..6c142b511 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -28,12 +28,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 with: results_file: results.sarif results_format: sarif @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 with: sarif_file: results.sarif diff --git a/.golangci.yml b/.golangci.yml index 6727d3001..5b6d7cf8e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -74,9 +74,9 @@ linters: errorlint: # Check for plain type assertions and type switches. - asserts: false + asserts: true # Check for plain error comparisons. - comparison: false + comparison: true exhaustive: default-signifies-exhaustive: true diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 0c4f697b6..60df8a308 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main // import "helm.sh/helm/v4/cmd/helm" +package main import ( "errors" diff --git a/go.mod b/go.mod index 016b0fded..6b9878bb2 100644 --- a/go.mod +++ b/go.mod @@ -39,14 +39,14 @@ require ( golang.org/x/term v0.45.0 golang.org/x/text v0.40.0 gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.36.2 - k8s.io/apiextensions-apiserver v0.36.2 - k8s.io/apimachinery v0.36.2 - k8s.io/apiserver v0.36.2 - k8s.io/cli-runtime v0.36.2 - k8s.io/client-go v0.36.2 + k8s.io/api v0.36.3 + k8s.io/apiextensions-apiserver v0.36.3 + k8s.io/apimachinery v0.36.3 + k8s.io/apiserver v0.36.3 + k8s.io/cli-runtime v0.36.3 + k8s.io/client-go v0.36.3 k8s.io/klog/v2 v2.140.0 - k8s.io/kubectl v0.36.2 + k8s.io/kubectl v0.36.3 oras.land/oras-go/v2 v2.6.2 sigs.k8s.io/controller-runtime v0.24.1 sigs.k8s.io/kustomize/kyaml v0.21.1 @@ -165,18 +165,18 @@ require ( golang.org/x/sys v0.47.0 // indirect golang.org/x/time v0.15.0 // indirect golang.org/x/tools v0.47.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect - google.golang.org/grpc v1.80.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/grpc v1.82.1 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/component-base v0.36.2 // indirect + k8s.io/component-base v0.36.3 // indirect k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/kustomize/api v0.21.1 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect ) diff --git a/go.sum b/go.sum index d097bc72c..e5933d99a 100644 --- a/go.sum +++ b/go.sum @@ -465,12 +465,12 @@ golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -487,26 +487,26 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= -k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= -k8s.io/apiextensions-apiserver v0.36.2 h1:3O5gqOj/dt2XWWbpMe+TXWpE9yU6pjM/tXxtHHJT/K4= -k8s.io/apiextensions-apiserver v0.36.2/go.mod h1:cL1tBWe8XSaP1H30iWKGo7hf6iAUUUJPEU70dskmAnA= -k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= -k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= -k8s.io/apiserver v0.36.2 h1:6vMnkmHZPeBloNkHUhmZYq7Ylv8WIB8xjyEl+eSt26E= -k8s.io/apiserver v0.36.2/go.mod h1:9PoQ2ikCytrZyZg11mGhLEF5m8Rgsb5FJmYJ4Wvnl1k= -k8s.io/cli-runtime v0.36.2 h1:CconTvEeV4DJs4ZX3HQKCFbFRGsm6OtuBM9yjmMP2VM= -k8s.io/cli-runtime v0.36.2/go.mod h1:LddcjiMf4YlnHO7c1Y7rEtDqL84FyiYVLco7V679GUU= -k8s.io/client-go v0.36.2 h1:bfgxmFKc9CgqsgX4xKLAAdmTQlWee7Ob/HlDOrJ5TBI= -k8s.io/client-go v0.36.2/go.mod h1:1vgO4OAlfPnoLcb+Rze2GF5rAr14w8qjrYMoyXJzQj0= -k8s.io/component-base v0.36.2 h1:Z0VH80O7Ng0HDZnZj3WRR3urEGa0kTwmO8CwEwjVK1w= -k8s.io/component-base v0.36.2/go.mod h1:mGfFOA7Gwpdm1VW2cwSQYbiDIlz8GD2WGwH88QSeCyA= +k8s.io/api v0.36.3 h1:NxB+05W2UGqXWFXcLO0RB5cnqnUPP5v5sVlaOH0Iz4w= +k8s.io/api v0.36.3/go.mod h1:JzLQKqRHC5+I8RVj/lS3lCg0mg6nWI9Fo/Sk3ElxHzg= +k8s.io/apiextensions-apiserver v0.36.3 h1:dPmOAPhwTtqb1bTxbFPsy18KHPhktQeO3WUPXunZIB0= +k8s.io/apiextensions-apiserver v0.36.3/go.mod h1:KTXFqgXiuw2pRoL+Wpmttqc+up9Xt/GohadPWeLLOa4= +k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM= +k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE= +k8s.io/apiserver v0.36.3 h1:MGSg2SkdfuytiDEcRylT5mQFmmSsbx90XFUO67Y4bsQ= +k8s.io/apiserver v0.36.3/go.mod h1:fVH7zv9EUNUA7Fl7LtDKh8aB9W7u1VQPSGtWV5SjUxg= +k8s.io/cli-runtime v0.36.3 h1:g+eJ+M1sYpnNYp/q5fzaw2KejIL0Q7DH+xFl6YVoL4U= +k8s.io/cli-runtime v0.36.3/go.mod h1:hZpAqK8nSFXvvLaVCbzUPVp8e9TRLSTCfpNzMt7s3tE= +k8s.io/client-go v0.36.3 h1:M4JdVzXxYcZk4fGpfDdYnxSwhLKWCFoQsHW6t+z8Hfg= +k8s.io/client-go v0.36.3/go.mod h1:gcPwr0c87vjjG6HB6pWEqOeuYVoXSsREjzux2j6GF30= +k8s.io/component-base v0.36.3 h1:vc/UFvPCkW0irPz84LAodAL1j3f4xktPM6dDJIEheAY= +k8s.io/component-base v0.36.3/go.mod h1:hZbNFG+gCMl9EbykDGEu73feKP9/Cq6JsV4pTo9GTO8= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= -k8s.io/kubectl v0.36.2 h1:rpUGGpeL09XVOLep2yle5jrtk//JA1L6ZHfkQQtVEwk= -k8s.io/kubectl v0.36.2/go.mod h1:gVbQ3B/yb4bSR2ggQ7rd0W6icUSWs7sduH4e16Vii+0= +k8s.io/kubectl v0.36.3 h1:TesKp+XYQEjPYoFvuobcVnuvira2+/xAVlq//+kksaI= +k8s.io/kubectl v0.36.3/go.mod h1:W+NEb1CzBGmoaI1Nrpn2ETo9omNBl0AsyxnnMT40N6E= k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc= k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= oras.land/oras-go/v2 v2.6.2 h1:N04RXngAp1LJKTG6ifz3xHPipasEkWr+hFmInja5YKo= @@ -521,7 +521,7 @@ sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7 sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/internal/chart/v3/dependency_test.go b/internal/chart/v3/dependency_test.go index fcea19aea..54b9ed9da 100644 --- a/internal/chart/v3/dependency_test.go +++ b/internal/chart/v3/dependency_test.go @@ -17,6 +17,8 @@ package v3 import ( "testing" + + "github.com/stretchr/testify/assert" ) func TestValidateDependency(t *testing.T) { @@ -35,10 +37,10 @@ func TestValidateDependency(t *testing.T) { } { dep.Alias = value res := dep.Validate() - if res != nil && !shouldFail { - t.Errorf("Failed on case %q", dep.Alias) - } else if res == nil && shouldFail { - t.Errorf("Expected failure for %q", dep.Alias) + if shouldFail { + assert.Errorf(t, res, "Expected failure for %q", dep.Alias) + } else { + assert.NoErrorf(t, res, "Failed on case %q", dep.Alias) } } } diff --git a/internal/chart/v3/lint/lint.go b/internal/chart/v3/lint/lint.go index ea8ca3d60..193f0f796 100644 --- a/internal/chart/v3/lint/lint.go +++ b/internal/chart/v3/lint/lint.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package lint // import "helm.sh/helm/v4/internal/chart/v3/lint" +package lint import ( "path/filepath" diff --git a/internal/chart/v3/lint/lint_test.go b/internal/chart/v3/lint/lint_test.go index 8916c6e22..b0a7ce651 100644 --- a/internal/chart/v3/lint/lint_test.go +++ b/internal/chart/v3/lint/lint_test.go @@ -114,7 +114,7 @@ func TestBadValuesV3(t *testing.T) { func TestBadCrdFileV3(t *testing.T) { var values map[string]any m := RunAll(badCrdFileDir, values, namespace).Messages - assert.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) + require.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) require.ErrorContains(t, m[0].Err, "apiVersion is not in 'apiextensions.k8s.io'") assert.ErrorContains(t, m[1].Err, "object kind is not 'CustomResourceDefinition'") } @@ -122,8 +122,7 @@ func TestBadCrdFileV3(t *testing.T) { func TestGoodChart(t *testing.T) { var values map[string]any m := RunAll(goodChartDir, values, namespace).Messages - if len(m) != 0 { - t.Error("All returned linter messages when it shouldn't have") + if !assert.Empty(t, m, "All returned linter messages when it shouldn't have") { for i, msg := range m { t.Logf("Message %d: %s", i, msg) } @@ -143,13 +142,12 @@ func TestHelmCreateChart(t *testing.T) { // Note: we test with strict=true here, even though others have // strict = false. m := RunAll(createdChart, values, namespace, WithSkipSchemaValidation(true)).Messages - if ll := len(m); ll != 1 { - t.Errorf("All should have had exactly 1 error. Got %d", ll) + if !assert.Len(t, m, 1, "All should have had exactly 1 error") { for i, msg := range m { t.Logf("Message %d: %s", i, msg.Error()) } - } else if msg := m[0].Err.Error(); !strings.Contains(msg, "icon is recommended") { - t.Errorf("Unexpected lint error: %s", msg) + } else { + assert.ErrorContains(t, m[0].Err, "icon is recommended") } } @@ -192,8 +190,7 @@ func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) { func TestSubChartValuesChart(t *testing.T) { var values map[string]any m := RunAll(subChartValuesDir, values, namespace).Messages - if len(m) != 0 { - t.Error("All returned linter messages when it shouldn't have") + if !assert.Empty(t, m, "All returned linter messages when it shouldn't have") { for i, msg := range m { t.Logf("Message %d: %s", i, msg) } diff --git a/internal/chart/v3/lint/rules/chartfile.go b/internal/chart/v3/lint/rules/chartfile.go index db7ac61dc..c76654d53 100644 --- a/internal/chart/v3/lint/rules/chartfile.go +++ b/internal/chart/v3/lint/rules/chartfile.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" +package rules import ( "errors" diff --git a/internal/chart/v3/lint/rules/chartfile_test.go b/internal/chart/v3/lint/rules/chartfile_test.go index 9ac4ce75e..0638589b6 100644 --- a/internal/chart/v3/lint/rules/chartfile_test.go +++ b/internal/chart/v3/lint/rules/chartfile_test.go @@ -52,24 +52,19 @@ func TestValidateChartYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingChartFilePath, os.ModePerm) defer os.Remove(nonExistingChartFilePath) - err := validateChartYamlNotDirectory(nonExistingChartFilePath) - assert.Error(t, err, "validateChartYamlNotDirectory to return a linter error, got no error") + assert.Error(t, validateChartYamlNotDirectory(nonExistingChartFilePath), "validateChartYamlNotDirectory to return a linter error, got no error") } func TestValidateChartYamlFormat(t *testing.T) { - err := validateChartYamlFormat(errors.New("Read error")) - require.Error(t, err, "validateChartYamlFormat to return a linter error, got no error") + require.Error(t, validateChartYamlFormat(errors.New("Read error")), "validateChartYamlFormat to return a linter error, got no error") - err = validateChartYamlFormat(nil) - assert.NoError(t, err, "validateChartYamlFormat to return no error, got a linter error") + assert.NoError(t, validateChartYamlFormat(nil), "validateChartYamlFormat to return no error, got a linter error") } func TestValidateChartName(t *testing.T) { - err := validateChartName(badChart) - require.Error(t, err, "validateChartName to return a linter error, got no error") + require.Error(t, validateChartName(badChart), "validateChartName to return a linter error, got no error") - err = validateChartName(badChartName) - assert.Error(t, err, "expected validateChartName to return a linter error for an invalid name, got no error") + assert.Error(t, validateChartName(badChartName), "expected validateChartName to return a linter error for an invalid name, got no error") } func TestValidateChartVersion(t *testing.T) { @@ -90,15 +85,13 @@ func TestValidateChartVersion(t *testing.T) { for i, test := range failTest { t.Run(strconv.Itoa(i), func(t *testing.T) { badChart.Version = test.Version - err := validateChartVersion(badChart) - require.ErrorContains(t, err, test.ErrorMsg, "validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) + require.ErrorContains(t, validateChartVersion(badChart), test.ErrorMsg, "validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) }) } for _, version := range successTest { badChart.Version = version - err := validateChartVersion(badChart) - assert.NoError(t, err, "validateChartVersion(%s) to return no error, got a linter error", version) + assert.NoError(t, validateChartVersion(badChart), "validateChartVersion(%s) to return no error, got a linter error", version) } } @@ -124,24 +117,20 @@ func TestValidateChartMaintainer(t *testing.T) { for _, test := range failTest { t.Run(fmt.Sprintf("%s, %s", test.Name, test.Email), func(t *testing.T) { badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - require.ErrorContains(t, err, test.ErrorMsg, "validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) + require.ErrorContains(t, validateChartMaintainer(badChart), test.ErrorMsg, "validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) }) } for _, test := range successTest { t.Run(fmt.Sprintf("%s, %s", test.Name, test.Email), func(t *testing.T) { badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - require.NoError(t, err, "validateChartMaintainer(%s, %s) to return no error", test.Name, test.Email) + require.NoError(t, validateChartMaintainer(badChart), "validateChartMaintainer(%s, %s) to return no error", test.Name, test.Email) }) } // Testing for an empty maintainer badChart.Maintainers = []*chart.Maintainer{nil} - err := validateChartMaintainer(badChart) - require.Error(t, err, "validateChartMaintainer did not return error for nil maintainer as expected") - assert.EqualError(t, err, "a maintainer entry is empty", "validateChartMaintainer returned unexpected error for nil maintainer") + assert.EqualError(t, validateChartMaintainer(badChart), "a maintainer entry is empty") } func TestValidateChartSources(t *testing.T) { @@ -150,15 +139,13 @@ func TestValidateChartSources(t *testing.T) { for _, test := range failTest { t.Run(test, func(t *testing.T) { badChart.Sources = []string{test} - err := validateChartSources(badChart) - require.ErrorContains(t, err, "invalid source URL", "validateChartSources(%s) to return \"invalid source URL\", got no error", test) + require.ErrorContains(t, validateChartSources(badChart), "invalid source URL", "validateChartSources(%s) to return \"invalid source URL\", got no error", test) }) } for _, test := range successTest { badChart.Sources = []string{test} - err := validateChartSources(badChart) - assert.NoError(t, err, "validateChartSources(%s) to return no error", test) + assert.NoError(t, validateChartSources(badChart), "validateChartSources(%s) to return no error", test) } } @@ -168,19 +155,13 @@ func TestValidateChartIconPresence(t *testing.T) { Icon: "", } - err := validateChartIconPresence(testChart) - - require.Error(t, err, "validateChartIconPresence to return a linter error, got no error") - assert.ErrorContains(t, err, "icon is recommended", "expected %q", "icon is recommended") + assert.ErrorContains(t, validateChartIconPresence(testChart), "icon is recommended", "expected %q", "icon is recommended") }) t.Run("Icon present", func(t *testing.T) { testChart := &chart.Metadata{ Icon: "http://example.org/icon.png", } - - err := validateChartIconPresence(testChart) - - assert.NoError(t, err, "Unexpected error") + assert.NoError(t, validateChartIconPresence(testChart)) }) } @@ -190,15 +171,13 @@ func TestValidateChartIconURL(t *testing.T) { for _, test := range failTest { t.Run(test, func(t *testing.T) { badChart.Icon = test - err := validateChartIconURL(badChart) - require.ErrorContains(t, err, "invalid icon URL", "validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) + require.ErrorContains(t, validateChartIconURL(badChart), "invalid icon URL", "validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) }) } for _, test := range successTest { badChart.Icon = test - err := validateChartIconURL(badChart) - assert.NoError(t, err, "validateChartIconURL(%s) to return no error", test) + assert.NoError(t, validateChartIconURL(badChart), "validateChartIconURL(%s) to return no error", test) } } diff --git a/internal/chart/v3/lint/rules/crds_test.go b/internal/chart/v3/lint/rules/crds_test.go index 60cb1b5ba..9009c1801 100644 --- a/internal/chart/v3/lint/rules/crds_test.go +++ b/internal/chart/v3/lint/rules/crds_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/chart/v3/lint/support" ) @@ -33,7 +34,7 @@ func TestInvalidCrdsDir(t *testing.T) { Crds(&linter) res := linter.Messages - assert.Len(t, res, 1) + require.Len(t, res, 1) assert.ErrorContains(t, res[0].Err, "not a directory") } diff --git a/internal/chart/v3/lint/rules/dependencies.go b/internal/chart/v3/lint/rules/dependencies.go index f45153728..2f558aaf0 100644 --- a/internal/chart/v3/lint/rules/dependencies.go +++ b/internal/chart/v3/lint/rules/dependencies.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" +package rules import ( "fmt" diff --git a/internal/chart/v3/lint/rules/deprecations.go b/internal/chart/v3/lint/rules/deprecations.go index 9c73268af..85dddd114 100644 --- a/internal/chart/v3/lint/rules/deprecations.go +++ b/internal/chart/v3/lint/rules/deprecations.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" +package rules import ( "fmt" diff --git a/internal/chart/v3/lint/rules/deprecations_test.go b/internal/chart/v3/lint/rules/deprecations_test.go index a255abf50..96462bc15 100644 --- a/internal/chart/v3/lint/rules/deprecations_test.go +++ b/internal/chart/v3/lint/rules/deprecations_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/internal/chart/v3/lint/rules" +package rules import ( "testing" @@ -29,14 +29,12 @@ func TestValidateNoDeprecations(t *testing.T) { Kind: "Deployment", } err := validateNoDeprecations(deprecated, nil) - var depErr deprecatedAPIError require.Error(t, err, "Expected deprecated extension to be flagged") + var depErr deprecatedAPIError require.ErrorAs(t, err, &depErr, "Expected error to be of type deprecatedAPIError") - require.NotEmpty(t, depErr.Message, "Expected error message to be non-blank: %v", err) - - err = validateNoDeprecations(&k8sYamlStruct{ + require.NotEmpty(t, depErr.Message, "Expected error message to be non-blank") + assert.NoError(t, validateNoDeprecations(&k8sYamlStruct{ APIVersion: "v1", Kind: "Pod", - }, nil) - assert.NoError(t, err, "Expected a v1 Pod to not be deprecated") + }, nil), "Expected a v1 Pod to not be deprecated") } diff --git a/internal/chart/v3/lint/rules/template_test.go b/internal/chart/v3/lint/rules/template_test.go index 0b83e1cd5..3271a5bbe 100644 --- a/internal/chart/v3/lint/rules/template_test.go +++ b/internal/chart/v3/lint/rules/template_test.go @@ -37,13 +37,11 @@ const templateTestBasedir = "./testdata/albatross" func TestValidateAllowedExtension(t *testing.T) { var failTest = []string{"/foo", "/test.toml"} for _, test := range failTest { - err := validateAllowedExtension(test) - require.ErrorContains(t, err, "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) + require.ErrorContains(t, validateAllowedExtension(test), "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { - err := validateAllowedExtension(test) - assert.NoError(t, err, "validateAllowedExtension('%s') to return no error", test) + assert.NoError(t, validateAllowedExtension(test), "validateAllowedExtension('%s') to return no error", test) } } @@ -58,8 +56,7 @@ func TestTemplateParsing(t *testing.T) { res := linter.Messages require.Len(t, res, 1, "Expected one error, got %d, %v", len(res), res) - - assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError", "Unexpected error: %s", res[0]) + assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError") } var wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") @@ -86,7 +83,7 @@ func TestMultiTemplateFail(t *testing.T) { require.Len(t, res, 1, "Expected 1 error, got %d, %v", len(res), res) - assert.ErrorContains(t, res[0].Err, "object name does not conform to Kubernetes naming requirements", "Unexpected error: %s", res[0].Err) + assert.ErrorContains(t, res[0].Err, "object name does not conform to Kubernetes naming requirements") } func TestValidateMetadataName(t *testing.T) { @@ -202,12 +199,12 @@ func TestDeprecatedAPIFails(t *testing.T) { linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates(&linter, values, namespace, strict) - if l := len(linter.Messages); l != 1 { + if !assert.Len(t, linter.Messages, 1) { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) } - t.Fatalf("Expected 1 lint error, got %d", l) } + require.Len(t, linter.Messages, 1, "Expected 1 lint error") var err deprecatedAPIError require.ErrorAs(t, linter.Messages[0].Err, &err, "Expected error to be of type deprecatedAPIError") @@ -255,8 +252,7 @@ func TestStrictTemplateParsingMapError(t *testing.T) { ChartDir: filepath.Join(dir, ch.Metadata.Name), } Templates(linter, ch.Values, namespace, strict) - if len(linter.Messages) != 0 { - t.Errorf("expected zero messages, got %d", len(linter.Messages)) + if !assert.Empty(t, linter.Messages, "expected zero messages") { for i, msg := range linter.Messages { t.Logf("Message %d: %q", i, msg) } @@ -292,8 +288,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - err := validateMatchSelector(md, manifest) - require.NoError(t, err) + require.NoError(t, validateMatchSelector(md, manifest)) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -315,8 +310,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - err = validateMatchSelector(md, manifest) - require.NoError(t, err) + require.NoError(t, validateMatchSelector(md, manifest)) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -335,8 +329,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - err = validateMatchSelector(md, manifest) - assert.Error(t, err, "expected Deployment with no selector to fail") + assert.Error(t, validateMatchSelector(md, manifest), "expected Deployment with no selector to fail") } func TestValidateTopIndentLevel(t *testing.T) { @@ -349,8 +342,11 @@ func TestValidateTopIndentLevel(t *testing.T) { " apiVersion:foo": true, "\n\n apiVersion:foo\n\n": true, } { - if err := validateTopIndentLevel(doc); (err == nil) == shouldFail { - t.Errorf("Expected %t for %q", shouldFail, doc) + err := validateTopIndentLevel(doc) + if shouldFail { + assert.Errorf(t, err, "Expected %t for %q", shouldFail, doc) + } else { + assert.NoErrorf(t, err, "Expected %t for %q", shouldFail, doc) } } } @@ -379,12 +375,12 @@ func TestEmptyWithCommentsManifests(t *testing.T) { linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates(&linter, values, namespace, strict) - if l := len(linter.Messages); l > 0 { + if !assert.Empty(t, linter.Messages) { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) } - t.Fatalf("Expected 0 lint errors, got %d", l) } + require.Empty(t, linter.Messages, "Expected 0 lint errors") } func TestValidateListAnnotations(t *testing.T) { md := &k8sYamlStruct{ diff --git a/internal/chart/v3/lint/rules/values_test.go b/internal/chart/v3/lint/rules/values_test.go index c87607f2d..7f1177729 100644 --- a/internal/chart/v3/lint/rules/values_test.go +++ b/internal/chart/v3/lint/rules/values_test.go @@ -56,8 +56,7 @@ func TestValidateValuesYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingValuesFilePath, os.ModePerm) defer os.Remove(nonExistingValuesFilePath) - err := validateValuesFileExistence(nonExistingValuesFilePath) - assert.Error(t, err, "validateValuesFileExistence to return a linter error, got no error") + assert.Error(t, validateValuesFileExistence(nonExistingValuesFilePath), "validateValuesFileExistence to return a linter error, got no error") } func TestValidateValuesFileWellFormed(t *testing.T) { @@ -150,7 +149,7 @@ func TestValidateValuesFile(t *testing.T) { require.NoError(t, err, "Failed validation") } else { require.Error(t, err, "expected values file to fail parsing") - assert.ErrorContains(t, err, tt.errorMessage, "Failed with unexpected error") + assert.ErrorContains(t, err, tt.errorMessage) } }) } diff --git a/internal/chart/v3/lint/support/doc.go b/internal/chart/v3/lint/support/doc.go index 2d54a9b7d..80b1d2169 100644 --- a/internal/chart/v3/lint/support/doc.go +++ b/internal/chart/v3/lint/support/doc.go @@ -20,4 +20,4 @@ Package support contains tools for linting charts. Linting is the process of testing charts for errors or warnings regarding formatting, compilation, or standards compliance. */ -package support // import "helm.sh/helm/v4/internal/chart/v3/lint/support" +package support diff --git a/internal/chart/v3/lint/support/message_test.go b/internal/chart/v3/lint/support/message_test.go index ce5b5e42e..d07cf9ed4 100644 --- a/internal/chart/v3/lint/support/message_test.go +++ b/internal/chart/v3/lint/support/message_test.go @@ -19,6 +19,9 @@ package support import ( "errors" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var errLint = errors.New("lint failed") @@ -47,33 +50,19 @@ func TestRunLinterRule(t *testing.T) { linter := Linter{} for _, test := range tests { isValid := linter.RunLinterRule(test.Severity, "chart", test.LintError) - if len(linter.Messages) != test.ExpectedMessages { - t.Errorf("RunLinterRule(%d, \"chart\", %v), linter.Messages should now have %d message, we got %d", test.Severity, test.LintError, test.ExpectedMessages, len(linter.Messages)) - } - - if linter.HighestSeverity != test.ExpectedHighestSeverity { - t.Errorf("RunLinterRule(%d, \"chart\", %v), linter.HighestSeverity should be %d, we got %d", test.Severity, test.LintError, test.ExpectedHighestSeverity, linter.HighestSeverity) - } - - if isValid != test.ExpectedReturn { - t.Errorf("RunLinterRule(%d, \"chart\", %v), should have returned %t but returned %t", test.Severity, test.LintError, test.ExpectedReturn, isValid) - } + assert.Lenf(t, linter.Messages, test.ExpectedMessages, "RunLinterRule(%d, \"chart\", %v), linter.Messages should now have %d message, we got %d", test.Severity, test.LintError, test.ExpectedMessages, len(linter.Messages)) + assert.Equalf(t, test.ExpectedHighestSeverity, linter.HighestSeverity, "RunLinterRule(%d, \"chart\", %v), linter.HighestSeverity should be %d, we got %d", test.Severity, test.LintError, test.ExpectedHighestSeverity, linter.HighestSeverity) + assert.Equalf(t, test.ExpectedReturn, isValid, "RunLinterRule(%d, \"chart\", %v), should have returned %t but returned %t", test.Severity, test.LintError, test.ExpectedReturn, isValid) } } func TestMessage(t *testing.T) { m := Message{ErrorSev, "Chart.yaml", errors.New("Foo")} - if m.Error() != "[ERROR] Chart.yaml: Foo" { - t.Errorf("Unexpected output: %s", m.Error()) - } + require.EqualError(t, m, "[ERROR] Chart.yaml: Foo") m = Message{WarningSev, "templates/", errors.New("Bar")} - if m.Error() != "[WARNING] templates/: Bar" { - t.Errorf("Unexpected output: %s", m.Error()) - } + require.EqualError(t, m, "[WARNING] templates/: Bar") m = Message{InfoSev, "templates/rc.yaml", errors.New("FooBar")} - if m.Error() != "[INFO] templates/rc.yaml: FooBar" { - t.Errorf("Unexpected output: %s", m.Error()) - } + assert.EqualError(t, m, "[INFO] templates/rc.yaml: FooBar") } diff --git a/internal/chart/v3/loader/load_test.go b/internal/chart/v3/loader/load_test.go index 5caec7815..dd5fdc8db 100644 --- a/internal/chart/v3/loader/load_test.go +++ b/internal/chart/v3/loader/load_test.go @@ -25,7 +25,6 @@ import ( "log" "os" "path/filepath" - "reflect" "runtime" "strings" "testing" @@ -41,13 +40,9 @@ import ( func TestLoadDir(t *testing.T) { l, err := Loader("testdata/frobnitz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -60,33 +55,24 @@ func TestLoadDirWithDevNull(t *testing.T) { } l, err := Loader("testdata/frobnitz_with_dev_null") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } - if _, err := l.Load(); err == nil { - t.Error("packages with an irregular file (/dev/null) should not load") - } + require.NoError(t, err, "Failed to load testdata") + _, err = l.Load() + assert.Error(t, err, "packages with an irregular file (/dev/null) should not load") } func TestLoadDirWithSymlink(t *testing.T) { sym := filepath.Join("..", "LICENSE") link := filepath.Join("testdata", "frobnitz_with_symlink", "LICENSE") - if err := os.Symlink(sym, link); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Symlink(sym, link)) defer os.Remove(link) l, err := Loader("testdata/frobnitz_with_symlink") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -109,8 +95,7 @@ func TestBomTestData(t *testing.T) { defer unzipped.Close() for _, testFile := range testFiles { data := make([]byte, 3) - err := unzipped.Reset(bytes.NewReader(archive)) - require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") + require.NoErrorf(t, unzipped.Reset(bytes.NewReader(archive)), "Error reading archive frobnitz_with_bom.tgz") tr := tar.NewReader(unzipped) for { file, err := tr.Next() @@ -132,13 +117,9 @@ func TestBomTestData(t *testing.T) { func TestLoadDirWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -148,13 +129,9 @@ func TestLoadDirWithUTFBOM(t *testing.T) { func TestLoadArchiveWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -164,13 +141,9 @@ func TestLoadArchiveWithUTFBOM(t *testing.T) { func TestLoadFile(t *testing.T) { l, err := Loader("testdata/frobnitz-1.2.3.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -224,36 +197,16 @@ icon: https://example.com/64x64.png } c, err := LoadFiles(goodFiles) - if err != nil { - t.Errorf("Expected good files to be loaded, got %v", err) - } - - if c.Name() != "frobnitz" { - t.Errorf("Expected chart name to be 'frobnitz', got %s", c.Name()) - } - - if c.Values["var"] != "some values" { - t.Error("Expected chart values to be populated with default values") - } - - if len(c.Raw) != 5 { - t.Errorf("Expected %d files, got %d", 5, len(c.Raw)) - } - - if !bytes.Equal(c.Schema, []byte("type: Values")) { - t.Error("Expected chart schema to be populated with default values") - } - - if len(c.Templates) != 2 { - t.Errorf("Expected number of templates == 2, got %d", len(c.Templates)) - } - - if _, err = LoadFiles([]*archive.BufferedFile{}); err == nil { - t.Fatal("Expected err to be non-nil") - } - if err.Error() != "Chart.yaml file is missing" { - t.Errorf("Expected chart metadata missing error, got '%s'", err.Error()) - } + require.NoError(t, err, "Expected good files to be loaded") + assert.Equal(t, "frobnitz", c.Name(), "Expected chart name to be 'frobnitz', got %s", c.Name()) + assert.Equal(t, "some values", c.Values["var"], "Expected chart values to be populated with default values") + assert.Len(t, c.Raw, 5, "Expected 5 files") + assert.True(t, bytes.Equal(c.Schema, []byte("type: Values")), "Expected chart schema to be populated with default values") + assert.Len(t, c.Templates, 2, "Expected 2 templates") + + _, err = LoadFiles([]*archive.BufferedFile{}) + require.Error(t, err, "Expected err to be non-nil") + assert.EqualError(t, err, "Chart.yaml file is missing", "Expected chart metadata missing error, got '%s'", err.Error()) } // Test the order of file loading. The Chart.yaml file needs to come first for @@ -309,9 +262,7 @@ icon: https://example.com/64x64.png // Capture stderr to make sure message about Chart.yaml handle dependencies // is not present r, w, err := os.Pipe() - if err != nil { - t.Fatalf("Unable to create pipe: %s", err) - } + require.NoError(t, err, "Unable to create pipe") stderr := log.Writer() log.SetOutput(w) defer func() { @@ -319,25 +270,19 @@ icon: https://example.com/64x64.png }() _, err = LoadFiles(goodFiles) - if err != nil { - t.Errorf("Expected good files to be loaded, got %v", err) - } + require.NoError(t, err, "Expected good files to be loaded") w.Close() var text bytes.Buffer io.Copy(&text, r) - if text.String() != "" { - t.Errorf("Expected no message to Stderr, got %s", text.String()) - } + assert.Empty(t, text.String(), "Expected no message to Stderr, got %s", text.String()) } // Packaging the chart on a Windows machine will produce an // archive that has \\ as delimiters. Test that we support these archives func TestLoadFileBackslash(t *testing.T) { c, err := Load("testdata/frobnitz_backslash-1.2.3.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyChartFileAndTemplate(t, c, "frobnitz_backslash") verifyChart(t, c) verifyDependencies(t, c) @@ -345,13 +290,9 @@ func TestLoadFileBackslash(t *testing.T) { func TestLoadV3WithReqs(t *testing.T) { l, err := Loader("testdata/frobnitz.v3.reqs") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyDependencies(t, c) verifyDependenciesLock(t, c) } @@ -361,9 +302,7 @@ func TestLoadInvalidArchive(t *testing.T) { writeTar := func(filename, internalPath string, body []byte) { dest, err := os.Create(filename) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) zipper := gzip.NewWriter(dest) tw := tar.NewWriter(zipper) @@ -373,12 +312,9 @@ func TestLoadInvalidArchive(t *testing.T) { Size: int64(len(body)), ModTime: time.Now(), } - if err := tw.WriteHeader(h); err != nil { - t.Fatal(err) - } - if _, err := tw.Write(body); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(h)) + _, err = tw.Write(body) + require.NoError(t, err) tw.Close() zipper.Close() dest.Close() @@ -410,37 +346,27 @@ func TestLoadInvalidArchive(t *testing.T) { illegalChart := filepath.Join(tmpdir, tt.chartname) writeTar(illegalChart, tt.internal, []byte("hello: world")) _, err := Load(illegalChart) - if err == nil { - t.Fatal("expected error when unpacking illegal files") - } - if !strings.Contains(err.Error(), tt.expectError) { - t.Errorf("Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) - } + require.Error(t, err, "expected error when unpacking illegal files") + require.ErrorContains(t, err, tt.expectError, "Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) } // Make sure that absolute path gets interpreted as relative illegalChart := filepath.Join(tmpdir, "abs-path.tgz") writeTar(illegalChart, "/Chart.yaml", []byte("hello: world")) _, err := Load(illegalChart) - if err.Error() != "validation: chart.metadata.name is required" { - t.Error(err) - } + require.EqualError(t, err, "validation: chart.metadata.name is required") // And just to validate that the above was not spurious illegalChart = filepath.Join(tmpdir, "abs-path2.tgz") writeTar(illegalChart, "files/whatever.yaml", []byte("hello: world")) _, err = Load(illegalChart) - if err.Error() != "Chart.yaml file is missing" { - t.Errorf("Unexpected error message: %s", err) - } + require.EqualError(t, err, "Chart.yaml file is missing") // Finally, test that drive letter gets stripped off on Windows illegalChart = filepath.Join(tmpdir, "abs-winpath.tgz") writeTar(illegalChart, "c:\\Chart.yaml", []byte("hello: world")) _, err = Load(illegalChart) - if err.Error() != "validation: chart.metadata.name is required" { - t.Error(err) - } + assert.EqualError(t, err, "validation: chart.metadata.name is required") } func TestLoadValues(t *testing.T) { @@ -487,12 +413,8 @@ foo: for testName, testCase := range testCases { t.Run(testName, func(tt *testing.T) { values, err := LoadValues(bytes.NewReader(testCase.data)) - if err != nil { - tt.Fatal(err) - } - if !reflect.DeepEqual(values, testCase.expctedValues) { - tt.Errorf("Expected values: %v, got %v", testCase.expctedValues, values) - } + require.NoError(tt, err) + assert.Equalf(tt, testCase.expctedValues, values, "Expected values: %v, got %v", testCase.expctedValues, values) }) } } @@ -520,22 +442,13 @@ func TestMergeValuesV3(t *testing.T) { } testMap := MergeMaps(flatMap, nestedMap) - equal := reflect.DeepEqual(testMap, nestedMap) - if !equal { - t.Errorf("Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) - } + assert.Equal(t, testMap, nestedMap, "Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) testMap = MergeMaps(nestedMap, flatMap) - equal = reflect.DeepEqual(testMap, flatMap) - if !equal { - t.Errorf("Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) - } + assert.Equal(t, testMap, flatMap, "Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) testMap = MergeMaps(nestedMap, anotherNestedMap) - equal = reflect.DeepEqual(testMap, anotherNestedMap) - if !equal { - t.Errorf("Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) - } + assert.Equal(t, testMap, anotherNestedMap, "Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) testMap = MergeMaps(anotherFlatMap, anotherNestedMap) expectedMap := map[string]any{ @@ -546,32 +459,23 @@ func TestMergeValuesV3(t *testing.T) { "awesome": "stuff", }, } - equal = reflect.DeepEqual(testMap, expectedMap) - if !equal { - t.Errorf("Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) - } + assert.Equal(t, expectedMap, testMap, "Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) } func verifyChart(t *testing.T, c *chart.Chart) { t.Helper() - if c.Name() == "" { - t.Fatalf("No chart metadata found on %v", c) - } + require.NotEmpty(t, c.Name(), "No chart metadata found on %v", c) t.Logf("Verifying chart %s", c.Name()) - if len(c.Templates) != 1 { - t.Errorf("Expected 1 template, got %d", len(c.Templates)) - } + assert.Len(t, c.Templates, 1, "Expected 1 template") numfiles := 6 - if len(c.Files) != numfiles { - t.Errorf("Expected %d extra files, got %d", numfiles, len(c.Files)) + if !assert.Len(t, c.Files, numfiles, "Expected %d extra files", numfiles) { for _, n := range c.Files { t.Logf("\t%s", n.Name) } } - if len(c.Dependencies()) != 2 { - t.Errorf("Expected 2 dependencies, got %d (%v)", len(c.Dependencies()), c.Dependencies()) + if !assert.Len(t, c.Dependencies(), 2, "Expected 2 dependencies") { for _, d := range c.Dependencies() { t.Logf("\tSubchart: %s\n", d.Name()) } @@ -587,62 +491,40 @@ func verifyChart(t *testing.T, c *chart.Chart) { } for _, dep := range c.Dependencies() { - if dep.Metadata == nil { - t.Fatalf("expected metadata on dependency: %v", dep) - } + require.NotNil(t, dep.Metadata, "expected metadata on dependency: %v", dep) exp, ok := expect[dep.Name()] - if !ok { - t.Fatalf("Unknown dependency %s", dep.Name()) - } - if exp["version"] != dep.Metadata.Version { - t.Errorf("Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version) - } + require.True(t, ok, "Unknown dependency %s", dep.Name()) + assert.Equal(t, exp["version"], dep.Metadata.Version, "Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version) } } func verifyDependencies(t *testing.T, c *chart.Chart) { t.Helper() - if len(c.Metadata.Dependencies) != 2 { - t.Errorf("Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) - } + assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies") tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, } for i, tt := range tests { d := c.Metadata.Dependencies[i] - if d.Name != tt.Name { - t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) - } - if d.Version != tt.Version { - t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) - } - if d.Repository != tt.Repository { - t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) - } + assert.Equal(t, tt.Name, d.Name, "Expected dependency named %q, got %q", tt.Name, d.Name) + assert.Equal(t, tt.Version, d.Version, "Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) + assert.Equal(t, tt.Repository, d.Repository, "Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) } } func verifyDependenciesLock(t *testing.T, c *chart.Chart) { t.Helper() - if len(c.Metadata.Dependencies) != 2 { - t.Errorf("Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) - } + assert.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, } for i, tt := range tests { d := c.Metadata.Dependencies[i] - if d.Name != tt.Name { - t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) - } - if d.Version != tt.Version { - t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) - } - if d.Repository != tt.Repository { - t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) - } + assert.Equal(t, tt.Name, d.Name, "Expected dependency named %q, got %q", tt.Name, d.Name) + assert.Equal(t, tt.Version, d.Version, "Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) + assert.Equal(t, tt.Repository, d.Repository, "Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) } } @@ -653,51 +535,25 @@ func verifyFrobnitz(t *testing.T, c *chart.Chart) { func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { t.Helper() - if c.Metadata == nil { - t.Fatal("Metadata is nil") - } - if c.Name() != name { - t.Errorf("Expected %s, got %s", name, c.Name()) - } - if len(c.Templates) != 1 { - t.Fatalf("Expected 1 template, got %d", len(c.Templates)) - } - if c.Templates[0].Name != "templates/template.tpl" { - t.Errorf("Unexpected template: %s", c.Templates[0].Name) - } - if len(c.Templates[0].Data) == 0 { - t.Error("No template data.") - } - if len(c.Files) != 6 { - t.Fatalf("Expected 6 Files, got %d", len(c.Files)) - } - if len(c.Dependencies()) != 2 { - t.Fatalf("Expected 2 Dependency, got %d", len(c.Dependencies())) - } - if len(c.Metadata.Dependencies) != 2 { - t.Fatalf("Expected 2 Dependencies.Dependency, got %d", len(c.Metadata.Dependencies)) - } - if len(c.Lock.Dependencies) != 2 { - t.Fatalf("Expected 2 Lock.Dependency, got %d", len(c.Lock.Dependencies)) - } + require.NotNil(t, c.Metadata, "Metadata is nil") + assert.Equal(t, name, c.Name(), "Expected %s, got %s", name, c.Name()) + require.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) + assert.Equal(t, "templates/template.tpl", c.Templates[0].Name, "Unexpected template: %s", c.Templates[0].Name) + assert.NotEmpty(t, c.Templates[0].Data, "No template data.") + require.Len(t, c.Files, 6, "Expected 6 Files, got %d", len(c.Files)) + require.Len(t, c.Dependencies(), 2, "Expected 2 Dependency, got %d", len(c.Dependencies())) + require.Len(t, c.Metadata.Dependencies, 2, "Expected 2 Dependencies.Dependency, got %d", len(c.Metadata.Dependencies)) + require.Len(t, c.Lock.Dependencies, 2, "Expected 2 Lock.Dependency, got %d", len(c.Lock.Dependencies)) for _, dep := range c.Dependencies() { switch dep.Name() { case "mariner": case "alpine": - if len(dep.Templates) != 1 { - t.Fatalf("Expected 1 template, got %d", len(dep.Templates)) - } - if dep.Templates[0].Name != "templates/alpine-pod.yaml" { - t.Errorf("Unexpected template: %s", dep.Templates[0].Name) - } + require.Len(t, dep.Templates, 1, "Expected 1 template, got %d", len(dep.Templates)) + assert.Equal(t, "templates/alpine-pod.yaml", dep.Templates[0].Name, "Unexpected template: %s", dep.Templates[0].Name) assert.NotEmpty(t, dep.Templates[0].Data, "No template data.") - if len(dep.Files) != 1 { - t.Fatalf("Expected 1 Files, got %d", len(dep.Files)) - } - if len(dep.Dependencies()) != 2 { - t.Fatalf("Expected 2 Dependency, got %d", len(dep.Dependencies())) - } + require.Len(t, dep.Files, 1, "Expected 1 Files, got %d", len(dep.Files)) + require.Len(t, dep.Dependencies(), 2, "Expected 2 Dependency, got %d", len(dep.Dependencies())) default: t.Errorf("Unexpected dependency %s", dep.Name()) } @@ -707,8 +563,6 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { func verifyBomStripped(t *testing.T, files []*common.File) { t.Helper() for _, file := range files { - if bytes.HasPrefix(file.Data, utf8bom) { - t.Errorf("Byte Order Mark still present in processed file %s", file.Name) - } + assert.Falsef(t, bytes.HasPrefix(file.Data, utf8bom), "Byte Order Mark still present in processed file %s", file.Name) } } diff --git a/internal/chart/v3/util/chartfile_test.go b/internal/chart/v3/util/chartfile_test.go index c791930c1..850f39af2 100644 --- a/internal/chart/v3/util/chartfile_test.go +++ b/internal/chart/v3/util/chartfile_test.go @@ -29,48 +29,28 @@ const testfile = "testdata/chartfiletest.yaml" func TestLoadChartfile(t *testing.T) { f, err := LoadChartfile(testfile) - if err != nil { - t.Errorf("Failed to open %s: %s", testfile, err) - return - } + require.NoErrorf(t, err, "Failed to open %s", testfile) verifyChartfile(t, f, "frobnitz") } func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { t.Helper() require.NotNil(t, f, "Failed verifyChartfile because f is nil") - assert.Equal(t, name, f.Name, "Expected %s, got %s", name, f.Name) - assert.Equal(t, "This is a frobnitz.", f.Description, "Unexpected description %q", f.Description) - assert.Equal(t, "1.2.3", f.Version, "Unexpected version %q", f.Version) - assert.Len(t, f.Maintainers, 2, "Expected 2 maintainers, got %d", len(f.Maintainers)) - assert.Equal(t, "The Helm Team", f.Maintainers[0].Name, "Unexpected maintainer name.") - assert.Equal(t, "nobody@example.com", f.Maintainers[1].Email, "Unexpected maintainer email.") - require.Len(t, f.Sources, 1, "Unexpected number of sources") - assert.Equal(t, "https://example.com/foo/bar", f.Sources[0], "Expected https://example.com/foo/bar, got %s", f.Sources) - assert.Equal(t, "http://example.com", f.Home, "Unexpected home.") - assert.Equal(t, "https://example.com/64x64.png", f.Icon, "Unexpected icon: %q", f.Icon) - require.Len(t, f.Keywords, 3, "Unexpected keywords") - require.Len(t, f.Annotations, 2, "Unexpected annotations") - if want, got := "extravalue", f.Annotations["extrakey"]; want != got { - t.Errorf("Want %q, but got %q", want, got) - } - - if want, got := "anothervalue", f.Annotations["anotherkey"]; want != got { - t.Errorf("Want %q, but got %q", want, got) - } + assert.Equal(t, "extravalue", f.Annotations["extrakey"]) + assert.Equal(t, "anothervalue", f.Annotations["anotherkey"]) kk := []string{"frobnitz", "sprocket", "dodad"} for i, k := range f.Keywords { @@ -80,13 +60,9 @@ func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { func TestIsChartDir(t *testing.T) { validChartDir, err := IsChartDir("testdata/frobnitz") - if !validChartDir { - t.Errorf("unexpected error while reading chart-directory: (%v)", err) - return - } + require.NoError(t, err, "while reading chart-directory") + require.True(t, validChartDir, "expected valid chart directory") validChartDir, err = IsChartDir("testdata") - if validChartDir || err == nil { - t.Error("expected error but did not get any") - return - } + require.Error(t, err) + require.False(t, validChartDir, "expected invalid chart directory") } diff --git a/internal/chart/v3/util/create_test.go b/internal/chart/v3/util/create_test.go index eba0811ae..ddbbf6216 100644 --- a/internal/chart/v3/util/create_test.go +++ b/internal/chart/v3/util/create_test.go @@ -38,7 +38,7 @@ func TestCreate(t *testing.T) { dir := filepath.Join(tdir, "foo") mychart, err := loader.LoadDir(c) - require.NoError(t, err, "Failed to load newly created chart %q: %s", c, err) + require.NoError(t, err, "Failed to load newly created chart %q", c) assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) @@ -55,9 +55,8 @@ func TestCreate(t *testing.T) { TestConnectionName, ValuesfileName, } { - if _, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } + _, err := os.Stat(filepath.Join(dir, f)) + assert.NoErrorf(t, err, "Expected %s file", f) } } @@ -71,14 +70,12 @@ func TestCreateFrom(t *testing.T) { } srcdir := "./testdata/frobnitz/charts/mariner" - if err := CreateFrom(cf, tdir, srcdir); err != nil { - t.Fatal(err) - } + require.NoError(t, CreateFrom(cf, tdir, srcdir)) dir := filepath.Join(tdir, "foo") c := filepath.Join(tdir, cf.Name) mychart, err := loader.LoadDir(c) - require.NoError(t, err, "Failed to load newly created chart %q: %s", c, err) + require.NoError(t, err, "Failed to load newly created chart %q", c) assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) @@ -87,16 +84,13 @@ func TestCreateFrom(t *testing.T) { ValuesfileName, filepath.Join(TemplatesDir, "placeholder.tpl"), } { - if _, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } + _, err := os.Stat(filepath.Join(dir, f)) + require.NoErrorf(t, err, "Expected %s file", f) // Check each file to make sure has been replaced b, err := os.ReadFile(filepath.Join(dir, f)) - require.NoError(t, err, "Unable to read file %s: %s", f, err) - if bytes.Contains(b, []byte("")) { - t.Errorf("File %s contains ", f) - } + require.NoError(t, err, "Unable to read file %s", f) + assert.Falsef(t, bytes.Contains(b, []byte("")), "File %s contains ", f) } } @@ -106,9 +100,8 @@ func TestCreate_Overwrite(t *testing.T) { var errlog bytes.Buffer - if _, err := Create("foo", tdir); err != nil { - t.Fatal(err) - } + _, err := Create("foo", tdir) + require.NoError(t, err) dir := filepath.Join(tdir, "foo") @@ -117,9 +110,8 @@ func TestCreate_Overwrite(t *testing.T) { // Now re-run the create Stderr = &errlog - if _, err := Create("foo", tdir); err != nil { - t.Fatal(err) - } + _, err = Create("foo", tdir) + require.NoError(t, err) data, err := os.ReadFile(tplname) require.NoError(t, err) @@ -150,8 +142,11 @@ func TestValidateChartName(t *testing.T) { "abcdefghijklmnopqrstuvwxyz-_." + "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.": false, } { - if err := validateChartName(name); (err != nil) == shouldPass { - t.Errorf("test for %q failed", name) + err := validateChartName(name) + if shouldPass { + assert.NoErrorf(t, err, "Expected chart name %q to pass validation", name) + } else { + assert.Errorf(t, err, "Expected chart name %q to fail validation, but it passed", name) } } } diff --git a/internal/chart/v3/util/dependencies_test.go b/internal/chart/v3/util/dependencies_test.go index f6ca06da3..45693ef46 100644 --- a/internal/chart/v3/util/dependencies_test.go +++ b/internal/chart/v3/util/dependencies_test.go @@ -369,8 +369,7 @@ func TestDependentChartWithSubChartsAbsentInDependency(t *testing.T) { require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - err := processDependencyEnabled(c, c.Values, "") - require.NoError(t, err, "expected no errors") + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") } @@ -381,8 +380,7 @@ func TestDependentChartWithSubChartsHelmignore(t *testing.T) { func TestDependentChartsWithSubChartsSymlink(t *testing.T) { joonix := filepath.Join("testdata", "joonix") - err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")) - require.NoError(t, err, "failed to create symlink") + require.NoError(t, os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")), "failed to create symlink") defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) c := loadChart(t, joonix) @@ -394,12 +392,8 @@ func TestDependentChartsWithSubchartsAllSpecifiedInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-with-all-in-requirements-yaml") require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - - err := processDependencyEnabled(c, c.Values, "") - require.NoError(t, err, "expected no errors") - + require.NoError(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") - require.Len(t, c.Dependencies(), len(c.Metadata.Dependencies), "expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) } diff --git a/internal/chart/v3/util/expand_test.go b/internal/chart/v3/util/expand_test.go index a7a756485..ddf74b392 100644 --- a/internal/chart/v3/util/expand_test.go +++ b/internal/chart/v3/util/expand_test.go @@ -47,19 +47,19 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff fStat, err := f.Stat() require.NoError(t, err) - err = tw.WriteHeader(&tar.Header{ + require.NoError(t, tw.WriteHeader(&tar.Header{ Name: filepath.Join(chartName, relPath), Mode: int64(fStat.Mode()), Size: fStat.Size(), - }) - require.NoError(t, err) + })) data, err := fs.ReadFile(dir, relPath) require.NoError(t, err) - tw.Write(data) + _, err = tw.Write(data) + require.NoError(t, err) } - err := fs.WalkDir(dir, ".", func(path string, d os.DirEntry, walkErr error) error { + require.NoError(t, fs.WalkDir(dir, ".", func(path string, d os.DirEntry, walkErr error) error { if walkErr != nil { return walkErr } @@ -71,13 +71,10 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff writeFile(path) return nil - }) - require.NoError(t, err) + })) - err = tw.Close() - require.NoError(t, err) - err = gw.Close() - require.NoError(t, err) + require.NoError(t, tw.Close()) + require.NoError(t, gw.Close()) return &result } @@ -87,26 +84,24 @@ func TestExpand(t *testing.T) { reader, err := os.Open("testdata/frobnitz-1.2.3.tgz") require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, reader.Close()) }) - if err := Expand(dest, reader); err != nil { - t.Fatal(err) - } + require.NoError(t, Expand(dest, reader)) expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) require.NoError(t, err) - if !fi.IsDir() { - t.Fatalf("expected a chart directory at %s", expectedChartPath) - } + require.Truef(t, fi.IsDir(), "expected a chart directory at %s", expectedChartPath) dir, err := os.Open(expectedChartPath) require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, dir.Close()) }) fis, err := dir.Readdir(0) require.NoError(t, err) expectLen := 11 - assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) + assert.Len(t, fis, expectLen, "Expected %d files", expectLen) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) @@ -137,8 +132,7 @@ func TestExpandError(t *testing.T) { archive := makeTestChartArchive(t, tt.chartName, tt.chartDir) dest := t.TempDir() - err := Expand(dest, archive) - assert.ErrorContains(t, err, tt.wantErr) + assert.ErrorContains(t, Expand(dest, archive), tt.wantErr) }) } } @@ -146,16 +140,12 @@ func TestExpandError(t *testing.T) { func TestExpandFile(t *testing.T) { dest := t.TempDir() - if err := ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz"); err != nil { - t.Fatal(err) - } + require.NoError(t, ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz")) expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) require.NoError(t, err) - if !fi.IsDir() { - t.Fatalf("expected a chart directory at %s", expectedChartPath) - } + require.Truef(t, fi.IsDir(), "expected a chart directory at %s", expectedChartPath) dir, err := os.Open(expectedChartPath) require.NoError(t, err) @@ -164,7 +154,7 @@ func TestExpandFile(t *testing.T) { require.NoError(t, err) expectLen := 11 - assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) + assert.Len(t, fis, expectLen, "Expected %d files", expectLen) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) diff --git a/internal/chart/v3/util/save_test.go b/internal/chart/v3/util/save_test.go index fe84a744f..2f4f11671 100644 --- a/internal/chart/v3/util/save_test.go +++ b/internal/chart/v3/util/save_test.go @@ -62,20 +62,15 @@ func TestSave(t *testing.T) { chartWithInvalidJSON := withSchema(*c, []byte("{")) where, err := Save(c, dest) - require.NoError(t, err, "Failed to save: %s", err) - if !strings.HasPrefix(where, dest) { - t.Fatalf("Expected %q to start with %q", where, dest) - } - if !strings.HasSuffix(where, ".tgz") { - t.Fatalf("Expected %q to end with .tgz", where) - } + require.NoError(t, err, "Failed to save") + require.Truef(t, strings.HasPrefix(where, dest), "Expected %q to start with %q", where, dest) + require.Truef(t, strings.HasSuffix(where, ".tgz"), "Expected %q to end with .tgz", where) c2, err := loader.LoadFile(where) require.NoError(t, err) require.Equal(t, c.Name(), c2.Name(), "Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - if len(c2.Files) != 1 || c2.Files[0].Name != "scheherazade/shahryar.txt" { - t.Fatal("Files data did not match") - } + require.Len(t, c2.Files, 1, "Files data did not match") + require.Equal(t, "scheherazade/shahryar.txt", c2.Files[0].Name, "Files data did not match") if !bytes.Equal(c.Schema, c2.Schema) { indentation := 4 @@ -83,13 +78,12 @@ func TestSave(t *testing.T) { formattedActual := Indent(indentation, string(c2.Schema)) t.Fatalf("Schema data did not match.\nExpected:\n%s\nActual:\n%s", formattedExpected, formattedActual) } - if _, err := Save(&chartWithInvalidJSON, dest); err == nil { - t.Fatal("Invalid JSON was not caught while saving chart") - } + _, err = Save(&chartWithInvalidJSON, dest) + require.Error(t, err, "Invalid JSON was not caught while saving chart") c.Metadata.APIVersion = chart.APIVersionV3 where, err = Save(c, dest) - require.NoError(t, err, "Failed to save: %s", err) + require.NoError(t, err, "Failed to save") c2, err = loader.LoadFile(where) require.NoError(t, err) require.NotNil(t, c2.Lock, "Expected v3 chart archive to contain a Chart.lock file") @@ -294,16 +288,14 @@ func TestSavePreservesTimestamps(t *testing.T) { } where, err := Save(c, tmp) - require.NoError(t, err, "Failed to save: %s", err) + require.NoError(t, err, "Failed to save") allHeaders, err := retrieveAllHeadersFromTar(where) - require.NoError(t, err, "Failed to parse tar: %v", err) + require.NoError(t, err, "Failed to parse tar") roundedTime := initialCreateTime.Round(time.Second) for _, header := range allHeaders { - if !header.ModTime.Equal(roundedTime) { - t.Fatalf("File timestamp not preserved: %v", header.ModTime) - } + require.Truef(t, header.ModTime.Equal(roundedTime), "File timestamp not preserved: %v", header.ModTime) } } @@ -377,8 +369,7 @@ func TestSaveDir(t *testing.T) { pth := filepath.Join(tmp2, "tmpcharts") require.NoError(t, os.MkdirAll(filepath.Join(pth), 0o755), "Failed to create directory") - err = SaveDir(c, pth) - assert.EqualError(t, err, "\"../ahab\" is not a valid chart name", "Did not get expected error for chart named %q", c.Name()) + assert.EqualError(t, SaveDir(c, pth), "\"../ahab\" is not a valid chart name", "Did not get expected error for chart named %q", c.Name()) } func TestRepeatableSave(t *testing.T) { @@ -439,10 +430,10 @@ func TestRepeatableSave(t *testing.T) { // create package dest := path.Join(tmp, "newdir") where, err := Save(test.chart, dest) - require.NoError(t, err, "Failed to save: %s", err) + require.NoError(t, err, "Failed to save") // get shasum for package result, err := sha256Sum(where) - require.NoError(t, err, "Failed to check shasum: %s", err) + require.NoError(t, err, "Failed to check shasum") // assert that the package SHA is what we wanted. assert.Equal(t, test.want, result, "FormatName() result = %v, want %v", result, test.want) }) diff --git a/internal/chart/v3/util/validate_name_test.go b/internal/chart/v3/util/validate_name_test.go index cfc62a0f7..3ea768db2 100644 --- a/internal/chart/v3/util/validate_name_test.go +++ b/internal/chart/v3/util/validate_name_test.go @@ -16,7 +16,11 @@ limitations under the License. package util -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) // TestValidateReleaseName is a regression test for ValidateName // @@ -46,12 +50,11 @@ func TestValidateReleaseName(t *testing.T) { "a1111111111111111111111111111111111111111111111111111111111z": false, } for input, expectPass := range names { - if err := ValidateReleaseName(input); (err == nil) != expectPass { - st := "fail" - if expectPass { - st = "succeed" - } - t.Errorf("Expected %q to %s", input, st) + err := ValidateReleaseName(input) + if expectPass { + assert.NoErrorf(t, err, "Expected release name %q to pass validation", input) + } else { + assert.Errorf(t, err, "Expected release name %q to fail validation, but it passed", input) } } } @@ -80,12 +83,11 @@ func TestValidateMetadataName(t *testing.T) { "a1111111111111111111111111111111111111111111111111111111111z": false, } for input, expectPass := range names { - if err := ValidateMetadataName(input); (err == nil) != expectPass { - st := "fail" - if expectPass { - st = "succeed" - } - t.Errorf("Expected %q to %s", input, st) + err := ValidateMetadataName(input) + if expectPass { + assert.NoError(t, err, "Expected %q to succeed", input) + } else { + assert.Error(t, err, "Expected %q to fail", input) } } } diff --git a/internal/fileutil/fileutil_test.go b/internal/fileutil/fileutil_test.go index 9c997fcd3..85dd51894 100644 --- a/internal/fileutil/fileutil_test.go +++ b/internal/fileutil/fileutil_test.go @@ -37,8 +37,7 @@ func TestAtomicWriteFile(t *testing.T) { reader := bytes.NewReader([]byte(stringContent)) mode := os.FileMode(0o644) - err := AtomicWriteFile(testpath, reader, mode) - require.NoError(t, err) + require.NoError(t, AtomicWriteFile(testpath, reader, mode)) got, err := os.ReadFile(testpath) require.NoError(t, err) @@ -58,8 +57,7 @@ func TestAtomicWriteFile_CreateTempError(t *testing.T) { reader := bytes.NewReader([]byte("test content")) mode := os.FileMode(0o644) - err := AtomicWriteFile(invalidPath, reader, mode) - assert.Error(t, err, "Expected error when CreateTemp fails") + assert.Error(t, AtomicWriteFile(invalidPath, reader, mode), "Expected error when CreateTemp fails") } // TestAtomicWriteFile_EmptyContent tests with empty content @@ -70,8 +68,7 @@ func TestAtomicWriteFile_EmptyContent(t *testing.T) { reader := bytes.NewReader([]byte("")) mode := os.FileMode(0o644) - err := AtomicWriteFile(testpath, reader, mode) - require.NoError(t, err, "AtomicWriteFile error with empty content") + require.NoError(t, AtomicWriteFile(testpath, reader, mode), "AtomicWriteFile error with empty content") got, err := os.ReadFile(testpath) require.NoError(t, err) @@ -89,8 +86,7 @@ func TestAtomicWriteFile_LargeContent(t *testing.T) { reader := bytes.NewReader([]byte(largeContent)) mode := os.FileMode(0o644) - err := AtomicWriteFile(testpath, reader, mode) - require.NoError(t, err, "AtomicWriteFile error with large content") + require.NoError(t, AtomicWriteFile(testpath, reader, mode), "AtomicWriteFile error with large content") got, err := os.ReadFile(testpath) require.NoError(t, err) diff --git a/internal/logging/logging_test.go b/internal/logging/logging_test.go index 83979e9db..1d6eaf852 100644 --- a/internal/logging/logging_test.go +++ b/internal/logging/logging_test.go @@ -197,9 +197,8 @@ func TestDebugCheckHandler_Handle(t *testing.T) { } record := slog.NewRecord(time.Now(), slog.LevelInfo, "test message", 0) - err := handler.Handle(t.Context(), record) - require.NoError(t, err) + require.NoError(t, handler.Handle(t.Context(), record)) assert.Contains(t, buf.String(), "test message") }) @@ -214,9 +213,8 @@ func TestDebugCheckHandler_Handle(t *testing.T) { type testKey string ctx := context.WithValue(t.Context(), testKey("test"), "value") record := slog.NewRecord(time.Now(), slog.LevelInfo, "context test", 0) - err := handler.Handle(ctx, record) - require.NoError(t, err) + require.NoError(t, handler.Handle(ctx, record)) assert.Contains(t, buf.String(), "context test") }) } diff --git a/internal/plugin/cache/cache.go b/internal/plugin/cache/cache.go index f3b737477..1613d4d76 100644 --- a/internal/plugin/cache/cache.go +++ b/internal/plugin/cache/cache.go @@ -14,7 +14,7 @@ limitations under the License. */ // Package cache provides a key generator for vcs urls. -package cache // import "helm.sh/helm/v4/internal/plugin/cache" +package cache import ( "net/url" diff --git a/internal/plugin/installer/base.go b/internal/plugin/installer/base.go index c21a245a8..54d25287a 100644 --- a/internal/plugin/installer/base.go +++ b/internal/plugin/installer/base.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "path/filepath" diff --git a/internal/plugin/installer/base_test.go b/internal/plugin/installer/base_test.go index 6df8ec8a1..8ef7ff588 100644 --- a/internal/plugin/installer/base_test.go +++ b/internal/plugin/installer/base_test.go @@ -11,10 +11,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "testing" + + "github.com/stretchr/testify/assert" ) func TestPath(t *testing.T) { @@ -38,8 +40,6 @@ func TestPath(t *testing.T) { t.Setenv("HELM_PLUGINS", tt.helmPluginsDir) baseIns := newBase(tt.source) baseInsPath := baseIns.Path() - if baseInsPath != tt.expectPath { - t.Errorf("expected name %s, got %s", tt.expectPath, baseInsPath) - } + assert.Equal(t, tt.expectPath, baseInsPath, "expected name %s, got %s", tt.expectPath, baseInsPath) } } diff --git a/internal/plugin/installer/doc.go b/internal/plugin/installer/doc.go index a4cf384bf..a9d9555c9 100644 --- a/internal/plugin/installer/doc.go +++ b/internal/plugin/installer/doc.go @@ -14,4 +14,4 @@ limitations under the License. */ // Package installer provides an interface for installing Helm plugins. -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer diff --git a/internal/plugin/installer/extractor.go b/internal/plugin/installer/extractor.go index 85d695bd2..6cd45e2d8 100644 --- a/internal/plugin/installer/extractor.go +++ b/internal/plugin/installer/extractor.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "archive/tar" diff --git a/internal/plugin/installer/http_installer.go b/internal/plugin/installer/http_installer.go index 92d3d686e..7be326de2 100644 --- a/internal/plugin/installer/http_installer.go +++ b/internal/plugin/installer/http_installer.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "bytes" diff --git a/internal/plugin/installer/http_installer_test.go b/internal/plugin/installer/http_installer_test.go index cbd868f3a..df8385ed6 100644 --- a/internal/plugin/installer/http_installer_test.go +++ b/internal/plugin/installer/http_installer_test.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "archive/tar" @@ -27,10 +27,14 @@ import ( "net/http/httptest" "os" "path/filepath" + "strconv" "strings" "syscall" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/helmpath" @@ -52,18 +56,10 @@ func (t *TestHTTPGetter) Get(_ string, _ ...getter.Option) (*bytes.Buffer, error var fakePluginB64 = "H4sIAAAAAAAAA+3SQUvDMBgG4Jz7K0LwapdvSxrwJig6mCKC5xHabBaXdDSt4L+3cQ56mV42ZPg+lw+SF5LwZmXf3OV206/rMGEnIgdG6zTJaDmee4y01FOlZpqGHJGZSsb1qS401sfOtpyz0FTup9xv+2dqNep/N/IP6zdHPSMVXCh1sH8yhtGMDBUFFTL1r4iIcXnUWxzwz/sP1rsrLkbfQGTvro11E4ZlmcucRNZHu04py1OO73OVi2Vbb7td9vp7nXevtvsKRpGVjfc2VMP2xf3t4mH5tHi5mz8ub+bPk9JXIvvr5wMAAAAAAAAAAAAAAAAAAAAAnLVPqwHcXQAoAAA=" func TestStripName(t *testing.T) { - if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" { - t.Error("name does not match expected value") - } - if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" { - t.Error("name does not match expected value") - } - if stripPluginName("fake-plugin.tgz") != "fake-plugin" { - t.Error("name does not match expected value") - } - if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" { - t.Error("name does not match expected value") - } + assert.Equal(t, "fake-plugin", stripPluginName("fake-plugin-0.0.1.tar.gz"), "name does not match expected value") + assert.Equal(t, "fake-plugin", stripPluginName("fake-plugin-0.0.1.tgz"), "name does not match expected value") + assert.Equal(t, "fake-plugin", stripPluginName("fake-plugin.tgz"), "name does not match expected value") + assert.Equal(t, "fake-plugin", stripPluginName("fake-plugin.tar.gz"), "name does not match expected value") } func mockArchiveServer() *httptest.Server { @@ -71,10 +67,10 @@ func mockArchiveServer() *httptest.Server { if !strings.HasSuffix(r.URL.Path, ".tar.gz") { w.Header().Add("Content-Type", "text/html") fmt.Fprintln(w, "broken") - return + } else { + w.Header().Add("Content-Type", "application/gzip") + fmt.Fprintln(w, "test") } - w.Header().Add("Content-Type", "application/gzip") - fmt.Fprintln(w, "test") })) } @@ -85,45 +81,29 @@ func TestHTTPInstaller(t *testing.T) { defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { - t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) - } + require.NoErrorf(t, os.MkdirAll(helmpath.DataPath("plugins"), 0o755), "Could not create %s", helmpath.DataPath("plugins")) i, err := NewForSource(source, "0.0.1") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a HTTPInstaller was returned httpInstaller, ok := i.(*HTTPInstaller) - if !ok { - t.Fatal("expected a HTTPInstaller") - } + require.True(t, ok, "expected a HTTPInstaller") // inject fake http client responding with minimal plugin tarball mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) - if err != nil { - t.Fatalf("Could not decode fake tgz plugin: %s", err) - } + require.NoError(t, err, "Could not decode fake tgz plugin") httpInstaller.getter = &TestHTTPGetter{ MockResponse: bytes.NewBuffer(mockTgz), } // install the plugin - if err := Install(i); err != nil { - t.Fatal(err) - } - if i.Path() != helmpath.DataPath("plugins", "fake-plugin") { - t.Fatalf("expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path()) - } + require.NoError(t, Install(i)) + require.Equal(t, helmpath.DataPath("plugins", "fake-plugin"), i.Path(), "expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path()) // Install again to test plugin exists error - if err := Install(i); err == nil { - t.Fatal("expected error for plugin exists, got none") - } else if err.Error() != "plugin already exists" { - t.Fatalf("expected error for plugin exists, got (%v)", err) - } + require.EqualErrorf(t, Install(i), "plugin already exists", "expected error for plugin exists") } func TestHTTPInstallerNonExistentVersion(t *testing.T) { @@ -132,20 +112,14 @@ func TestHTTPInstallerNonExistentVersion(t *testing.T) { defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { - t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) - } + require.NoErrorf(t, os.MkdirAll(helmpath.DataPath("plugins"), 0o755), "Could not create %s", helmpath.DataPath("plugins")) i, err := NewForSource(source, "0.0.2") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a HTTPInstaller was returned httpInstaller, ok := i.(*HTTPInstaller) - if !ok { - t.Fatal("expected a HTTPInstaller") - } + require.True(t, ok, "expected a HTTPInstaller") // inject fake http client responding with error httpInstaller.getter = &TestHTTPGetter{ @@ -153,9 +127,7 @@ func TestHTTPInstallerNonExistentVersion(t *testing.T) { } // attempt to install the plugin - if err := Install(i); err == nil { - t.Fatal("expected error from http client") - } + require.Error(t, Install(i), "expected error from http client") } func TestHTTPInstallerUpdate(t *testing.T) { @@ -164,43 +136,29 @@ func TestHTTPInstallerUpdate(t *testing.T) { source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" ensure.HelmHome(t) - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { - t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) - } + require.NoErrorf(t, os.MkdirAll(helmpath.DataPath("plugins"), 0o755), "Could not create %s", helmpath.DataPath("plugins")) i, err := NewForSource(source, "0.0.1") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a HTTPInstaller was returned httpInstaller, ok := i.(*HTTPInstaller) - if !ok { - t.Fatal("expected a HTTPInstaller") - } + require.True(t, ok, "expected a HTTPInstaller") // inject fake http client responding with minimal plugin tarball mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) - if err != nil { - t.Fatalf("Could not decode fake tgz plugin: %s", err) - } + require.NoError(t, err, "Could not decode fake tgz plugin") httpInstaller.getter = &TestHTTPGetter{ MockResponse: bytes.NewBuffer(mockTgz), } // install the plugin before updating - if err := Install(i); err != nil { - t.Fatal(err) - } - if i.Path() != helmpath.DataPath("plugins", "fake-plugin") { - t.Fatalf("expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path()) - } + require.NoError(t, Install(i)) + require.Equal(t, helmpath.DataPath("plugins", "fake-plugin"), i.Path(), "expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path()) // Update plugin, should fail because it is not implemented - if err := Update(i); err == nil { - t.Fatal("update method not implemented for http installer") - } + require.Error(t, Update(i), "update method not implemented for http installer") } func TestExtract(t *testing.T) { @@ -229,12 +187,9 @@ func TestExtract(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } // Add pax global headers. This should be ignored. @@ -242,59 +197,46 @@ func TestExtract(t *testing.T) { // Details are in the internal Go function for the tar packaged named // allowedFormats. For a TypeXHeader it will return a message stating // "cannot manually encode TypeXHeader, TypeGNULongName, or TypeGNULongLink headers" - if err := tw.WriteHeader(&tar.Header{ + require.NoError(t, tw.WriteHeader(&tar.Header{ Name: "pax_global_header", Typeflag: tar.TypeXGlobalHeader, - }); err != nil { - t.Fatal(err) - } + })) - if err := tw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) var buf bytes.Buffer gz := gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err := gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() // END tarball creation extractor, err := NewExtractor(source) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if err = extractor.Extract(&buf, tempDir); err != nil { - t.Fatalf("Did not expect error but got error: %v", err) - } + require.NoErrorf(t, extractor.Extract(&buf, tempDir), "Did not expect error") // Calculate expected permissions after umask is applied expectedPluginYAMLPerm := os.FileMode(0o600 &^ currentUmask) expectedReadmePerm := os.FileMode(0o777 &^ currentUmask) pluginYAMLFullPath := filepath.Join(tempDir, "plugin.yaml") - if info, err := os.Stat(pluginYAMLFullPath); err != nil { - if errors.Is(err, fs.ErrNotExist) { - t.Fatalf("Expected %s to exist but doesn't", pluginYAMLFullPath) - } - t.Fatal(err) - } else if info.Mode().Perm() != expectedPluginYAMLPerm { - t.Fatalf("Expected %s to have %o mode but has %o (umask: %o)", - pluginYAMLFullPath, expectedPluginYAMLPerm, info.Mode().Perm(), currentUmask) + info, err := os.Stat(pluginYAMLFullPath) + if err != nil { + require.NotErrorIs(t, err, fs.ErrNotExist, "Expected %s to exist but doesn't", pluginYAMLFullPath) } + require.NoError(t, err) + require.Equalf(t, expectedPluginYAMLPerm, info.Mode().Perm(), "Expected %s to have %o mode but has %o (umask: %o)", + pluginYAMLFullPath, expectedPluginYAMLPerm, info.Mode().Perm(), currentUmask) readmeFullPath := filepath.Join(tempDir, "README.md") - if info, err := os.Stat(readmeFullPath); err != nil { - if errors.Is(err, fs.ErrNotExist) { - t.Fatalf("Expected %s to exist but doesn't", readmeFullPath) - } - t.Fatal(err) - } else if info.Mode().Perm() != expectedReadmePerm { - t.Fatalf("Expected %s to have %o mode but has %o (umask: %o)", - readmeFullPath, expectedReadmePerm, info.Mode().Perm(), currentUmask) + info, err = os.Stat(readmeFullPath) + if err != nil { + require.NotErrorIs(t, err, fs.ErrNotExist, "Expected %s to exist but doesn't", readmeFullPath) } + require.NoError(t, err) + require.Equalf(t, expectedReadmePerm, info.Mode().Perm(), "Expected %s to have %o mode but has %o (umask: %o)", + readmeFullPath, expectedReadmePerm, info.Mode().Perm(), currentUmask) } func TestCleanJoin(t *testing.T) { @@ -313,16 +255,15 @@ func TestCleanJoin(t *testing.T) { {"foo\\bar.txt", "/tmp/foo/bar.txt", false}, {"c:\\foo\\bar.txt", "", true}, } { - out, err := cleanJoin("/tmp", fixture.path) - if err != nil { - if !fixture.expectError { - t.Errorf("Test %d: Path was not cleaned: %s", i, err) + t.Run(strconv.Itoa(i), func(t *testing.T) { + out, err := cleanJoin("/tmp", fixture.path) + if fixture.expectError { + require.Error(t, err, "Test %d: Path was not cleaned", i) + } else { + require.NoError(t, err) + assert.Equal(t, fixture.expect, out, "Test %d: Expected %q but got %q", i, fixture.expect, out) } - continue - } - if fixture.expect != out { - t.Errorf("Test %d: Expected %q but got %q", i, fixture.expect, out) - } + }) } } @@ -336,14 +277,11 @@ func TestMediaTypeToExtension(t *testing.T) { "application/json": false, } { ext, ok := mediaTypeToExtension(mt) - if ok != shouldPass { - t.Errorf("Media type %q failed test", mt) - } - if shouldPass && ext == "" { - t.Error("Expected an extension but got empty string") - } - if !shouldPass && ext != "" { - t.Error("Expected extension to be empty for unrecognized type") + assert.Equal(t, shouldPass, ok, "Media type %q failed test", mt) + if shouldPass { + assert.NotEmpty(t, ext, "Expected an extension but got empty string for media type %q", mt) + } else { + assert.Empty(t, ext, "Expected extension to be empty for unrecognized media type %q", mt) } } } @@ -377,55 +315,41 @@ func TestExtractWithNestedDirectories(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) if file.TypeFlag == tar.TypeReg { - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } } - if err := tw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) var buf bytes.Buffer gz := gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err := gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() extractor, err := NewExtractor(source) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // First extraction - if err = extractor.Extract(&buf, tempDir); err != nil { - t.Fatalf("First extraction failed: %v", err) - } + require.NoError(t, extractor.Extract(&buf, tempDir), "First extraction failed") // Verify nested structure was created nestedFile := filepath.Join(tempDir, "docs", "examples", "example1.yaml") - if _, err := os.Stat(nestedFile); err != nil { - t.Fatalf("Expected nested file %s to exist but got error: %v", nestedFile, err) - } + _, err = os.Stat(nestedFile) + require.NoErrorf(t, err, "Expected nested file %s to exist", nestedFile) // Reset buffer for second extraction buf.Reset() gz = gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err = gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() // Second extraction to same directory (should not fail) - if err = extractor.Extract(&buf, tempDir); err != nil { - t.Fatalf("Second extraction to existing directory failed: %v", err) - } + require.NoErrorf(t, extractor.Extract(&buf, tempDir), "Second extraction to existing directory failed") } func TestExtractWithExistingDirectory(t *testing.T) { @@ -434,15 +358,11 @@ func TestExtractWithExistingDirectory(t *testing.T) { // Pre-create the cache directory structure cacheDir := filepath.Join(tempDir, "cache") - if err := os.MkdirAll(filepath.Join(cacheDir, "existing", "dir"), 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(cacheDir, "existing", "dir"), 0o755)) // Create a file in the existing directory existingFile := filepath.Join(cacheDir, "existing", "file.txt") - if err := os.WriteFile(existingFile, []byte("existing content"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(existingFile, []byte("existing content"), 0o644)) // Write a tarball var tarbuf bytes.Buffer @@ -466,47 +386,35 @@ func TestExtractWithExistingDirectory(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) if file.TypeFlag == tar.TypeReg { - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } } - if err := tw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) var buf bytes.Buffer gz := gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err := gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() extractor, err := NewExtractor(source) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Extract to directory with existing content - if err = extractor.Extract(&buf, cacheDir); err != nil { - t.Fatalf("Extraction to directory with existing content failed: %v", err) - } + require.NoErrorf(t, extractor.Extract(&buf, cacheDir), "Extraction to directory with existing content failed") // Verify new file was created newFile := filepath.Join(cacheDir, "existing", "dir", "newfile.txt") - if _, err := os.Stat(newFile); err != nil { - t.Fatalf("Expected new file %s to exist but got error: %v", newFile, err) - } + _, err = os.Stat(newFile) + require.NoErrorf(t, err, "Expected new file %s to exist but got error", newFile) // Verify existing file is still there - if _, err := os.Stat(existingFile); err != nil { - t.Fatalf("Expected existing file %s to still exist but got error: %v", existingFile, err) - } + _, err = os.Stat(existingFile) + require.NoErrorf(t, err, "Expected existing file %s to still exist", existingFile) } func TestExtractPluginInSubdirectory(t *testing.T) { @@ -536,25 +444,19 @@ func TestExtractPluginInSubdirectory(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) if file.TypeFlag == tar.TypeReg { - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } } - if err := tw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) var buf bytes.Buffer gz := gzip.NewWriter(&buf) - if _, err := gz.Write(tarbuf.Bytes()); err != nil { - t.Fatal(err) - } + _, err := gz.Write(tarbuf.Bytes()) + require.NoError(t, err) gz.Close() // Test the installer @@ -573,24 +475,16 @@ func TestExtractPluginInSubdirectory(t *testing.T) { // Ensure the destination directory doesn't exist // (In a real scenario, this is handled by installer.Install() wrapper) destPath := installer.Path() - if err := os.RemoveAll(destPath); err != nil { - t.Fatalf("Failed to clean destination path: %v", err) - } + require.NoErrorf(t, os.RemoveAll(destPath), "Failed to clean destination path") // Install should handle the subdirectory correctly - if err := installer.Install(); err != nil { - t.Fatalf("Failed to install plugin with subdirectory: %v", err) - } + require.NoErrorf(t, installer.Install(), "Failed to install plugin with subdirectory") // The plugin should be installed from the subdirectory // Check that detectPluginRoot found the correct location pluginRoot, err := detectPluginRoot(tempDir) - if err != nil { - t.Fatalf("Failed to detect plugin root: %v", err) - } + require.NoError(t, err, "Failed to detect plugin root") expectedRoot := filepath.Join(tempDir, "my-plugin") - if pluginRoot != expectedRoot { - t.Errorf("Expected plugin root to be %s but got %s", expectedRoot, pluginRoot) - } + assert.Equal(t, expectedRoot, pluginRoot, "Expected plugin root to be %s but got %s", expectedRoot, pluginRoot) } diff --git a/internal/plugin/installer/installer_test.go b/internal/plugin/installer/installer_test.go index 50e8e1ee2..75c22787b 100644 --- a/internal/plugin/installer/installer_test.go +++ b/internal/plugin/installer/installer_test.go @@ -15,33 +15,25 @@ limitations under the License. package installer -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func TestIsRemoteHTTPArchive(t *testing.T) { srv := mockArchiveServer() defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - if isRemoteHTTPArchive("/not/a/URL") { - t.Error("Expected non-URL to return false") - } + assert.False(t, isRemoteHTTPArchive("/not/a/URL"), "Expected non-URL to return false") // URLs with valid archive extensions are considered valid archives // even if the server is unreachable (optimization to avoid unnecessary HTTP requests) - if !isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.tgz") { - t.Error("URL with .tgz extension should be considered a valid archive") - } + assert.True(t, isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.tgz"), "URL with .tgz extension should be considered a valid archive") // Test with invalid extension and unreachable server - if isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.notanarchive") { - t.Error("Bad URL without valid extension should not succeed") - } - - if !isRemoteHTTPArchive(source) { - t.Errorf("Expected %q to be a valid archive URL", source) - } - - if isRemoteHTTPArchive(source + "-not-an-extension") { - t.Error("Expected media type match to fail") - } + assert.False(t, isRemoteHTTPArchive("https://127.0.0.1:123/fake/plugin-1.2.3.notanarchive"), "Bad URL without valid extension should not succeed") + assert.True(t, isRemoteHTTPArchive(source), "Expected %q to be a valid archive URL", source) + assert.False(t, isRemoteHTTPArchive(source+"-not-an-extension"), "Expected media type match to fail") } diff --git a/internal/plugin/installer/local_installer.go b/internal/plugin/installer/local_installer.go index a7a6caa14..59918401b 100644 --- a/internal/plugin/installer/local_installer.go +++ b/internal/plugin/installer/local_installer.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "bytes" diff --git a/internal/plugin/installer/local_installer_test.go b/internal/plugin/installer/local_installer_test.go index 02d4d7bff..94632756c 100644 --- a/internal/plugin/installer/local_installer_test.go +++ b/internal/plugin/installer/local_installer_test.go @@ -13,17 +13,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "archive/tar" "bytes" "compress/gzip" - "errors" "os" "path/filepath" "testing" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/helmpath" ) @@ -34,40 +35,23 @@ func TestLocalInstaller(t *testing.T) { ensure.HelmHome(t) // Make a temp dir tdir := t.TempDir() - if err := os.WriteFile(filepath.Join(tdir, "plugin.yaml"), []byte{}, 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(tdir, "plugin.yaml"), []byte{}, 0o644)) source := "../testdata/plugdir/good/echo-v1" i, err := NewForSource(source, "") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) - if err := Install(i); err != nil { - t.Fatal(err) - } + require.NoError(t, Install(i)) - if i.Path() != helmpath.DataPath("plugins", "echo-v1") { - t.Fatalf("expected path '$XDG_CONFIG_HOME/helm/plugins/helm-env', got %q", i.Path()) - } + require.Equal(t, helmpath.DataPath("plugins", "echo-v1"), i.Path(), "expected path '$XDG_CONFIG_HOME/helm/plugins/helm-env', got %q", i.Path()) os.RemoveAll(filepath.Dir(helmpath.DataPath())) // helmpath.DataPath is like /tmp/helm013130971/helm } func TestLocalInstallerNotAFolder(t *testing.T) { source := "../testdata/plugdir/good/echo-v1/plugin.yaml" i, err := NewForSource(source, "") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - err = Install(i) - if err == nil { - t.Fatal("expected error") - } - if !errors.Is(err, ErrPluginNotADirectory) { - t.Fatalf("expected error to equal: %q", err) - } + require.NoError(t, err) + require.ErrorIs(t, Install(i), ErrPluginNotADirectory) } func TestLocalInstallerTarball(t *testing.T) { @@ -97,53 +81,31 @@ func TestLocalInstallerTarball(t *testing.T) { Mode: file.Mode, Size: int64(len(file.Body)), } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(hdr)) + _, err := tw.Write([]byte(file.Body)) + require.NoError(t, err) } - if err := tw.Close(); err != nil { - t.Fatal(err) - } - if err := gw.Close(); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.Close()) + require.NoError(t, gw.Close()) // Write tarball to file - if err := os.WriteFile(tarballPath, buf.Bytes(), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(tarballPath, buf.Bytes(), 0o644)) // Test installation i, err := NewForSource(tarballPath, "") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // Verify it's detected as LocalInstaller localInstaller, ok := i.(*LocalInstaller) - if !ok { - t.Fatal("expected LocalInstaller") - } - - if !localInstaller.isArchive { - t.Fatal("expected isArchive to be true") - } - - if err := Install(i); err != nil { - t.Fatal(err) - } + require.True(t, ok, "expected LocalInstaller") + require.True(t, localInstaller.isArchive, "expected isArchive to be true") + require.NoError(t, Install(i)) expectedPath := helmpath.DataPath("plugins", "test-plugin") - if i.Path() != expectedPath { - t.Fatalf("expected path %q, got %q", expectedPath, i.Path()) - } + require.Equal(t, expectedPath, i.Path(), "expected path %q, got %q", expectedPath, i.Path()) // Verify plugin was installed - if _, err := os.Stat(i.Path()); err != nil { - t.Fatalf("plugin not found at %s: %v", i.Path(), err) - } + _, err = os.Stat(i.Path()) + require.NoErrorf(t, err, "plugin not found at %s", i.Path()) } diff --git a/internal/plugin/installer/oci_installer_test.go b/internal/plugin/installer/oci_installer_test.go index c3bebdb52..ce381d12c 100644 --- a/internal/plugin/installer/oci_installer_test.go +++ b/internal/plugin/installer/oci_installer_test.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "archive/tar" @@ -64,12 +64,9 @@ command: "$HELM_PLUGIN_DIR/bin/%s" Size: int64(len(pluginYAML)), Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(header); err != nil { - t.Fatal(err) - } - if _, err := tarWriter.Write([]byte(pluginYAML)); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(header)) + _, err := tarWriter.Write([]byte(pluginYAML)) + require.NoError(t, err) // Add bin directory dirHeader := &tar.Header{ @@ -77,9 +74,7 @@ command: "$HELM_PLUGIN_DIR/bin/%s" Mode: 0o755, Typeflag: tar.TypeDir, } - if err := tarWriter.WriteHeader(dirHeader); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(dirHeader)) // Add executable execContent := fmt.Sprintf("#!/bin/sh\necho '%s test plugin'", pluginName) @@ -89,12 +84,9 @@ command: "$HELM_PLUGIN_DIR/bin/%s" Size: int64(len(execContent)), Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(execHeader); err != nil { - t.Fatal(err) - } - if _, err := tarWriter.Write([]byte(execContent)); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(execHeader)) + _, err = tarWriter.Write([]byte(execContent)) + require.NoError(t, err) tarWriter.Close() gzWriter.Close() @@ -135,9 +127,7 @@ func mockOCIRegistryWithArtifactType(t *testing.T, pluginName string) (*httptest } manifestData, err := json.Marshal(manifest) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) manifestDigest := fmt.Sprintf("sha256:%x", sha256Sum(manifestData)) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -175,9 +165,7 @@ func mockOCIRegistryWithArtifactType(t *testing.T, pluginName string) (*httptest // Parse server URL to get host:port format for OCI reference serverURL, err := url.Parse(server.URL) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) registryHost := serverURL.Host return server, registryHost @@ -240,42 +228,20 @@ func TestNewOCIInstaller(t *testing.T) { installer, err := NewOCIInstaller(tt.source) if tt.expectError { - if err == nil { - t.Error("expected error but got none") - } - return - } - - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } - - // Check all fields thoroughly - if installer.PluginName != tt.expectName { - t.Errorf("expected plugin name %s, got %s", tt.expectName, installer.PluginName) - } - - if installer.Source != tt.source { - t.Errorf("expected source %s, got %s", tt.source, installer.Source) - } - - if installer.CacheDir == "" { - t.Error("expected non-empty cache directory") - } - - if !strings.Contains(installer.CacheDir, "plugins") { - t.Errorf("expected cache directory to contain 'plugins', got %s", installer.CacheDir) - } - - if installer.settings == nil { - t.Error("expected settings to be initialized") - } - - // Check that Path() method works - expectedPath := helmpath.DataPath("plugins", tt.expectName) - if installer.Path() != expectedPath { - t.Errorf("expected path %s, got %s", expectedPath, installer.Path()) + require.Error(t, err) + } else { + require.NoError(t, err) + + // Check all fields thoroughly + assert.Equal(t, tt.expectName, installer.PluginName, "expected plugin name %s, got %s", tt.expectName, installer.PluginName) + assert.Equal(t, tt.source, installer.Source, "expected source %s, got %s", tt.source, installer.Source) + assert.NotEmpty(t, installer.CacheDir, "expected non-empty cache directory") + assert.Contains(t, installer.CacheDir, "plugins", "expected cache directory to contain 'plugins', got %s", installer.CacheDir) + assert.NotNil(t, installer.settings, "expected settings to be initialized") + + // Check that Path() method works + expectedPath := helmpath.DataPath("plugins", tt.expectName) + assert.Equal(t, expectedPath, installer.Path(), "expected path %s, got %s", expectedPath, installer.Path()) } }) } @@ -311,9 +277,7 @@ func TestOCIInstaller_Path(t *testing.T) { } path := installer.Path() - if path != tt.expectPath { - t.Errorf("expected path %s, got %s", tt.expectPath, path) - } + assert.Equal(t, tt.expectPath, path, "expected path %s, got %s", tt.expectPath, path) }) } } @@ -331,39 +295,30 @@ func TestOCIInstaller_Install(t *testing.T) { // Test with plain HTTP (since test server uses HTTP) installer, err := NewOCIInstaller(source, getter.WithPlainHTTP(true)) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } + require.NoError(t, err) // The OCI installer uses helmpath.DataPath, which is isolated by ensure.HelmHome(t) actualPath := installer.Path() t.Logf("Installer will use path: %s", actualPath) // Install the plugin - if err := Install(installer); err != nil { - t.Fatalf("Expected installation to succeed, got error: %v", err) - } + require.NoErrorf(t, Install(installer), "Expected installation to succeed") // Verify plugin was installed to the correct location - if !isPlugin(actualPath) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml", actualPath) - } + assert.Truef(t, isPlugin(actualPath), "Expected plugin directory %s to contain plugin.yaml", actualPath) // Debug: list what was actually created - if entries, err := os.ReadDir(actualPath); err != nil { - t.Fatalf("Could not read plugin directory %s: %v", actualPath, err) - } else { - t.Logf("Plugin directory %s contains:", actualPath) - for _, entry := range entries { - t.Logf(" - %s", entry.Name()) - } + entries, err := os.ReadDir(actualPath) + require.NoError(t, err, "Could not read plugin directory %s", actualPath) + t.Logf("Plugin directory %s contains:", actualPath) + for _, entry := range entries { + t.Logf(" - %s", entry.Name()) } // Verify the plugin.yaml file exists and is valid pluginFile := filepath.Join(actualPath, "plugin.yaml") - if _, err := os.Stat(pluginFile); err != nil { - t.Errorf("Expected plugin.yaml to exist, got error: %v", err) - } + _, err = os.Stat(pluginFile) + assert.NoErrorf(t, err, "Expected plugin.yaml to exist") } func TestOCIInstaller_Install_WithGetterOptions(t *testing.T) { @@ -404,11 +359,9 @@ func TestOCIInstaller_Install_WithGetterOptions(t *testing.T) { source := fmt.Sprintf("oci://%s/%s:latest", registryHost, tc.pluginName) installer, err := NewOCIInstaller(source, tc.options...) - if err != nil { - if !tc.wantErr { - t.Fatalf("Expected no error creating installer, got %v", err) - } - return + + if !tc.wantErr { + require.NoError(t, err, "Expected no error creating installer") } // The installer now uses our isolated test directory @@ -419,7 +372,7 @@ func TestOCIInstaller_Install_WithGetterOptions(t *testing.T) { if tc.wantErr { require.Error(t, err, "Expected installation to fail, but it succeeded") } else { - require.NoError(t, err, "Expected installation to succeed, got error: %v", err) + require.NoError(t, err, "Expected installation to succeed") // Verify plugin was installed to the actual path assert.True(t, isPlugin(actualPath), "Expected plugin directory %s to contain plugin.yaml", actualPath) } @@ -437,27 +390,16 @@ func TestOCIInstaller_Install_AlreadyExists(t *testing.T) { source := fmt.Sprintf("oci://%s/%s:latest", registryHost, pluginName) installer, err := NewOCIInstaller(source, getter.WithPlainHTTP(true)) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } + require.NoError(t, err) // First install should succeed - if err := Install(installer); err != nil { - t.Fatalf("Expected first installation to succeed, got error: %v", err) - } + require.NoErrorf(t, Install(installer), "Expected first installation to succeed") // Verify plugin was installed - if !isPlugin(installer.Path()) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml", installer.Path()) - } + assert.Truef(t, isPlugin(installer.Path()), "Expected plugin directory %s to contain plugin.yaml", installer.Path()) // Second install should fail with "plugin already exists" - err = Install(installer) - if err == nil { - t.Error("Expected error when installing plugin that already exists") - } else if !strings.Contains(err.Error(), "plugin already exists") { - t.Errorf("Expected 'plugin already exists' error, got: %v", err) - } + assert.ErrorContains(t, Install(installer), "plugin already exists") } func TestOCIInstaller_Update(t *testing.T) { @@ -470,38 +412,23 @@ func TestOCIInstaller_Update(t *testing.T) { source := fmt.Sprintf("oci://%s/%s:latest", registryHost, pluginName) installer, err := NewOCIInstaller(source, getter.WithPlainHTTP(true)) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } + require.NoError(t, err) // Test update when plugin does not exist - should fail - err = Update(installer) - if err == nil { - t.Error("Expected error when updating plugin that does not exist") - } else if !strings.Contains(err.Error(), "plugin does not exist") { - t.Errorf("Expected 'plugin does not exist' error, got: %v", err) - } + require.ErrorContains(t, Update(installer), "plugin does not exist") // Install plugin first - if err := Install(installer); err != nil { - t.Fatalf("Expected installation to succeed, got error: %v", err) - } + require.NoErrorf(t, Install(installer), "Expected installation to succeed") // Verify plugin was installed - if !isPlugin(installer.Path()) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml", installer.Path()) - } + assert.Truef(t, isPlugin(installer.Path()), "Expected plugin directory %s to contain plugin.yaml", installer.Path()) // Test update when plugin exists - should succeed // For OCI, Update() removes old version and reinstalls - if err := Update(installer); err != nil { - t.Errorf("Expected update to succeed, got error: %v", err) - } + require.NoErrorf(t, Update(installer), "Expected update to succeed") // Verify plugin is still installed after update - if !isPlugin(installer.Path()) { - t.Errorf("Expected plugin directory %s to contain plugin.yaml after update", installer.Path()) - } + assert.Truef(t, isPlugin(installer.Path()), "Expected plugin directory %s to contain plugin.yaml after update", installer.Path()) } func TestOCIInstaller_Install_ComponentExtraction(t *testing.T) { @@ -513,35 +440,26 @@ func TestOCIInstaller_Install_ComponentExtraction(t *testing.T) { pluginData := createTestPluginTarGz(t, pluginName) // Test extraction - err := extractTarGz(bytes.NewReader(pluginData), tempDir) - if err != nil { - t.Fatalf("Failed to extract plugin: %v", err) - } + require.NoError(t, extractTarGz(bytes.NewReader(pluginData), tempDir), "Failed to extract plugin") // Verify plugin.yaml exists pluginYAMLPath := filepath.Join(tempDir, "plugin.yaml") - if _, err := os.Stat(pluginYAMLPath); os.IsNotExist(err) { - t.Error("plugin.yaml not found after extraction") - } + _, err := os.Stat(pluginYAMLPath) + assert.False(t, os.IsNotExist(err), "plugin.yaml not found after extraction") // Verify bin directory exists binPath := filepath.Join(tempDir, "bin") - if _, err := os.Stat(binPath); os.IsNotExist(err) { - t.Error("bin directory not found after extraction") - } + _, err = os.Stat(binPath) + assert.False(t, os.IsNotExist(err), "bin directory not found after extraction") // Verify executable exists and has correct permissions execPath := filepath.Join(tempDir, "bin", pluginName) - if info, err := os.Stat(execPath); err != nil { - t.Errorf("executable not found: %v", err) - } else if info.Mode()&0o111 == 0 { - t.Error("file is not executable") - } + info, err := os.Stat(execPath) + require.NoError(t, err, "executable not found") + assert.NotEqual(t, 0, info.Mode()&0o111, "file is not executable") // Verify this would be recognized as a plugin - if !isPlugin(tempDir) { - t.Error("extracted directory is not a valid plugin") - } + assert.True(t, isPlugin(tempDir), "extracted directory is not a valid plugin") } func TestExtractTarGz(t *testing.T) { @@ -561,13 +479,10 @@ func TestExtractTarGz(t *testing.T) { Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(header); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(header)) - if _, err := tarWriter.Write([]byte(testContent)); err != nil { - t.Fatal(err) - } + _, err := tarWriter.Write([]byte(testContent)) + require.NoError(t, err) // Add a test directory dirHeader := &tar.Header{ @@ -576,35 +491,25 @@ func TestExtractTarGz(t *testing.T) { Typeflag: tar.TypeDir, } - if err := tarWriter.WriteHeader(dirHeader); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(dirHeader)) tarWriter.Close() gzWriter.Close() // Test extraction - err := extractTarGz(bytes.NewReader(buf.Bytes()), tempDir) - if err != nil { - t.Errorf("extractTarGz failed: %v", err) - } + require.NoError(t, extractTarGz(bytes.NewReader(buf.Bytes()), tempDir), "extractTarGz failed") // Verify extracted file extractedFile := filepath.Join(tempDir, "test-file.txt") content, err := os.ReadFile(extractedFile) - if err != nil { - t.Errorf("failed to read extracted file: %v", err) - } + require.NoError(t, err, "failed to read extracted file") - if string(content) != testContent { - t.Errorf("expected content %s, got %s", testContent, string(content)) - } + assert.Equal(t, testContent, string(content), "expected content %s, got %s", testContent, string(content)) // Verify extracted directory extractedDir := filepath.Join(tempDir, "test-dir") - if _, err := os.Stat(extractedDir); os.IsNotExist(err) { - t.Errorf("extracted directory does not exist: %s", extractedDir) - } + _, err = os.Stat(extractedDir) + assert.Falsef(t, os.IsNotExist(err), "extracted directory does not exist: %s", extractedDir) } func TestExtractTarGz_InvalidGzip(t *testing.T) { @@ -612,10 +517,7 @@ func TestExtractTarGz_InvalidGzip(t *testing.T) { // Test with invalid gzip data invalidGzipData := []byte("not gzip data") - err := extractTarGz(bytes.NewReader(invalidGzipData), tempDir) - if err == nil { - t.Error("expected error for invalid gzip data") - } + assert.Error(t, extractTarGz(bytes.NewReader(invalidGzipData), tempDir), "expected error for invalid gzip data") } func TestExtractTar_UnknownFileType(t *testing.T) { @@ -634,13 +536,10 @@ func TestExtractTar_UnknownFileType(t *testing.T) { Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(header); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(header)) - if _, err := tarWriter.Write([]byte(testContent)); err != nil { - t.Fatal(err) - } + _, err := tarWriter.Write([]byte(testContent)) + require.NoError(t, err) // Test unknown file type unknownHeader := &tar.Header{ @@ -649,21 +548,12 @@ func TestExtractTar_UnknownFileType(t *testing.T) { Typeflag: tar.TypeSymlink, // Use a type that's not handled } - if err := tarWriter.WriteHeader(unknownHeader); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(unknownHeader)) tarWriter.Close() // Test extraction - should fail due to unknown type - err := extractTar(bytes.NewReader(buf.Bytes()), tempDir) - if err == nil { - t.Error("expected error for unknown tar file type") - } - - if !strings.Contains(err.Error(), "unknown type") { - t.Errorf("expected 'unknown type' error, got: %v", err) - } + assert.ErrorContains(t, extractTar(bytes.NewReader(buf.Bytes()), tempDir), "unknown type") } func TestExtractTar_SuccessfulExtraction(t *testing.T) { @@ -686,32 +576,22 @@ func TestExtractTar_SuccessfulExtraction(t *testing.T) { Typeflag: tar.TypeReg, } - if err := tarWriter.WriteHeader(header); err != nil { - t.Fatal(err) - } + require.NoError(t, tarWriter.WriteHeader(header)) - if _, err := tarWriter.Write([]byte(testContent)); err != nil { - t.Fatal(err) - } + _, err := tarWriter.Write([]byte(testContent)) + require.NoError(t, err) tarWriter.Close() // Test extraction - err := extractTar(bytes.NewReader(buf.Bytes()), tempDir) - if err != nil { - t.Errorf("extractTar failed: %v", err) - } + require.NoError(t, extractTar(bytes.NewReader(buf.Bytes()), tempDir), "extractTar failed") // Verify the regular file was extracted extractedFile := filepath.Join(tempDir, "test-file.txt") content, err := os.ReadFile(extractedFile) - if err != nil { - t.Errorf("failed to read extracted file: %v", err) - } + require.NoError(t, err, "failed to read extracted file") - if string(content) != testContent { - t.Errorf("expected content %s, got %s", testContent, string(content)) - } + assert.Equal(t, testContent, string(content), "expected content %s, got %s", testContent, string(content)) } func TestOCIInstaller_Install_PlainHTTPOption(t *testing.T) { @@ -720,41 +600,25 @@ func TestOCIInstaller_Install_PlainHTTPOption(t *testing.T) { // Test with PlainHTTP=false (default) installer1, err := NewOCIInstaller(source) - if err != nil { - t.Fatalf("failed to create installer: %v", err) - } - if installer1.getter == nil { - t.Error("getter should be initialized") - } + require.NoError(t, err, "failed to create installer") + assert.NotNil(t, installer1.getter, "getter should be initialized") // Test with PlainHTTP=true installer2, err := NewOCIInstaller(source, getter.WithPlainHTTP(true)) - if err != nil { - t.Fatalf("failed to create installer with PlainHTTP=true: %v", err) - } - if installer2.getter == nil { - t.Error("getter should be initialized with PlainHTTP=true") - } + require.NoError(t, err, "failed to create installer with PlainHTTP=true") + assert.NotNil(t, installer2.getter, "getter should be initialized with PlainHTTP=true") // Both installers should have the same basic properties - if installer1.PluginName != installer2.PluginName { - t.Error("plugin names should match") - } - if installer1.Source != installer2.Source { - t.Error("sources should match") - } + assert.Equal(t, installer2.PluginName, installer1.PluginName, "plugin names should match") + assert.Equal(t, installer2.Source, installer1.Source, "sources should match") // Test with multiple options installer3, err := NewOCIInstaller(source, getter.WithPlainHTTP(true), getter.WithBasicAuth("user", "pass"), ) - if err != nil { - t.Fatalf("failed to create installer with multiple options: %v", err) - } - if installer3.getter == nil { - t.Error("getter should be initialized with multiple options") - } + require.NoError(t, err, "failed to create installer with multiple options") + assert.NotNil(t, installer3.getter, "getter should be initialized with multiple options") } func TestOCIInstaller_Install_ValidationErrors(t *testing.T) { @@ -789,12 +653,8 @@ func TestOCIInstaller_Install_ValidationErrors(t *testing.T) { // Test the gzip validation logic that's used in the Install method if len(tt.layerData) < 2 || tt.layerData[0] != 0x1f || tt.layerData[1] != 0x8b { // This matches the validation in the Install method - if !tt.expectError { - t.Error("expected valid gzip data") - } - if !strings.Contains(tt.errorMsg, "is not a gzip compressed archive") { - t.Error("expected error message to contain 'is not a gzip compressed archive'") - } + assert.True(t, tt.expectError, "expected valid gzip data") + assert.Contains(t, tt.errorMsg, "is not a gzip compressed archive") } }) } diff --git a/internal/plugin/installer/plugin_structure_test.go b/internal/plugin/installer/plugin_structure_test.go index 182eb9bd8..187918a4b 100644 --- a/internal/plugin/installer/plugin_structure_test.go +++ b/internal/plugin/installer/plugin_structure_test.go @@ -19,6 +19,9 @@ import ( "os" "path/filepath" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestDetectPluginRoot(t *testing.T) { @@ -73,26 +76,18 @@ func TestDetectPluginRoot(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dir := t.TempDir() - if err := tt.setup(dir); err != nil { - t.Fatalf("Setup failed: %v", err) - } + require.NoErrorf(t, tt.setup(dir), "Setup failed") root, err := detectPluginRoot(dir) if tt.expectError { - if err == nil { - t.Error("Expected error but got none") - } + assert.Error(t, err) } else { - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + require.NoError(t, err) expectedPath := dir if tt.expectRoot != "." { expectedPath = filepath.Join(dir, tt.expectRoot) } - if root != expectedPath { - t.Errorf("Expected root %s but got %s", expectedPath, root) - } + assert.Equal(t, expectedPath, root, "Expected root %s but got %s", expectedPath, root) } }) } @@ -145,20 +140,14 @@ description: test` for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dir := t.TempDir() - if err := tt.setup(dir); err != nil { - t.Fatalf("Setup failed: %v", err) - } + require.NoErrorf(t, tt.setup(dir), "Setup failed") pluginRoot := filepath.Join(dir, tt.pluginRoot) err := validatePluginName(pluginRoot, tt.expectedName) if tt.expectError { - if err == nil { - t.Error("Expected error but got none") - } + assert.Error(t, err) } else { - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + assert.NoError(t, err) } }) } diff --git a/internal/plugin/installer/vcs_installer.go b/internal/plugin/installer/vcs_installer.go index 3601ec7a8..13aba74dc 100644 --- a/internal/plugin/installer/vcs_installer.go +++ b/internal/plugin/installer/vcs_installer.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "errors" diff --git a/internal/plugin/installer/vcs_installer_test.go b/internal/plugin/installer/vcs_installer_test.go index 401f2b921..82401d069 100644 --- a/internal/plugin/installer/vcs_installer_test.go +++ b/internal/plugin/installer/vcs_installer_test.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package installer // import "helm.sh/helm/v4/internal/plugin/installer" +package installer import ( "fmt" @@ -23,6 +23,7 @@ import ( "testing" "github.com/Masterminds/vcs" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/helmpath" @@ -52,9 +53,7 @@ func (r *testRepo) UpdateVersion(version string) error { func TestVCSInstaller(t *testing.T) { ensure.HelmHome(t) - if err := os.MkdirAll(helmpath.DataPath("plugins"), 0o755); err != nil { - t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) - } + require.NoErrorf(t, os.MkdirAll(helmpath.DataPath("plugins"), 0o755), "Could not create %s", helmpath.DataPath("plugins")) source := "https://github.com/adamreese/helm-env" testRepoPath, _ := filepath.Abs("../testdata/plugdir/good/echo-v1") @@ -64,43 +63,27 @@ func TestVCSInstaller(t *testing.T) { } i, err := NewForSource(source, "~0.1.0") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a VCSInstaller was returned vcsInstaller, ok := i.(*VCSInstaller) - if !ok { - t.Fatal("expected a VCSInstaller") - } + require.True(t, ok, "expected a VCSInstaller") // set the testRepo in the VCSInstaller vcsInstaller.Repo = repo - if err := Install(i); err != nil { - t.Fatal(err) - } - if repo.current != "0.1.1" { - t.Fatalf("expected version '0.1.1', got %q", repo.current) - } + require.NoError(t, Install(i)) + require.Equal(t, "0.1.1", repo.current, "expected version '0.1.1', got %q", repo.current) expectedPath := helmpath.DataPath("plugins", "helm-env") - if i.Path() != expectedPath { - t.Fatalf("expected path %q, got %q", expectedPath, i.Path()) - } + require.Equal(t, expectedPath, i.Path(), "expected path %q, got %q", expectedPath, i.Path()) // Install again to test plugin exists error - if err := Install(i); err == nil { - t.Fatal("expected error for plugin exists, got none") - } else if err.Error() != "plugin already exists" { - t.Fatalf("expected error for plugin exists, got (%v)", err) - } + require.EqualErrorf(t, Install(i), "plugin already exists", "expected error for plugin exists") // Testing FindSource method, expect error because plugin code is not a cloned repository - if _, err := FindSource(i.Path()); err == nil { - t.Fatal("expected error for inability to find plugin source, got none") - } else if err.Error() != "cannot get information about plugin source" { - t.Fatalf("expected error for inability to find plugin source, got (%v)", err) - } + _, err = FindSource(i.Path()) + require.Error(t, err, "expected error for inability to find plugin source, got none") + require.EqualErrorf(t, err, "cannot get information about plugin source", "expected error for inability to find plugin source") } func TestVCSInstallerNonExistentVersion(t *testing.T) { @@ -110,22 +93,17 @@ func TestVCSInstallerNonExistentVersion(t *testing.T) { version := "0.2.0" i, err := NewForSource(source, version) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a VCSInstaller was returned - if _, ok := i.(*VCSInstaller); !ok { - t.Fatal("expected a VCSInstaller") - } + require.IsType(t, &VCSInstaller{}, i, "expected a VCSInstaller") - if err := Install(i); err == nil { - t.Fatal("expected error for version does not exists, got none") - } else if strings.Contains(err.Error(), "Could not resolve host: github.com") { + err = Install(i) + require.Error(t, err, "expected error for version does not exists, got none") + if strings.Contains(err.Error(), "Could not resolve host: github.com") { t.Skip("Unable to run test without Internet access") - } else if err.Error() != fmt.Sprintf("requested version %q does not exist for plugin %q", version, source) { - t.Fatalf("expected error for version does not exists, got (%v)", err) } + require.EqualErrorf(t, err, fmt.Sprintf("requested version %q does not exist for plugin %q", version, source), "expected error for version does not exists") } func TestVCSInstallerUpdate(t *testing.T) { ensure.HelmHome(t) @@ -133,56 +111,34 @@ func TestVCSInstallerUpdate(t *testing.T) { source := "https://github.com/adamreese/helm-env" i, err := NewForSource(source, "") - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) // ensure a VCSInstaller was returned - if _, ok := i.(*VCSInstaller); !ok { - t.Fatal("expected a VCSInstaller") - } + require.IsType(t, &VCSInstaller{}, i, "expected a VCSInstaller") - if err := Update(i); err == nil { - t.Fatal("expected error for plugin does not exist, got none") - } else if err.Error() != "plugin does not exist" { - t.Fatalf("expected error for plugin does not exist, got (%v)", err) - } + require.EqualErrorf(t, Update(i), "plugin does not exist", "expected error for plugin does not exist") // Install plugin before update - if err := Install(i); err != nil { - if strings.Contains(err.Error(), "Could not resolve host: github.com") { - t.Skip("Unable to run test without Internet access") - } else { - t.Fatal(err) - } + err = Install(i) + if err != nil && strings.Contains(err.Error(), "Could not resolve host: github.com") { + t.Skip("Unable to run test without Internet access") } + require.NoError(t, err) // Test FindSource method for positive result pluginInfo, err := FindSource(i.Path()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vcsInstaller := pluginInfo.(*VCSInstaller) repoRemote := vcsInstaller.Repo.Remote() - if repoRemote != source { - t.Fatalf("invalid source found, expected %q got %q", source, repoRemote) - } + require.Equal(t, source, repoRemote, "invalid source found, expected %q got %q", source, repoRemote) // Update plugin - if err := Update(i); err != nil { - t.Fatal(err) - } + require.NoError(t, Update(i)) // Test update failure - if err := os.Remove(filepath.Join(vcsInstaller.Repo.LocalPath(), "plugin.yaml")); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Remove(filepath.Join(vcsInstaller.Repo.LocalPath(), "plugin.yaml"))) // Testing update for error - if err := Update(vcsInstaller); err == nil { - t.Fatal("expected error for plugin modified, got none") - } else if err.Error() != "plugin repo was modified" { - t.Fatalf("expected error for plugin modified, got (%v)", err) - } + require.EqualErrorf(t, Update(vcsInstaller), "plugin repo was modified", "expected error for plugin modified") } diff --git a/internal/plugin/installer/verification_test.go b/internal/plugin/installer/verification_test.go index d3824a0fc..1f8aa7ef4 100644 --- a/internal/plugin/installer/verification_test.go +++ b/internal/plugin/installer/verification_test.go @@ -23,6 +23,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/plugin" "helm.sh/helm/v4/internal/test/ensure" ) @@ -37,29 +40,20 @@ func TestInstallWithOptions_VerifyMissingProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification enabled should fail when .prov is missing result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: "dummy"}) // Should fail with a missing provenance error - if err == nil { - t.Fatal("Expected installation to fail when .prov file is missing and verification is enabled") - } - if !strings.Contains(err.Error(), "no provenance file") { - t.Errorf("Expected 'no provenance file' in error message, got: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when .prov file is missing, got: %+v", result) - } + require.Error(t, err, "Expected installation to fail when .prov file is missing and verification is enabled") + require.ErrorContains(t, err, "no provenance file") + assert.Nil(t, result, "Expected nil verification result when .prov file is missing, got: %+v", result) // Plugin should NOT be installed - if _, err := os.Stat(installer.Path()); !os.IsNotExist(err) { - t.Error("Plugin should not be installed when verification fails due to missing .prov") - } + _, err = os.Stat(installer.Path()) + assert.True(t, os.IsNotExist(err), "Plugin should not be installed when verification fails due to missing .prov") } func TestInstallWithOptions_NoVerifyMissingProvenance(t *testing.T) { @@ -72,25 +66,18 @@ func TestInstallWithOptions_NoVerifyMissingProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification explicitly disabled should succeed without .prov result, err := InstallWithOptions(installer, Options{Verify: false}) - if err != nil { - t.Fatalf("Expected installation to succeed with --verify=false, got error: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification is disabled, got: %+v", result) - } + require.NoError(t, err, "Expected installation to succeed with --verify=false") + assert.Nil(t, result, "Expected nil verification result when verification is disabled, got: %+v", result) // Plugin should be installed - if _, err := os.Stat(installer.Path()); os.IsNotExist(err) { - t.Errorf("Plugin should be installed at %s", installer.Path()) - } + _, err = os.Stat(installer.Path()) + assert.Falsef(t, os.IsNotExist(err), "Plugin should be installed at %s", installer.Path()) } func TestInstallWithOptions_VerifyWithValidProvenance(t *testing.T) { @@ -110,9 +97,7 @@ func TestInstallWithOptions_VerifyWithValidProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification enabled @@ -120,20 +105,13 @@ func TestInstallWithOptions_VerifyWithValidProvenance(t *testing.T) { result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: keyring}) // Should fail due to invalid signature (empty keyring) but we test that it gets past the hash check - if err == nil { - t.Fatal("Expected installation to fail with empty keyring") - } - if !strings.Contains(err.Error(), "plugin verification failed") { - t.Errorf("Expected plugin verification failed error, got: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + require.Error(t, err, "Expected installation to fail with empty keyring") + require.ErrorContains(t, err, "plugin verification failed") + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) // Plugin should not be installed due to verification failure - if _, err := os.Stat(installer.Path()); !os.IsNotExist(err) { - t.Error("Plugin should not be installed when verification fails") - } + _, err = os.Stat(installer.Path()) + assert.True(t, os.IsNotExist(err), "Plugin should not be installed when verification fails") } func TestInstallWithOptions_VerifyWithInvalidProvenance(t *testing.T) { @@ -154,32 +132,23 @@ func TestInstallWithOptions_VerifyWithInvalidProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification enabled (should fail) result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: keyring}) // Should fail with verification error - if err == nil { - t.Fatal("Expected installation with invalid .prov file to fail") - } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + require.Error(t, err, "Expected installation with invalid .prov file to fail") + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) // Should contain verification failure message expectedError := "plugin verification failed" - if !strings.Contains(err.Error(), expectedError) { - t.Errorf("Expected error message '%s', got: %s", expectedError, err.Error()) - } + require.ErrorContains(t, err, expectedError) // Plugin should not be installed - if _, err := os.Stat(installer.Path()); !os.IsNotExist(err) { - t.Error("Plugin should not be installed when verification fails") - } + _, err = os.Stat(installer.Path()) + assert.True(t, os.IsNotExist(err), "Plugin should not be installed when verification fails") } func TestInstallWithOptions_NoVerifyRequested(t *testing.T) { @@ -192,26 +161,19 @@ func TestInstallWithOptions_NoVerifyRequested(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install without verification (should succeed without any verification) result, err := InstallWithOptions(installer, Options{Verify: false}) // Should succeed with no verification - if err != nil { - t.Fatalf("Expected installation without verification to succeed, got error: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification is disabled, got: %+v", result) - } + require.NoError(t, err, "Expected installation without verification to succeed") + assert.Nil(t, result, "Expected nil verification result when verification is disabled, got: %+v", result) // Plugin should be installed - if _, err := os.Stat(installer.Path()); os.IsNotExist(err) { - t.Errorf("Plugin should be installed at %s", installer.Path()) - } + _, err = os.Stat(installer.Path()) + assert.Falsef(t, os.IsNotExist(err), "Plugin should be installed at %s", installer.Path()) } func TestInstallWithOptions_VerifyDirectoryNotSupported(t *testing.T) { @@ -222,24 +184,16 @@ func TestInstallWithOptions_VerifyDirectoryNotSupported(t *testing.T) { // Create local installer for directory installer, err := NewLocalInstaller(pluginDir) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification should fail (directories don't support verification) result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: "dummy"}) // Should fail with verification not supported error - if err == nil { - t.Fatal("Expected installation to fail with verification not supported error") - } - if !strings.Contains(err.Error(), "--verify is only supported for plugin tarballs") { - t.Errorf("Expected verification not supported error, got: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + require.Error(t, err, "Expected installation to fail with verification not supported error") + require.ErrorContains(t, err, "--verify is only supported for plugin tarballs") + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) } func TestInstallWithOptions_VerifyMismatchedProvenance(t *testing.T) { @@ -261,24 +215,16 @@ func TestInstallWithOptions_VerifyMismatchedProvenance(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification should fail due to hash mismatch result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: keyring}) // Should fail with verification error - if err == nil { - t.Fatal("Expected installation to fail with hash mismatch") - } - if !strings.Contains(err.Error(), "plugin verification failed") { - t.Errorf("Expected plugin verification failed error, got: %v", err) - } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + require.Error(t, err, "Expected installation to fail with hash mismatch") + require.ErrorContains(t, err, "plugin verification failed") + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) } func TestInstallWithOptions_VerifyProvenanceAccessError(t *testing.T) { @@ -291,9 +237,7 @@ func TestInstallWithOptions_VerifyProvenanceAccessError(t *testing.T) { // Create a .prov file but make it inaccessible (simulate permission error) provFile := pluginTgz + ".prov" - if err := os.WriteFile(provFile, []byte("test"), 0o000); err != nil { - t.Fatalf("Failed to create inaccessible provenance file: %v", err) - } + require.NoErrorf(t, os.WriteFile(provFile, []byte("test"), 0o000), "Failed to create inaccessible provenance file") defer os.Remove(provFile) // Create keyring @@ -302,27 +246,21 @@ func TestInstallWithOptions_VerifyProvenanceAccessError(t *testing.T) { // Create local installer installer, err := NewLocalInstaller(pluginTgz) - if err != nil { - t.Fatalf("Failed to create installer: %v", err) - } + require.NoError(t, err, "Failed to create installer") defer os.RemoveAll(installer.Path()) // Install with verification should fail due to access error result, err := InstallWithOptions(installer, Options{Verify: true, Keyring: keyring}) // Should fail with access error (either at stat level or during verification) - if err == nil { - t.Fatal("Expected installation to fail with provenance file access error") - } + require.Error(t, err, "Expected installation to fail with provenance file access error") // The error could be either "failed to access provenance file" or "plugin verification failed" // depending on when the permission error occurs if !strings.Contains(err.Error(), "failed to access provenance file") && !strings.Contains(err.Error(), "plugin verification failed") { t.Errorf("Expected provenance file access or verification error, got: %v", err) } - if result != nil { - t.Errorf("Expected nil verification result when verification fails, got: %+v", result) - } + assert.Nil(t, result, "Expected nil verification result when verification fails, got: %+v", result) } // Helper functions for test setup @@ -333,9 +271,7 @@ func createTestPluginDir(t *testing.T) string { // Create temporary directory with plugin structure tmpDir := t.TempDir() pluginDir := filepath.Join(tmpDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatalf("Failed to create plugin directory: %v", err) - } + require.NoErrorf(t, os.MkdirAll(pluginDir, 0o755), "Failed to create plugin directory") // Create plugin.yaml using the standardized v1 format pluginYaml := `apiVersion: v1 @@ -346,9 +282,7 @@ version: 1.0.0 runtimeConfig: platformCommand: - command: echo` - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYaml), 0o644); err != nil { - t.Fatalf("Failed to create plugin.yaml: %v", err) - } + require.NoErrorf(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYaml), 0o644), "Failed to create plugin.yaml") return pluginDir } @@ -360,15 +294,10 @@ func createTarballFromPluginDir(t *testing.T, pluginDir string) string { tmpDir := filepath.Dir(pluginDir) tgzPath := filepath.Join(tmpDir, "test-plugin-1.0.0.tgz") tarFile, err := os.Create(tgzPath) - if err != nil { - t.Fatalf("Failed to create tarball file: %v", err) - } + require.NoError(t, err, "Failed to create tarball file") defer tarFile.Close() - if err := plugin.CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil { - t.Fatalf("Failed to create tarball: %v", err) - } - + require.NoErrorf(t, plugin.CreatePluginTarball(pluginDir, "test-plugin", tarFile), "Failed to create tarball") return tgzPath } @@ -379,9 +308,7 @@ func createProvFile(t *testing.T, provFile, pluginTgz, hash string) { if hash == "" { // Calculate actual hash of the tarball for realistic testing data, err := os.ReadFile(pluginTgz) - if err != nil { - t.Fatalf("Failed to read tarball for hashing: %v", err) - } + require.NoError(t, err, "Failed to read tarball for hashing") hashSum := sha256.Sum256(data) hashStr = fmt.Sprintf("sha256:%x", hashSum) } else { @@ -404,9 +331,7 @@ Version: GnuPG v1 iQEcBAEBCAAGBQJktest... -----END PGP SIGNATURE----- `, hashStr) - if err := os.WriteFile(provFile, []byte(provContent), 0o644); err != nil { - t.Fatalf("Failed to create provenance file: %v", err) - } + require.NoErrorf(t, os.WriteFile(provFile, []byte(provContent), 0o644), "Failed to create provenance file") } func createProvFileInvalidFormat(t *testing.T, provFile string) { @@ -414,9 +339,7 @@ func createProvFileInvalidFormat(t *testing.T, provFile string) { // Create an invalid provenance file (not PGP signed format) invalidProv := "This is not a valid PGP signed message" - if err := os.WriteFile(provFile, []byte(invalidProv), 0o644); err != nil { - t.Fatalf("Failed to create invalid provenance file: %v", err) - } + require.NoErrorf(t, os.WriteFile(provFile, []byte(invalidProv), 0o644), "Failed to create invalid provenance file") } func createTestKeyring(t *testing.T) string { @@ -427,9 +350,7 @@ func createTestKeyring(t *testing.T) string { keyringPath := filepath.Join(tmpDir, "pubring.gpg") // Create empty keyring for testing - if err := os.WriteFile(keyringPath, []byte{}, 0o644); err != nil { - t.Fatalf("Failed to create test keyring: %v", err) - } + require.NoErrorf(t, os.WriteFile(keyringPath, []byte{}, 0o644), "Failed to create test keyring") return keyringPath } diff --git a/internal/plugin/loader_test.go b/internal/plugin/loader_test.go index 4b98a6f83..e0682aed7 100644 --- a/internal/plugin/loader_test.go +++ b/internal/plugin/loader_test.go @@ -194,13 +194,9 @@ func TestDetectDuplicates(t *testing.T) { mockSubprocessCLIPlugin(t, "foo"), mockSubprocessCLIPlugin(t, "bar"), } - if err := detectDuplicates(plugs); err != nil { - t.Error("no duplicates in the first set") - } + require.NoError(t, detectDuplicates(plugs), "no duplicates in the first set") plugs = append(plugs, mockSubprocessCLIPlugin(t, "foo")) - if err := detectDuplicates(plugs); err == nil { - t.Error("duplicates in the second set") - } + assert.Error(t, detectDuplicates(plugs), "duplicates in the second set") } func TestLoadAllDir_Empty(t *testing.T) { diff --git a/internal/plugin/metadata_test.go b/internal/plugin/metadata_test.go index b4994cf68..9cfdbc83a 100644 --- a/internal/plugin/metadata_test.go +++ b/internal/plugin/metadata_test.go @@ -66,7 +66,7 @@ func TestValidatePluginData(t *testing.T) { t.Run(strconv.Itoa(i), func(t *testing.T) { err := item.plug.Metadata().Validate() if item.pass { - require.NoError(t, err, "failed to validate case %d: %s", i, err) + require.NoError(t, err, "failed to validate case %d", i) } else { require.Error(t, err, "expected case %d to fail", i) assert.ErrorContains(t, err, item.errString, "expected case %d error to contain %q", i, item.errString) @@ -97,8 +97,7 @@ func TestMetadataValidateVersion(t *testing.T) { t.Run(name, func(t *testing.T) { m := mockSubprocessCLIPlugin(t, "testplugin") m.metadata.Version = tc.version - err := m.Metadata().Validate() - assert.NoError(t, err) + assert.NoError(t, m.Metadata().Validate()) }) } @@ -106,8 +105,7 @@ func TestMetadataValidateVersion(t *testing.T) { t.Run(name, func(t *testing.T) { m := mockSubprocessCLIPlugin(t, "testplugin") m.metadata.Version = tc.version - err := m.Metadata().Validate() - assert.ErrorContains(t, err, "invalid plugin version") + assert.ErrorContains(t, m.Metadata().Validate(), "invalid plugin version") }) } } @@ -139,7 +137,7 @@ func TestMetadataValidateMultipleErrors(t *testing.T) { } for _, expectedErr := range expectedErrors { - assert.Contains(t, errStr, expectedErr, "expected error to contain %q, but got: %v", expectedErr, errStr) + require.ErrorContains(t, err, expectedErr) } // Verify that the error contains the correct number of error messages diff --git a/internal/plugin/metadata_v1_test.go b/internal/plugin/metadata_v1_test.go index 74c67178e..8a6f28705 100644 --- a/internal/plugin/metadata_v1_test.go +++ b/internal/plugin/metadata_v1_test.go @@ -77,8 +77,7 @@ func TestMetadataV1ValidateVersion(t *testing.T) { t.Run("invalid/"+name, func(t *testing.T) { m := base() m.Version = tc.version - err := m.Validate() - assert.ErrorContains(t, err, tc.errMsg) + assert.ErrorContains(t, m.Validate(), tc.errMsg) }) } } diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 789e583ae..ad2dd7922 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package plugin // import "helm.sh/helm/v4/internal/plugin" +package plugin import ( "context" diff --git a/internal/plugin/plugin_test.go b/internal/plugin/plugin_test.go index 2e3f274f2..947792046 100644 --- a/internal/plugin/plugin_test.go +++ b/internal/plugin/plugin_test.go @@ -18,6 +18,8 @@ package plugin import ( "testing" + "github.com/stretchr/testify/assert" + "helm.sh/helm/v4/internal/plugin/schema" ) @@ -34,9 +36,7 @@ func TestValidPluginName(t *testing.T) { for name, pluginName := range validNames { t.Run("valid/"+name, func(t *testing.T) { - if !validPluginName.MatchString(pluginName) { - t.Errorf("expected %q to match validPluginName regex", pluginName) - } + assert.Truef(t, validPluginName.MatchString(pluginName), "expected %q to match validPluginName regex", pluginName) }) } @@ -52,9 +52,7 @@ func TestValidPluginName(t *testing.T) { for name, pluginName := range invalidNames { t.Run("invalid/"+name, func(t *testing.T) { - if validPluginName.MatchString(pluginName) { - t.Errorf("expected %q to not match validPluginName regex", pluginName) - } + assert.Falsef(t, validPluginName.MatchString(pluginName), "expected %q to not match validPluginName regex", pluginName) }) } } diff --git a/internal/plugin/runtime_extismv1_test.go b/internal/plugin/runtime_extismv1_test.go index 290d418ea..72a24d111 100644 --- a/internal/plugin/runtime_extismv1_test.go +++ b/internal/plugin/runtime_extismv1_test.go @@ -59,8 +59,7 @@ func buildLoadExtismPlugin(t *testing.T, dir string) pluginRaw { func TestRuntimeConfigExtismV1Validate(t *testing.T) { rc := RuntimeConfigExtismV1{} - err := rc.Validate() - assert.NoError(t, err, "expected no error for empty RuntimeConfigExtismV1") + assert.NoError(t, rc.Validate(), "expected no error for empty RuntimeConfigExtismV1") } func TestRuntimeExtismV1InvokePlugin(t *testing.T) { diff --git a/internal/plugin/runtime_subprocess.go b/internal/plugin/runtime_subprocess.go index b921587c1..2dbe220d9 100644 --- a/internal/plugin/runtime_subprocess.go +++ b/internal/plugin/runtime_subprocess.go @@ -18,6 +18,7 @@ package plugin import ( "bytes" "context" + "errors" "fmt" "io" "log/slog" @@ -152,7 +153,8 @@ func (r *SubprocessPluginRuntime) InvokeHook(event string) error { slog.Debug("executing plugin hook command", slog.String("pluginName", r.metadata.Name), slog.String("command", cmd.String())) if err := cmd.Run(); err != nil { - if eerr, ok := err.(*exec.ExitError); ok { + var eerr *exec.ExitError + if errors.As(err, &eerr) { os.Stderr.Write(eerr.Stderr) return fmt.Errorf("plugin %s hook for %q exited with error", event, r.metadata.Name) } @@ -166,7 +168,8 @@ func (r *SubprocessPluginRuntime) InvokeHook(event string) error { // then replace the other three with a call to this func func executeCmd(prog *exec.Cmd, pluginName string) error { if err := prog.Run(); err != nil { - if eerr, ok := err.(*exec.ExitError); ok { + var eerr *exec.ExitError + if errors.As(err, &eerr) { slog.Debug( "plugin execution failed", slog.String("pluginName", pluginName), diff --git a/internal/plugin/runtime_subprocess_hooks.go b/internal/plugin/runtime_subprocess_hooks.go index 7b4ff5a38..8d5f3cba6 100644 --- a/internal/plugin/runtime_subprocess_hooks.go +++ b/internal/plugin/runtime_subprocess_hooks.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package plugin // import "helm.sh/helm/v4/internal/plugin" +package plugin // Types of hooks const ( diff --git a/internal/plugin/runtime_subprocess_test.go b/internal/plugin/runtime_subprocess_test.go index c651dd3f7..c04127e0d 100644 --- a/internal/plugin/runtime_subprocess_test.go +++ b/internal/plugin/runtime_subprocess_test.go @@ -16,7 +16,6 @@ limitations under the License. package plugin import ( - "errors" "fmt" "os" "path/filepath" @@ -78,8 +77,7 @@ func TestSubprocessPluginRuntime(t *testing.T) { require.Error(t, err) ieerr := &InvokeExecError{} - ok := errors.As(err, &ieerr) - require.True(t, ok, "expected InvokeExecError, got %T", err) + require.ErrorAs(t, err, &ieerr, "expected InvokeExecError") assert.Equal(t, 56, ieerr.ExitCode) assert.Nil(t, output) diff --git a/internal/plugin/subprocess_commands_test.go b/internal/plugin/subprocess_commands_test.go index 6aa0a7435..7505bf343 100644 --- a/internal/plugin/subprocess_commands_test.go +++ b/internal/plugin/subprocess_commands_test.go @@ -16,7 +16,6 @@ limitations under the License. package plugin import ( - "reflect" "runtime" "testing" @@ -39,9 +38,7 @@ func TestPrepareCommand(t *testing.T) { cmd, args, err := PrepareCommands(platformCommand, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandExtraArgs(t *testing.T) { @@ -113,9 +110,7 @@ func TestPrepareCommands(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsExtraArgs(t *testing.T) { @@ -136,9 +131,7 @@ func TestPrepareCommandsExtraArgs(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, extraArgs, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, expectedArgs) { - t.Fatalf("Expected %v, got %v", expectedArgs, args) - } + require.Equalf(t, expectedArgs, args, "Expected %v, got %v", expectedArgs, args) } func TestPrepareCommandsNoArch(t *testing.T) { @@ -155,9 +148,7 @@ func TestPrepareCommandsNoArch(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsNoOsNoArch(t *testing.T) { @@ -174,9 +165,7 @@ func TestPrepareCommandsNoOsNoArch(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } func TestPrepareCommandsNoMatch(t *testing.T) { @@ -216,9 +205,7 @@ func TestPrepareCommandsExpand(t *testing.T) { cmd, args, err := PrepareCommands(cmds, true, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, expectedArgs) { - t.Fatalf("Expected %v, got %v", expectedArgs, args) - } + require.Equalf(t, expectedArgs, args, "Expected %v, got %v", expectedArgs, args) } func TestPrepareCommandsNoExpand(t *testing.T) { @@ -235,7 +222,5 @@ func TestPrepareCommandsNoExpand(t *testing.T) { cmd, args, err := PrepareCommands(cmds, false, []string{}, env) require.NoError(t, err) require.Equal(t, cmdMain, cmd, "Expected %q, got %q", cmdMain, cmd) - if !reflect.DeepEqual(args, cmdArgs) { - t.Fatalf("Expected %v, got %v", cmdArgs, args) - } + require.Equalf(t, args, cmdArgs, "Expected %v, got %v", cmdArgs, args) } diff --git a/internal/plugin/verify_test.go b/internal/plugin/verify_test.go index 5721e0414..4f5b26a97 100644 --- a/internal/plugin/verify_test.go +++ b/internal/plugin/verify_test.go @@ -44,11 +44,9 @@ func TestVerifyPlugin(t *testing.T) { // Create plugin directory pluginDir := filepath.Join(tempDir, "verify-test-plugin") - err := os.MkdirAll(pluginDir, 0o755) - require.NoError(t, err) + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) - err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) // Create tarball tarballPath := filepath.Join(tempDir, "verify-test-plugin.tar.gz") @@ -64,10 +62,9 @@ func TestVerifyPlugin(t *testing.T) { // Sign the plugin with source directory signer, err := provenance.NewFromKeyring(testKeyFile, "helm-test") require.NoError(t, err) - err = signer.DecryptKey(func(_ string) ([]byte, error) { + require.NoError(t, signer.DecryptKey(func(_ string) ([]byte, error) { return []byte(""), nil - }) - require.NoError(t, err) + })) // Read the tarball data tarballData, err := os.ReadFile(tarballPath) @@ -78,8 +75,7 @@ func TestVerifyPlugin(t *testing.T) { // Write the signature to .prov file provFile := tarballPath + ".prov" - err = os.WriteFile(provFile, []byte(sig), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(provFile, []byte(sig), 0o644)) // Read the files for verification archiveData, err := os.ReadFile(tarballPath) @@ -105,11 +101,9 @@ func TestVerifyPluginBadSignature(t *testing.T) { // Create a plugin tarball pluginDir := filepath.Join(tempDir, "bad-plugin") - err := os.MkdirAll(pluginDir, 0o755) - require.NoError(t, err) + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) - err = os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) tarballPath := filepath.Join(tempDir, "bad-plugin.tar.gz") tarFile, err := os.Create(tarballPath) @@ -133,8 +127,7 @@ InvalidSignatureData -----END PGP SIGNATURE-----` provFile := tarballPath + ".prov" - err = os.WriteFile(provFile, []byte(badSig), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(provFile, []byte(badSig), 0o644)) // Read the files archiveData, err := os.ReadFile(tarballPath) @@ -153,8 +146,7 @@ func TestVerifyPluginMissingProvenance(t *testing.T) { tarballPath := filepath.Join(tempDir, "no-prov.tar.gz") // Create a minimal tarball - err := os.WriteFile(tarballPath, []byte("dummy"), 0o644) - require.NoError(t, err) + require.NoError(t, os.WriteFile(tarballPath, []byte("dummy"), 0o644)) // Read the tarball data archiveData, err := os.ReadFile(tarballPath) diff --git a/internal/release/v2/hook_test.go b/internal/release/v2/hook_test.go index 5a0867398..3e946825e 100644 --- a/internal/release/v2/hook_test.go +++ b/internal/release/v2/hook_test.go @@ -170,12 +170,12 @@ func TestHookExecutionUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &exec) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.StartedAt.Unix(), exec.StartedAt.Unix()) + assert.Equal(t, tt.expected.CompletedAt.Unix(), exec.CompletedAt.Unix()) + assert.Equal(t, tt.expected.Phase, exec.Phase) } - require.NoError(t, err) - assert.Equal(t, tt.expected.StartedAt.Unix(), exec.StartedAt.Unix()) - assert.Equal(t, tt.expected.CompletedAt.Unix(), exec.CompletedAt.Unix()) - assert.Equal(t, tt.expected.Phase, exec.Phase) }) } } @@ -194,8 +194,7 @@ func TestHookExecutionRoundTrip(t *testing.T) { require.NoError(t, err) var decoded HookExecution - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.StartedAt.Unix(), decoded.StartedAt.Unix()) assert.Equal(t, original.CompletedAt.Unix(), decoded.CompletedAt.Unix()) @@ -208,12 +207,11 @@ func TestHookExecutionEmptyStringRoundTrip(t *testing.T) { input := `{"started_at":"","completed_at":"","phase":"Succeeded"}` var exec HookExecution - err := json.Unmarshal([]byte(input), &exec) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &exec)) // Verify time fields are zero values - assert.True(t, exec.StartedAt.IsZero()) - assert.True(t, exec.CompletedAt.IsZero()) + assert.Zero(t, exec.StartedAt) + assert.Zero(t, exec.CompletedAt) assert.Equal(t, HookPhaseSucceeded, exec.Phase) // Marshal back and verify empty time fields are omitted @@ -221,8 +219,7 @@ func TestHookExecutionEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time values should be omitted assert.NotContains(t, result, "started_at") diff --git a/internal/release/v2/info_test.go b/internal/release/v2/info_test.go index 5812c6560..571daa025 100644 --- a/internal/release/v2/info_test.go +++ b/internal/release/v2/info_test.go @@ -253,17 +253,17 @@ func TestInfoUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &info) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.FirstDeployed.Unix(), info.FirstDeployed.Unix()) + assert.Equal(t, tt.expected.LastDeployed.Unix(), info.LastDeployed.Unix()) + assert.Equal(t, tt.expected.Deleted.Unix(), info.Deleted.Unix()) + assert.Equal(t, tt.expected.Description, info.Description) + assert.Equal(t, tt.expected.Status, info.Status) + assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) + assert.Equal(t, tt.expected.Notes, info.Notes) + assert.Equal(t, tt.expected.Resources, info.Resources) } - require.NoError(t, err) - assert.Equal(t, tt.expected.FirstDeployed.Unix(), info.FirstDeployed.Unix()) - assert.Equal(t, tt.expected.LastDeployed.Unix(), info.LastDeployed.Unix()) - assert.Equal(t, tt.expected.Deleted.Unix(), info.Deleted.Unix()) - assert.Equal(t, tt.expected.Description, info.Description) - assert.Equal(t, tt.expected.Status, info.Status) - assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) - assert.Equal(t, tt.expected.Notes, info.Notes) - assert.Equal(t, tt.expected.Resources, info.Resources) }) } } @@ -284,9 +284,7 @@ func TestInfoRoundTrip(t *testing.T) { require.NoError(t, err) var decoded Info - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.FirstDeployed.Unix(), decoded.FirstDeployed.Unix()) assert.Equal(t, original.LastDeployed.Unix(), decoded.LastDeployed.Unix()) assert.Equal(t, original.Deleted.Unix(), decoded.Deleted.Unix()) @@ -330,8 +328,7 @@ func TestInfoRollbackRevisionRoundTrip(t *testing.T) { require.NoError(t, err) var decoded Info - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, tt.info.RollbackRevision, decoded.RollbackRevision) assert.Equal(t, tt.info.FirstDeployed.Unix(), decoded.FirstDeployed.Unix()) @@ -342,8 +339,7 @@ func TestInfoRollbackRevisionRoundTrip(t *testing.T) { // Verify omitempty behavior: zero rollback_revision should not appear in JSON if tt.info.RollbackRevision == 0 { var raw map[string]any - err = json.Unmarshal(data, &raw) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &raw)) assert.NotContains(t, raw, "rollback_revision") } }) @@ -356,13 +352,12 @@ func TestInfoEmptyStringRoundTrip(t *testing.T) { input := `{"first_deployed":"","last_deployed":"","deleted":"","status":"deployed","description":"test"}` var info Info - err := json.Unmarshal([]byte(input), &info) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &info)) // Verify time fields are zero values - assert.True(t, info.FirstDeployed.IsZero()) - assert.True(t, info.LastDeployed.IsZero()) - assert.True(t, info.Deleted.IsZero()) + assert.Zero(t, info.FirstDeployed) + assert.Zero(t, info.LastDeployed) + assert.Zero(t, info.Deleted) assert.Equal(t, common.StatusDeployed, info.Status) assert.Equal(t, "test", info.Description) @@ -371,8 +366,7 @@ func TestInfoEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time values should be omitted due to omitzero tag assert.NotContains(t, result, "first_deployed") diff --git a/internal/release/v2/util/filter.go b/internal/release/v2/util/filter.go index bc568cbdc..0daf06014 100644 --- a/internal/release/v2/util/filter.go +++ b/internal/release/v2/util/filter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( v2 "helm.sh/helm/v4/internal/release/v2" diff --git a/internal/release/v2/util/filter_test.go b/internal/release/v2/util/filter_test.go index 8c7363b87..542510ba3 100644 --- a/internal/release/v2/util/filter_test.go +++ b/internal/release/v2/util/filter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "testing" diff --git a/internal/release/v2/util/kind_sorter.go b/internal/release/v2/util/kind_sorter.go index dba35b6d2..950e836fa 100644 --- a/internal/release/v2/util/kind_sorter.go +++ b/internal/release/v2/util/kind_sorter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "sort" diff --git a/internal/release/v2/util/kind_sorter_test.go b/internal/release/v2/util/kind_sorter_test.go index dba19e287..06885aa93 100644 --- a/internal/release/v2/util/kind_sorter_test.go +++ b/internal/release/v2/util/kind_sorter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "bytes" diff --git a/internal/release/v2/util/manifest.go b/internal/release/v2/util/manifest.go index d3296984e..37b9dfbd3 100644 --- a/internal/release/v2/util/manifest.go +++ b/internal/release/v2/util/manifest.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "fmt" diff --git a/internal/release/v2/util/manifest_sorter.go b/internal/release/v2/util/manifest_sorter.go index f269dda6d..3507deed5 100644 --- a/internal/release/v2/util/manifest_sorter.go +++ b/internal/release/v2/util/manifest_sorter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "fmt" diff --git a/internal/release/v2/util/manifest_sorter_test.go b/internal/release/v2/util/manifest_sorter_test.go index eac9c9f36..6cf529bff 100644 --- a/internal/release/v2/util/manifest_sorter_test.go +++ b/internal/release/v2/util/manifest_sorter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "testing" @@ -143,7 +143,6 @@ metadata: // This test will fail if 'six' or 'seven' was added. assert.Len(t, generic, 2) - assert.Len(t, hs, 4) for _, out := range hs { diff --git a/internal/release/v2/util/manifest_test.go b/internal/release/v2/util/manifest_test.go index 1806368af..e76905a63 100644 --- a/internal/release/v2/util/manifest_test.go +++ b/internal/release/v2/util/manifest_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "testing" diff --git a/internal/release/v2/util/sorter.go b/internal/release/v2/util/sorter.go index 5f13569c1..66b51d873 100644 --- a/internal/release/v2/util/sorter.go +++ b/internal/release/v2/util/sorter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "sort" diff --git a/internal/release/v2/util/sorter_test.go b/internal/release/v2/util/sorter_test.go index 82a53ae66..e151f0790 100644 --- a/internal/release/v2/util/sorter_test.go +++ b/internal/release/v2/util/sorter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/internal/release/v2/util" +package util import ( "testing" diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index 547419e17..db976a45b 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -148,28 +148,22 @@ func TestResolve(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { l, err := r.Resolve(tt.req, repoNames) - if err != nil { - if tt.err { - return - } + if tt.err { + require.Error(t, err) + } else { require.NoError(t, err) - } + h, err := HashReq(tt.req, tt.expect.Dependencies) + require.NoError(t, err) + assert.Equal(t, l.Digest, h, "%q: hashes don't match.", tt.name) - if tt.err { - require.Failf(t, "Expected error in test %q", tt.name) + // Check fields. + require.Len(t, l.Dependencies, len(tt.req), "%s: wrong number of dependencies in lock", tt.name) + d0 := l.Dependencies[0] + e0 := tt.expect.Dependencies[0] + assert.Equal(t, e0.Name, d0.Name, tt.name) + assert.Equal(t, e0.Repository, d0.Repository, tt.name) + assert.Equal(t, e0.Version, d0.Version, tt.name) } - - h, err := HashReq(tt.req, tt.expect.Dependencies) - require.NoError(t, err) - assert.Equal(t, l.Digest, h, "%q: hashes don't match.", tt.name) - - // Check fields. - assert.Len(t, l.Dependencies, len(tt.req), "%s: wrong number of dependencies in lock", tt.name) - d0 := l.Dependencies[0] - e0 := tt.expect.Dependencies[0] - assert.Equal(t, e0.Name, d0.Name, tt.name) - assert.Equal(t, e0.Repository, d0.Repository, tt.name) - assert.Equal(t, e0.Version, d0.Version, tt.name) }) } } @@ -280,20 +274,16 @@ func TestGetLocalPath(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { p, err := GetLocalPath(tt.repo, tt.chartpath) - if err != nil { - if tt.err { - return - } - require.NoError(t, err) - } if tt.err { - require.Failf(t, "Expected error in test %q", tt.name) - } - expect := tt.expect - if runtime.GOOS == "windows" { - expect = tt.winExpect + require.Error(t, err) + } else { + require.NoError(t, err) + if runtime.GOOS == "windows" { + assert.Equal(t, tt.winExpect, p, tt.name) + } else { + assert.Equal(t, tt.expect, p, tt.name) + } } - assert.Equal(t, expect, p, tt.name) }) } } diff --git a/internal/sympath/walk.go b/internal/sympath/walk.go index 812bb68ce..b54b97ad4 100644 --- a/internal/sympath/walk.go +++ b/internal/sympath/walk.go @@ -21,6 +21,7 @@ limitations under the License. package sympath import ( + "errors" "fmt" "log/slog" "os" @@ -40,7 +41,7 @@ func Walk(root string, walkFn filepath.WalkFunc) error { } else { err = symwalk(root, info, walkFn) } - if err == filepath.SkipDir { + if errors.Is(err, filepath.SkipDir) { return nil } return err @@ -75,7 +76,7 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { if info, err = os.Lstat(resolved); err != nil { return err } - if err := symwalk(path, info, walkFn); err != nil && err != filepath.SkipDir { + if err := symwalk(path, info, walkFn); err != nil && !errors.Is(err, filepath.SkipDir) { return err } return nil @@ -98,13 +99,13 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { filename := filepath.Join(path, name) fileInfo, err := os.Lstat(filename) if err != nil { - if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { + if err := walkFn(filename, fileInfo, err); err != nil && !errors.Is(err, filepath.SkipDir) { return err } } else { err = symwalk(filename, fileInfo, walkFn) if err != nil { - if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir { + if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || !errors.Is(err, filepath.SkipDir) { return err } } diff --git a/internal/sympath/walk_test.go b/internal/sympath/walk_test.go index 76ed39cac..5dd051e4d 100644 --- a/internal/sympath/walk_test.go +++ b/internal/sympath/walk_test.go @@ -132,8 +132,7 @@ func TestWalk(t *testing.T) { return mark(info, err, &errors, true) } // Expect no errors. - err := Walk(tree.name, markFn) - require.NoError(t, err) + require.NoError(t, Walk(tree.name, markFn)) require.Empty(t, errors, "unexpected errors") checkMarks(t, true) diff --git a/internal/third_party/dep/fs/fs_test.go b/internal/third_party/dep/fs/fs_test.go index 797890f9f..d777b6af4 100644 --- a/internal/third_party/dep/fs/fs_test.go +++ b/internal/third_party/dep/fs/fs_test.go @@ -32,54 +32,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package fs import ( - "errors" "os" "path/filepath" "runtime" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestRenameWithFallback(t *testing.T) { dir := t.TempDir() - if err := RenameWithFallback(filepath.Join(dir, "does_not_exists"), filepath.Join(dir, "dst")); err == nil { - t.Fatal("expected an error for non existing file, but got nil") - } + require.Error(t, RenameWithFallback(filepath.Join(dir, "does_not_exists"), filepath.Join(dir, "dst")), "expected an error for non existing file, but got nil") srcpath := filepath.Join(dir, "src") - if srcf, err := os.Create(srcpath); err != nil { - t.Fatal(err) - } else { - srcf.Close() - } + srcf, err := os.Create(srcpath) + require.NoError(t, err) + srcf.Close() - if err := RenameWithFallback(srcpath, filepath.Join(dir, "dst")); err != nil { - t.Fatal(err) - } + require.NoError(t, RenameWithFallback(srcpath, filepath.Join(dir, "dst"))) srcpath = filepath.Join(dir, "a") - if err := os.MkdirAll(srcpath, 0o777); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcpath, 0o777)) dstpath := filepath.Join(dir, "b") - if err := os.MkdirAll(dstpath, 0o777); err != nil { - t.Fatal(err) - } - - if err := RenameWithFallback(srcpath, dstpath); err == nil { - t.Fatal("expected an error if dst is an existing directory, but got nil") - } + require.NoError(t, os.MkdirAll(dstpath, 0o777)) + require.Error(t, RenameWithFallback(srcpath, dstpath), "expected an error if dst is an existing directory, but got nil") } func TestCopyDir(t *testing.T) { dir := t.TempDir() srcdir := filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcdir, 0o755)) files := []struct { path string @@ -94,61 +81,40 @@ func TestCopyDir(t *testing.T) { for i, file := range files { fn := filepath.Join(srcdir, file.path) dn := filepath.Dir(fn) - if err := os.MkdirAll(dn, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(dn, 0o755)) fh, err := os.Create(fn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err = fh.WriteString(file.contents); err != nil { - t.Fatal(err) - } + _, err = fh.WriteString(file.contents) + require.NoError(t, err) fh.Close() files[i].fi, err = os.Stat(fn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } destdir := filepath.Join(dir, "dest") - if err := CopyDir(srcdir, destdir); err != nil { - t.Fatal(err) - } + require.NoError(t, CopyDir(srcdir, destdir)) // Compare copy against structure indicated in 'files' for _, file := range files { fn := filepath.Join(srcdir, file.path) dn := filepath.Dir(fn) dirOK, err := IsDir(dn) - if err != nil { - t.Fatal(err) - } - if !dirOK { - t.Fatalf("expected %s to be a directory", dn) - } + require.NoError(t, err) + require.Truef(t, dirOK, "expected %s to be a directory", dn) got, err := os.ReadFile(fn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if file.contents != string(got) { - t.Fatalf("expected: %s, got: %s", file.contents, string(got)) - } + require.Equalf(t, file.contents, string(got), "expected: %s, got: %s", file.contents, string(got)) gotinfo, err := os.Stat(fn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if file.fi.Mode() != gotinfo.Mode() { - t.Fatalf("expected %s: %#v\n to be the same mode as %s: %#v", - file.path, file.fi.Mode(), fn, gotinfo.Mode()) - } + require.Equalf(t, file.fi.Mode(), gotinfo.Mode(), "expected %s: %#v\n to be the same mode as %s: %#v", + file.path, file.fi.Mode(), fn, gotinfo.Mode()) } } @@ -178,9 +144,7 @@ func TestCopyDirFail_SrcInaccessible(t *testing.T) { dir := t.TempDir() dstdir = filepath.Join(dir, "dst") - if err := CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } + assert.Errorf(t, CopyDir(srcdir, dstdir), "expected error for CopyDir(%s, %s), got none", srcdir, dstdir) } func TestCopyDirFail_DstInaccessible(t *testing.T) { @@ -203,9 +167,7 @@ func TestCopyDirFail_DstInaccessible(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcdir, 0o755)) cleanup := setupInaccessibleDir(t, func(dir string) error { dstdir = filepath.Join(dir, "dst") @@ -213,9 +175,7 @@ func TestCopyDirFail_DstInaccessible(t *testing.T) { }) defer cleanup() - if err := CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } + assert.Errorf(t, CopyDir(srcdir, dstdir), "expected error for CopyDir(%s, %s), got none", srcdir, dstdir) } func TestCopyDirFail_SrcIsNotDir(t *testing.T) { @@ -225,44 +185,25 @@ func TestCopyDirFail_SrcIsNotDir(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if _, err = os.Create(srcdir); err != nil { - t.Fatal(err) - } + _, err = os.Create(srcdir) + require.NoError(t, err) dstdir = filepath.Join(dir, "dst") - if err = CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } - - if !errors.Is(err, errSrcNotDir) { - t.Fatalf("expected %v error for CopyDir(%s, %s), got %s", errSrcNotDir, srcdir, dstdir, err) - } + require.ErrorIsf(t, CopyDir(srcdir, dstdir), errSrcNotDir, "expected %v error for CopyDir(%s, %s)", errSrcNotDir, srcdir, dstdir) } func TestCopyDirFail_DstExists(t *testing.T) { var srcdir, dstdir string - var err error dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err = os.MkdirAll(srcdir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcdir, 0o755)) dstdir = filepath.Join(dir, "dst") - if err = os.MkdirAll(dstdir, 0o755); err != nil { - t.Fatal(err) - } - - if err = CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } - - if !errors.Is(err, errDstExist) { - t.Fatalf("expected %v error for CopyDir(%s, %s), got %s", errDstExist, srcdir, dstdir, err) - } + require.NoError(t, os.MkdirAll(dstdir, 0o755)) + require.ErrorIs(t, CopyDir(srcdir, dstdir), errDstExist, "expected %v error for CopyDir(%s, %s)", errDstExist, srcdir, dstdir) } func TestCopyDirFailOpen(t *testing.T) { @@ -288,70 +229,46 @@ func TestCopyDirFailOpen(t *testing.T) { dir := t.TempDir() srcdir = filepath.Join(dir, "src") - if err := os.MkdirAll(srcdir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(srcdir, 0o755)) srcfn := filepath.Join(srcdir, "file") srcf, err := os.Create(srcfn) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) srcf.Close() // setup source file so that it cannot be read - if err = os.Chmod(srcfn, 0o222); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Chmod(srcfn, 0o222)) dstdir = filepath.Join(dir, "dst") - - if err = CopyDir(srcdir, dstdir); err == nil { - t.Fatalf("expected error for CopyDir(%s, %s), got none", srcdir, dstdir) - } + assert.Errorf(t, CopyDir(srcdir, dstdir), "expected error for CopyDir(%s, %s), got none", srcdir, dstdir) } func TestCopyFile(t *testing.T) { dir := t.TempDir() srcf, err := os.Create(filepath.Join(dir, "srcfile")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) want := "hello world" - if _, err := srcf.WriteString(want); err != nil { - t.Fatal(err) - } + _, err = srcf.WriteString(want) + require.NoError(t, err) srcf.Close() destf := filepath.Join(dir, "destf") - if err := CopyFile(srcf.Name(), destf); err != nil { - t.Fatal(err) - } + require.NoError(t, CopyFile(srcf.Name(), destf)) got, err := os.ReadFile(destf) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if want != string(got) { - t.Fatalf("expected: %s, got: %s", want, string(got)) - } + require.Equalf(t, want, string(got), "expected: %s, got: %s", want, string(got)) wantinfo, err := os.Stat(srcf.Name()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) gotinfo, err := os.Stat(destf) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if wantinfo.Mode() != gotinfo.Mode() { - t.Fatalf("expected %s: %#v\n to be the same mode as %s: %#v", srcf.Name(), wantinfo.Mode(), destf, gotinfo.Mode()) - } + assert.Equalf(t, wantinfo.Mode(), gotinfo.Mode(), "expected %s: %#v\n to be the same mode as %s: %#v", srcf.Name(), wantinfo.Mode(), destf, gotinfo.Mode()) } func TestCopyFileSymlink(t *testing.T) { @@ -366,9 +283,7 @@ func TestCopyFileSymlink(t *testing.T) { for symlink, dst := range testcases { t.Run(symlink, func(t *testing.T) { var err error - if err = CopyFile(symlink, dst); err != nil { - t.Fatalf("failed to copy symlink: %s", err) - } + require.NoErrorf(t, CopyFile(symlink, dst), "failed to copy symlink") var want, got string @@ -377,31 +292,21 @@ func TestCopyFileSymlink(t *testing.T) { // regular users aren't granted usually. So we copy the file // content as a fall back instead of creating a real symlink. srcb, err := os.ReadFile(symlink) - if err != nil { - t.Fatalf("%+v", err) - } + require.NoError(t, err) dstb, err := os.ReadFile(dst) - if err != nil { - t.Fatalf("%+v", err) - } + require.NoError(t, err) want = string(srcb) got = string(dstb) } else { want, err = os.Readlink(symlink) - if err != nil { - t.Fatalf("%+v", err) - } + require.NoError(t, err) got, err = os.Readlink(dst) - if err != nil { - t.Fatalf("could not resolve symlink: %s", err) - } + require.NoErrorf(t, err, "could not resolve symlink") } - if want != got { - t.Fatalf("resolved path is incorrect. expected %s, got %s", want, got) - } + require.Equalf(t, want, got, "resolved path is incorrect. expected %s, got %s", want, got) }) } } @@ -424,9 +329,7 @@ func TestCopyFileFail(t *testing.T) { dir := t.TempDir() srcf, err := os.Create(filepath.Join(dir, "srcfile")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) srcf.Close() var dstdir string @@ -438,9 +341,7 @@ func TestCopyFileFail(t *testing.T) { defer cleanup() fn := filepath.Join(dstdir, "file") - if err := CopyFile(srcf.Name(), fn); err == nil { - t.Fatalf("expected error for %s, got none", fn) - } + require.Errorf(t, CopyFile(srcf.Name(), fn), "expected error for %s, got none", fn) } // setupInaccessibleDir creates a temporary location with a single @@ -463,9 +364,7 @@ func setupInaccessibleDir(t *testing.T, op func(dir string) error) func() { subdir := filepath.Join(dir, "dir") cleanup := func() { - if err := os.Chmod(subdir, 0o777); err != nil { - t.Error(err) - } + assert.NoError(t, os.Chmod(subdir, 0o777)) } if err := os.Mkdir(subdir, 0o777); err != nil { @@ -498,9 +397,7 @@ func TestIsDir(t *testing.T) { } wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var dn string @@ -530,14 +427,16 @@ func TestIsDir(t *testing.T) { } for f, want := range tests { - got, err := IsDir(f) - if err != nil && !want.err { - t.Fatalf("expected no error, got %v", err) - } + t.Run(f, func(t *testing.T) { + got, err := IsDir(f) - if got != want.exists { - t.Fatalf("expected %t for %s, got %t", want.exists, f, got) - } + if want.err { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.Equalf(t, want.exists, got, "expected %t for %s, got %t", want.exists, f, got) + }) } } @@ -552,26 +451,18 @@ func TestIsSymlink(t *testing.T) { dir := t.TempDir() dirPath := filepath.Join(dir, "directory") - if err := os.MkdirAll(dirPath, 0o777); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(dirPath, 0o777)) filePath := filepath.Join(dir, "file") f, err := os.Create(filePath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) f.Close() dirSymlink := filepath.Join(dir, "dirSymlink") fileSymlink := filepath.Join(dir, "fileSymlink") - if err = os.Symlink(dirPath, dirSymlink); err != nil { - t.Fatal(err) - } - if err = os.Symlink(filePath, fileSymlink); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Symlink(dirPath, dirSymlink)) + require.NoError(t, os.Symlink(filePath, fileSymlink)) var ( inaccessibleFile string @@ -609,14 +500,11 @@ func TestIsSymlink(t *testing.T) { for path, want := range tests { got, err := IsSymlink(path) - if err != nil { - if !want.err { - t.Errorf("expected no error, got %v", err) - } - } - - if got != want.expected { - t.Errorf("expected %t for %s, got %t", want.expected, path, got) + if want.err { + require.Error(t, err, "expected an error") + } else { + require.NoError(t, err, "expected no error") } + assert.Equalf(t, want.expected, got, "expected %t for %s, got %t", want.expected, path, got) } } diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index 880a9930b..056c539a5 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -58,9 +58,7 @@ func actionConfigFixtureWithDummyResources(t *testing.T, dummyResources kube.Res slog.SetDefault(logger) registryClient, err := registry.NewClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return &Configuration{ Releases: storage.Init(driver.NewMemory()), @@ -371,16 +369,10 @@ func TestGetVersionSet(t *testing.T) { client := fakeclientset.NewClientset() vs, err := GetVersionSet(client.Discovery()) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if !vs.Has("v1") { - t.Error("Expected supported versions to at least include v1.") - } - if vs.Has("nosuchversion/v1") { - t.Error("Non-existent version is reported found.") - } + assert.True(t, vs.Has("v1"), "Expected supported versions to at least include v1.") + assert.False(t, vs.Has("nosuchversion/v1"), "Non-existent version is reported found.") } // Mock PostRenderer for testing @@ -2031,9 +2023,7 @@ spec: mockPR := &mockPostRenderer{ transform: func(content string) string { count := strings.Count(content, "kind: ServiceAccount") - if count > 1 { - t.Errorf("post-renderer received %d ServiceAccount resources in a single stream, expected at most 1", count) - } + assert.LessOrEqualf(t, count, 1, "post-renderer received %d ServiceAccount resources in a single stream, expected at most 1", count) return content }, } diff --git a/pkg/action/dependency_test.go b/pkg/action/dependency_test.go index 25664b98c..adbe311d6 100644 --- a/pkg/action/dependency_test.go +++ b/pkg/action/dependency_test.go @@ -57,9 +57,7 @@ func TestList(t *testing.T) { }, } { buf := bytes.Buffer{} - if err := NewDependency().List(tcase.chart, &buf); err != nil { - t.Fatal(err) - } + require.NoError(t, NewDependency().List(tcase.chart, &buf)) test.AssertGoldenString(t, buf.String(), tcase.golden) } } @@ -71,22 +69,16 @@ func TestDependencyStatus_Dashes(t *testing.T) { dir := t.TempDir() chartpath := filepath.Join(dir, "charts") - if err := os.MkdirAll(chartpath, 0o700); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(chartpath, 0o700)) // Add some fake charts first := buildChart(withName("first-chart")) _, err := chartutil.Save(first, chartpath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) second := buildChart(withName("first-chart-second-chart")) _, err = chartutil.Save(second, chartpath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) dep := &chart.Dependency{ Name: "first-chart", @@ -95,9 +87,7 @@ func TestDependencyStatus_Dashes(t *testing.T) { // Now try to get the deps stat := NewDependency().dependencyStatus(dir, dep, first) - if stat != "ok" { - t.Errorf("Unexpected status: %q", stat) - } + assert.Equal(t, "ok", stat, "Unexpected status: %q", stat) } func TestStatArchiveForStatus(t *testing.T) { @@ -105,9 +95,7 @@ func TestStatArchiveForStatus(t *testing.T) { dir := t.TempDir() chartpath := filepath.Join(dir, "charts") - if err := os.MkdirAll(chartpath, 0o700); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(chartpath, 0o700)) // unsaved chart lilith := buildChart(withName("lilith")) diff --git a/pkg/action/get_metadata_test.go b/pkg/action/get_metadata_test.go index 37f20fb60..f8851e456 100644 --- a/pkg/action/get_metadata_test.go +++ b/pkg/action/get_metadata_test.go @@ -65,8 +65,7 @@ func TestGetMetadata_Run_BasicMetadata(t *testing.T) { Namespace: "default", } - err := cfg.Releases.Create(rel) - require.NoError(t, err) + require.NoError(t, cfg.Releases.Create(rel)) result, err := client.Run(releaseName) require.NoError(t, err) @@ -645,8 +644,7 @@ func TestGetMetadata_Labels(t *testing.T) { rel.Labels = customLabels metaGetter := NewGetMetadata(actionConfigFixture(t)) - err := metaGetter.cfg.Releases.Create(rel) - require.NoError(t, err) + require.NoError(t, metaGetter.cfg.Releases.Create(rel)) metadata, err := metaGetter.Run(rel.Name) require.NoError(t, err) diff --git a/pkg/action/history_test.go b/pkg/action/history_test.go index 31fdd4a96..51212b610 100644 --- a/pkg/action/history_test.go +++ b/pkg/action/history_test.go @@ -50,9 +50,7 @@ func TestHistoryRun(t *testing.T) { client.Max = 3 client.cfg.Releases.MaxHistory = 3 for _, rel := range []*release.Release{simpleRelease, updatedRelease} { - if err := client.cfg.Releases.Create(rel); err != nil { - t.Fatal(err, "Could not add releases to Config") - } + require.NoError(t, client.cfg.Releases.Create(rel), "Could not add releases to Config") } releases, err := config.Releases.ListReleases() diff --git a/pkg/action/hooks_test.go b/pkg/action/hooks_test.go index 20442af13..ad3a4b618 100644 --- a/pkg/action/hooks_test.go +++ b/pkg/action/hooks_test.go @@ -401,16 +401,12 @@ data: serverSideApply := true err := configuration.execHook(&tc.inputRelease, hookEvent, kube.StatusWatcherStrategy, nil, 600, serverSideApply) - if !reflect.DeepEqual(kubeClient.deleteRecord, tc.expectedDeleteRecord) { - t.Fatalf("Got unexpected delete record, expected: %#v, but got: %#v", kubeClient.deleteRecord, tc.expectedDeleteRecord) - } - - if err != nil && !tc.expectError { - t.Fatal("Got an unexpected error.") - } + require.Truef(t, reflect.DeepEqual(kubeClient.deleteRecord, tc.expectedDeleteRecord), "Got unexpected delete record, expected: %#v, but got: %#v", kubeClient.deleteRecord, tc.expectedDeleteRecord) - if err == nil && tc.expectError { - t.Fatal("Expected and error but did not get it.") + if !tc.expectError { + require.NoError(t, err) + } else { + require.Error(t, err) } }) } @@ -490,8 +486,7 @@ data: ctx := context.Background() waitOptions := []kube.WaitOption{kube.WithWaitContext(ctx)} - err := configuration.execHook(rel, release.HookPreInstall, kube.StatusWatcherStrategy, waitOptions, 600, false) - req.NoError(err) + req.NoError(configuration.execHook(rel, release.HookPreInstall, kube.StatusWatcherStrategy, waitOptions, 600, false)) // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index f79590670..4dbeb7c79 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -185,9 +185,7 @@ func TestInstallRelease(t *testing.T) { vals := map[string]any{} ctx, done := context.WithCancel(t.Context()) resi, err := instAction.RunWithContext(ctx, buildChart(), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) is.Equal("test-install-release", res.Name, "Expected release name.") @@ -238,9 +236,7 @@ func TestInstallReleaseWithTakeOwnership_ResourceNotOwned(t *testing.T) { instAction := installActionWithConfig(config) instAction.TakeOwnership = true resi, err := instAction.Run(buildChart(), nil) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -262,9 +258,7 @@ func TestInstallReleaseWithTakeOwnership_ResourceOwned(t *testing.T) { instAction := installActionWithConfig(config) instAction.TakeOwnership = false resi, err := instAction.Run(buildChart(), nil) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) r, err := instAction.cfg.Releases.Get(res.Name, res.Version) @@ -285,7 +279,7 @@ func TestInstallReleaseWithTakeOwnership_ResourceOwnedNoFlag(t *testing.T) { instAction := installActionWithConfig(config) _, err := instAction.Run(buildChart(), nil) req.Error(err) - is.Contains(err.Error(), "unable to continue with install") + is.ErrorContains(err, "unable to continue with install") } func TestInstallReleaseWithValues(t *testing.T) { @@ -303,9 +297,7 @@ func TestInstallReleaseWithValues(t *testing.T) { }, } resi, err := instAction.Run(buildChart(withSampleValues()), userVals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) is.Equal("test-install-release", res.Name, "Expected release name.") @@ -344,9 +336,7 @@ func TestInstallRelease_WithNotes(t *testing.T) { instAction.ReleaseName = "with-notes" vals := map[string]any{} resi, err := instAction.Run(buildChart(withNotes("note here")), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -376,9 +366,7 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) { instAction.ReleaseName = "with-notes" vals := map[string]any{} resi, err := instAction.Run(buildChart(withNotes("got-{{.Release.Name}}")), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -400,9 +388,7 @@ func TestInstallRelease_WithChartAndDependencyParentNotes(t *testing.T) { instAction.ReleaseName = "with-notes" vals := map[string]any{} resi, err := instAction.Run(buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -424,9 +410,7 @@ func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) { instAction.SubNotes = true vals := map[string]any{} resi, err := instAction.Run(buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -436,9 +420,7 @@ func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) { req.NoError(err) is.Equal("with-notes", rel.Name) // test run can return as either 'parent\nchild' or 'child\nparent' - if !strings.Contains(rel.Info.Notes, "parent") && !strings.Contains(rel.Info.Notes, "child") { - t.Fatalf("Expected 'parent\nchild' or 'child\nparent', got '%s'", rel.Info.Notes) - } + req.True(strings.Contains(rel.Info.Notes, "parent") || strings.Contains(rel.Info.Notes, "child"), "Expected 'parent\nchild' or 'child\nparent', got '%s'", rel.Info.Notes) is.Equal("Install complete", rel.Info.Description) } @@ -451,9 +433,7 @@ func TestInstallRelease_DryRunClient(t *testing.T) { vals := map[string]any{} resi, err := instAction.Run(buildChart(withSampleTemplates()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -466,7 +446,7 @@ func TestInstallRelease_DryRunClient(t *testing.T) { _, err = instAction.cfg.Releases.Get(res.Name, res.Version) req.Error(err) is.Len(res.Hooks, 1) - is.True(res.Hooks[0].LastRun.CompletedAt.IsZero(), "expect hook to not be marked as run") + is.Zero(res.Hooks[0].LastRun.CompletedAt, "expect hook to not be marked as run") is.Equal("Dry run complete", res.Info.Description) } } @@ -480,9 +460,7 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { instAction.DryRunStrategy = DryRunClient vals := map[string]any{} resi, err := instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) is.Contains(res.Manifest, "---\n# Source: hello/templates/secret.yaml\napiVersion: v1\nkind: Secret") @@ -495,9 +473,7 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { instAction.HideSecret = true vals = map[string]any{} res2i, err := instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res2, err := releaserToV1Release(res2i) req.NoError(err) @@ -511,9 +487,7 @@ func TestInstallRelease_DryRunHiddenSecret(t *testing.T) { instAction.DryRunStrategy = DryRunNone vals = map[string]any{} _, err = instAction.Run(buildChart(withSampleSecret(), withSampleTemplates()), vals) - if err == nil { - t.Fatal("Did not get the expected error when dry-run is false and hide secret is true") - } + req.Error(err, "Did not get the expected error when dry-run is false and hide secret is true") } // Regression test for #7955 @@ -532,9 +506,7 @@ func TestInstallRelease_DryRun_Lookup(t *testing.T) { }) resi, err := instAction.Run(mockChart, vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -543,6 +515,7 @@ func TestInstallRelease_DryRun_Lookup(t *testing.T) { func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.DryRunStrategy = DryRunNone vals := map[string]any{} @@ -550,10 +523,8 @@ func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) { expectedErr := `hello/templates/incorrect:1:10 executing "hello/templates/incorrect" at <.Values.bad.doh>: nil pointer evaluating interface {}.doh` - if err == nil { - t.Fatalf("Install should fail containing error: %s", expectedErr) - } - is.Contains(err.Error(), expectedErr) + req.Error(err, "Install should fail containing error: %s", expectedErr) + is.ErrorContains(err, expectedErr) } func TestInstallRelease_NoHooks(t *testing.T) { @@ -562,17 +533,15 @@ func TestInstallRelease_NoHooks(t *testing.T) { instAction := installAction(t) instAction.DisableHooks = true instAction.ReleaseName = "no-hooks" - require.NoError(t, instAction.cfg.Releases.Create(releaseStub())) + req.NoError(instAction.cfg.Releases.Create(releaseStub())) vals := map[string]any{} resi, err := instAction.Run(buildChart(), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) - is.True(res.Hooks[0].LastRun.CompletedAt.IsZero(), "hooks should not run with no-hooks") + is.Zero(res.Hooks[0].LastRun.CompletedAt, "hooks should not run with no-hooks") } func TestInstallRelease_FailedHooks(t *testing.T) { @@ -637,7 +606,7 @@ func TestInstallRelease_KubeVersion(t *testing.T) { vals = map[string]any{} _, err = instAction.Run(buildChart(withKube(">=99.0.0")), vals) req.Error(err) - is.Contains(err.Error(), "chart requires kubeVersion: >=99.0.0 which is incompatible with Kubernetes v1.20.") + is.ErrorContains(err, "chart requires kubeVersion: >=99.0.0 which is incompatible with Kubernetes v1.20.") } func TestInstallRelease_Wait(t *testing.T) { @@ -680,7 +649,7 @@ func TestInstallRelease_Wait_Interrupted(t *testing.T) { _, err := instAction.RunWithContext(ctx, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "context canceled") + req.ErrorContains(err, "context canceled") is.Equal(goroutines+1, instAction.getGoroutineCount()) // installation goroutine still is in background time.Sleep(10 * time.Second) // wait for goroutine to finish @@ -723,8 +692,8 @@ func TestInstallRelease_RollbackOnFailure(t *testing.T) { resi, err := instAction.Run(buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "I timed out") - is.Contains(err.Error(), "rollback-on-failure") + req.ErrorContains(err, "I timed out") + req.ErrorContains(err, "rollback-on-failure") res, err := releaserToV1Release(resi) req.NoError(err) @@ -748,9 +717,9 @@ func TestInstallRelease_RollbackOnFailure(t *testing.T) { _, err := instAction.Run(buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "I timed out") - is.Contains(err.Error(), "uninstall fail") - is.Contains(err.Error(), "an error occurred while uninstalling the release") + req.ErrorContains(err, "I timed out") + req.ErrorContains(err, "uninstall fail") + is.ErrorContains(err, "an error occurred while uninstalling the release") }) } func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { @@ -771,9 +740,9 @@ func TestInstallRelease_RollbackOnFailure_Interrupted(t *testing.T) { resi, err := instAction.RunWithContext(ctx, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "context canceled") - is.Contains(err.Error(), "rollback-on-failure") - is.Contains(err.Error(), "uninstalled") + req.ErrorContains(err, "context canceled") + req.ErrorContains(err, "rollback-on-failure") + req.ErrorContains(err, "uninstalled") res, err := releaserToV1Release(resi) req.NoError(err) @@ -820,36 +789,23 @@ func TestNameTemplate(t *testing.T) { } for _, tc := range testCases { - n, err := TemplateName(tc.tpl) - if err != nil { + t.Run(tc.tpl, func(t *testing.T) { + n, err := TemplateName(tc.tpl) if tc.expectedErrorStr == "" { - t.Errorf("Was not expecting error, but got: %v", err) - continue - } - re, compErr := regexp.Compile(tc.expectedErrorStr) - if compErr != nil { - t.Errorf("Expected error string failed to compile: %v", compErr) - continue - } - if !re.MatchString(err.Error()) { - t.Errorf("Error didn't match for %s expected %s but got %v", tc.tpl, tc.expectedErrorStr, err) - continue + require.NoError(t, err) + } else { + require.Error(t, err) + re, compErr := regexp.Compile(tc.expectedErrorStr) + require.NoError(t, compErr, "Expected error string failed to compile") + assert.True(t, re.MatchString(err.Error()), "Error didn't match for %s expected %s", tc.tpl, tc.expectedErrorStr) } - } - if err == nil && tc.expectedErrorStr != "" { - t.Errorf("Was expecting error %s but didn't get an error back", tc.expectedErrorStr) - } - if tc.expected != "" { - re, err := regexp.Compile(tc.expected) - if err != nil { - t.Errorf("Expected string failed to compile: %v", err) - continue + if tc.expected != "" { + re, err := regexp.Compile(tc.expected) + require.NoError(t, err) + assert.True(t, re.MatchString(n), "Returned name didn't match for %s expected %s but got %s", tc.tpl, tc.expected, n) } - if !re.MatchString(n) { - t.Errorf("Returned name didn't match for %s expected %s but got %s", tc.tpl, tc.expected, n) - } - } + }) } } @@ -864,9 +820,7 @@ func TestInstallReleaseOutputDir(t *testing.T) { instAction.OutputDir = dir _, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") _, err = os.Stat(filepath.Join(dir, "hello", "templates", "goodbye")) req.NoError(err) @@ -901,9 +855,7 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { newDir := filepath.Join(dir, instAction.ReleaseName) _, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") _, err = os.Stat(filepath.Join(newDir, "hello", "templates", "goodbye")) req.NoError(err) @@ -925,46 +877,37 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { func TestNameAndChart(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) chartName := "./foo" name, chrt, err := instAction.NameAndChart([]string{chartName}) - if err != nil { - t.Fatal(err) - } + req.NoError(err) is.Equal(instAction.ReleaseName, name) is.Equal(chartName, chrt) instAction.GenerateName = true _, _, err = instAction.NameAndChart([]string{"foo", chartName}) - if err == nil { - t.Fatal("expected an error") - } - is.Equal("cannot set --generate-name and also specify a name", err.Error()) + req.Error(err, "expected an error") + req.EqualError(err, "cannot set --generate-name and also specify a name") instAction.GenerateName = false instAction.NameTemplate = "{{ . }}" _, _, err = instAction.NameAndChart([]string{"foo", chartName}) - if err == nil { - t.Fatal("expected an error") - } - is.Equal("cannot set --name-template and also specify a name", err.Error()) + req.Error(err, "expected an error") + req.EqualError(err, "cannot set --name-template and also specify a name") instAction.NameTemplate = "" instAction.ReleaseName = "" _, _, err = instAction.NameAndChart([]string{chartName}) - if err == nil { - t.Fatal("expected an error") - } - is.Equal("must either provide a name or specify --generate-name", err.Error()) + req.Error(err, "expected an error") + req.EqualError(err, "must either provide a name or specify --generate-name") instAction.NameTemplate = "" instAction.ReleaseName = "" _, _, err = instAction.NameAndChart([]string{"foo", chartName, "bar"}) - if err == nil { - t.Fatal("expected an error") - } - is.Equal("expected at most two arguments, unexpected arguments: bar", err.Error()) + req.Error(err, "expected an error") + is.EqualError(err, "expected at most two arguments, unexpected arguments: bar") } func TestNameAndChartGenerateName(t *testing.T) { @@ -1016,9 +959,7 @@ func TestNameAndChartGenerateName(t *testing.T) { t.Parallel() name, chrt, err := instAction.NameAndChart([]string{tc.Chart}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) is.Equal(tc.ExpectedName, name) is.Equal(tc.Chart, chrt) @@ -1035,9 +976,7 @@ func TestInstallWithLabels(t *testing.T) { "key2": "val2", } resi, err := instAction.Run(buildChart(), nil) - if err != nil { - t.Fatalf("Failed install: %s", err) - } + req.NoError(err, "Failed install") res, err := releaserToV1Release(resi) req.NoError(err) @@ -1046,17 +985,15 @@ func TestInstallWithLabels(t *testing.T) { func TestInstallWithSystemLabels(t *testing.T) { is := assert.New(t) + req := require.New(t) instAction := installAction(t) instAction.Labels = map[string]string{ "owner": "val1", "key2": "val2", } _, err := instAction.Run(buildChart(), nil) - if err == nil { - t.Fatal("expected an error") - } - - is.Equal(fmt.Errorf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()), err) + req.Error(err, "expected an error") + is.EqualError(err, fmt.Sprintf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels())) } func TestUrlEqual(t *testing.T) { @@ -1111,13 +1048,9 @@ func TestUrlEqual(t *testing.T) { t.Parallel() u1, err := url.Parse(tc.url1) - if err != nil { - t.Fatalf("Failed to parse URL1 %s: %v", tc.url1, err) - } + require.NoError(t, err, "Failed to parse URL1 %s", tc.url1) u2, err := url.Parse(tc.url2) - if err != nil { - t.Fatalf("Failed to parse URL2 %s: %v", tc.url2, err) - } + require.NoError(t, err, "Failed to parse URL2 %s", tc.url2) is.Equal(tc.expected, urlEqual(u1, u2)) }) @@ -1161,7 +1094,7 @@ func TestInstallCRDs(t *testing.T) { mockChart := buildChart(withFile(mockFile)) crdsToInstall := mockChart.CRDObjects() - assert.Len(t, crdsToInstall, 1) + require.Len(t, crdsToInstall, 1) assert.Equal(t, crdsToInstall[0].File.Data, mockFile.Data) require.NoError(t, instAction.installCRDs(crdsToInstall)) } @@ -1285,11 +1218,7 @@ func TestInstallCRDs_CheckNilErrors(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { instAction := installAction(t) - - err := instAction.installCRDs(tt.input) - if err == nil { - t.Error("got nil expected err") - } + assert.Error(t, instAction.installCRDs(tt.input), "got nil expected err") }) } } diff --git a/pkg/action/lint_test.go b/pkg/action/lint_test.go index 5b5c2c50a..f3fd994d7 100644 --- a/pkg/action/lint_test.go +++ b/pkg/action/lint_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/v2/lint/support" ) @@ -89,11 +90,10 @@ func TestLintChart(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := lintChart(tt.chartPath, map[string]any{}, namespace, nil, tt.skipSchemaValidation) - switch { - case err != nil && !tt.err: - t.Errorf("%s", err) - case err == nil && tt.err: - t.Error("Expected a chart parsing error") + if tt.err { + require.Error(t, err, "Expected a chart parsing error") + } else { + require.NoError(t, err) } }) } @@ -106,14 +106,8 @@ func TestNonExistentChart(t *testing.T) { testLint := NewLint() result := testLint.Run(testCharts, values) - if len(result.Errors) != 1 { - t.Error("expected one error, but got", len(result.Errors)) - } - - actual := result.Errors[0].Error() - if actual != expectedError { - t.Errorf("expected '%s', but got '%s'", expectedError, actual) - } + require.Len(t, result.Errors, 1, "expected one error, but got", len(result.Errors)) + assert.EqualError(t, result.Errors[0], expectedError) }) t.Run("should error out for corrupted tgz chart", func(t *testing.T) { @@ -122,31 +116,23 @@ func TestNonExistentChart(t *testing.T) { testLint := NewLint() result := testLint.Run(testCharts, values) - if len(result.Errors) != 1 { - t.Error("expected one error, but got", len(result.Errors)) - } - - actual := result.Errors[0].Error() - if actual != expectedEOFError { - t.Errorf("expected '%s', but got '%s'", expectedEOFError, actual) - } + require.Len(t, result.Errors, 1, "expected one error, but got", len(result.Errors)) + assert.EqualError(t, result.Errors[0], expectedEOFError) }) } func TestLint_MultipleCharts(t *testing.T) { testCharts := []string{chart2MultipleChartLint, chart1MultipleChartLint} testLint := NewLint() - if result := testLint.Run(testCharts, values); len(result.Errors) > 0 { - t.Error(result.Errors) - } + result := testLint.Run(testCharts, values) + assert.Empty(t, result.Errors) } func TestLint_EmptyResultErrors(t *testing.T) { testCharts := []string{chart2MultipleChartLint} testLint := NewLint() - if result := testLint.Run(testCharts, values); len(result.Errors) > 0 { - t.Error("Expected no error, got more") - } + result := testLint.Run(testCharts, values) + assert.Empty(t, result.Errors, "Expected no error, got more") } func TestLint_ChartWithWarnings(t *testing.T) { @@ -154,18 +140,16 @@ func TestLint_ChartWithWarnings(t *testing.T) { testCharts := []string{chartWithNoTemplatesDir} testLint := NewLint() testLint.Strict = false - if result := testLint.Run(testCharts, values); len(result.Errors) > 0 { - t.Error("Expected no error, got more") - } + result := testLint.Run(testCharts, values) + assert.Empty(t, result.Errors, "Expected no error, got more") }) t.Run("should fail with one error when strict", func(t *testing.T) { testCharts := []string{chartWithNoTemplatesDir} testLint := NewLint() testLint.Strict = true - if result := testLint.Run(testCharts, values); len(result.Errors) != 1 { - t.Error("expected one error, but got", len(result.Errors)) - } + result := testLint.Run(testCharts, values) + assert.Len(t, result.Errors, 1, "expected one error") }) } diff --git a/pkg/action/list_test.go b/pkg/action/list_test.go index e7c2770d7..1c849028d 100644 --- a/pkg/action/list_test.go +++ b/pkg/action/list_test.go @@ -44,9 +44,7 @@ func TestListStates(t *testing.T) { "unknown": ListUnknown, "totally made up key": ListUnknown, } { - if expect != expect.FromName(input) { - t.Errorf("Expected %d for %s", expect, input) - } + assert.Equal(t, expect.FromName(input), expect, "Expected %d for %s", expect, input) // This is a cheap way to verify that ListAll actually allows everything but Unknown if got := expect.FromName(input); got != ListUnknown && got&ListAll == 0 { t.Errorf("Expected %s to match the ListAll filter", input) @@ -54,12 +52,10 @@ func TestListStates(t *testing.T) { } filter := ListDeployed | ListPendingRollback - if status := filter.FromName("deployed"); filter&status == 0 { - t.Errorf("Expected %d to match mask %d", status, filter) - } - if status := filter.FromName("failed"); filter&status != 0 { - t.Errorf("Expected %d to fail to match mask %d", status, filter) - } + status := filter.FromName("deployed") + assert.NotEqualf(t, ListStates(0), filter&status, "Expected %d to match mask %d", status, filter) + status = filter.FromName("failed") + assert.Equalf(t, ListStates(0), filter&status, "Expected %d to fail to match mask %d", status, filter) } func TestList_Empty(t *testing.T) { @@ -202,8 +198,7 @@ func TestList_StateMask(t *testing.T) { } one.SetStatus(common.StatusUninstalled, "uninstalled") - err = lister.cfg.Releases.Update(one) - req.NoError(err) + req.NoError(lister.cfg.Releases.Update(one)) res, err := lister.Run() req.NoError(err) @@ -277,9 +272,7 @@ func makeMeSomeReleasesWithStaleFailure(t *testing.T, store *storage.Storage) { five.Version = 1 for _, rel := range []*release.Release{one, two, three, four, five} { - if err := store.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, store.Create(rel)) } all, err := store.ListReleases() @@ -328,9 +321,7 @@ func makeMeSomeReleases(t *testing.T, store *storage.Storage) { three.Version = 3 for _, rel := range []*release.Release{one, two, three} { - if err := store.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, store.Create(rel)) } all, err := store.ListReleases() @@ -389,9 +380,7 @@ func TestSelectorList(t *testing.T) { lister := newListFixture(t) for _, rel := range []*release.Release{r1, r2, r3} { - if err := lister.cfg.Releases.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, lister.cfg.Releases.Create(rel)) } t.Run("should fail selector parsing", func(t *testing.T) { diff --git a/pkg/action/package_test.go b/pkg/action/package_test.go index 9984b508a..421f34b33 100644 --- a/pkg/action/package_test.go +++ b/pkg/action/package_test.go @@ -17,7 +17,6 @@ limitations under the License. package action import ( - "errors" "os" "path" "testing" @@ -35,18 +34,12 @@ func TestPassphraseFileFetcher(t *testing.T) { testPkg := NewPackage() fetcher, err := testPkg.passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil) - if err != nil { - t.Fatal("Unable to create passphraseFileFetcher", err) - } + require.NoError(t, err, "Unable to create passphraseFileFetcher") passphrase, err := fetcher("key") - if err != nil { - t.Fatal("Unable to fetch passphrase") - } + require.NoError(t, err, "Unable to fetch passphrase") - if string(passphrase) != secret { - t.Errorf("Expected %s got %s", secret, string(passphrase)) - } + assert.Equal(t, secret, string(passphrase), "Expected %s got %s", secret, string(passphrase)) } func TestPassphraseFileFetcher_WithLineBreak(t *testing.T) { @@ -55,18 +48,12 @@ func TestPassphraseFileFetcher_WithLineBreak(t *testing.T) { testPkg := NewPackage() fetcher, err := testPkg.passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil) - if err != nil { - t.Fatal("Unable to create passphraseFileFetcher", err) - } + require.NoError(t, err, "Unable to create passphraseFileFetcher") passphrase, err := fetcher("key") - if err != nil { - t.Fatal("Unable to fetch passphrase") - } + require.NoError(t, err, "Unable to fetch passphrase") - if string(passphrase) != secret { - t.Errorf("Expected %s got %s", secret, string(passphrase)) - } + assert.Equal(t, secret, string(passphrase), "Expected %s got %s", secret, string(passphrase)) } func TestPassphraseFileFetcher_WithInvalidStdin(t *testing.T) { @@ -74,21 +61,16 @@ func TestPassphraseFileFetcher_WithInvalidStdin(t *testing.T) { testPkg := NewPackage() stdin, err := os.CreateTemp(directory, "non-existing") - if err != nil { - t.Fatal("Unable to create test file", err) - } + require.NoError(t, err, "Unable to create test file") - if _, err := testPkg.passphraseFileFetcher("-", stdin); err == nil { - t.Error("Expected passphraseFileFetcher returning an error") - } + _, err = testPkg.passphraseFileFetcher("-", stdin) + assert.Error(t, err, "Expected passphraseFileFetcher returning an error") } func TestPassphraseFileFetcher_WithStdinAndMultipleFetches(t *testing.T) { testPkg := NewPackage() stdin, w, err := os.Pipe() - if err != nil { - t.Fatal("Unable to create pipe", err) - } + require.NoError(t, err, "Unable to create pipe") passphrase := "secret-from-stdin" @@ -99,18 +81,12 @@ func TestPassphraseFileFetcher_WithStdinAndMultipleFetches(t *testing.T) { for range 4 { fetcher, err := testPkg.passphraseFileFetcher("-", stdin) - if err != nil { - t.Errorf("Expected passphraseFileFetcher to not return an error, but got %v", err) - } + require.NoError(t, err, "Expected passphraseFileFetcher to not return an error") pass, err := fetcher("key") - if err != nil { - t.Errorf("Expected passphraseFileFetcher invocation to succeed, failed with %v", err) - } + require.NoError(t, err, "Expected passphraseFileFetcher invocation to succeed") - if string(pass) != string(passphrase) { - t.Errorf("Expected multiple passphrase fetch to return %q, got %q", passphrase, pass) - } + assert.Equal(t, string(passphrase), string(pass), "Expected multiple passphrase fetch to return %q, got %q", passphrase, pass) } } @@ -148,9 +124,7 @@ func TestValidateVersion(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if err := validateVersion(tt.args.ver); err != nil { - if !errors.Is(err, tt.wantErr) { - t.Errorf("Expected {%v}, got {%v}", tt.wantErr, err) - } + assert.ErrorIs(t, err, tt.wantErr) } }) } diff --git a/pkg/action/pull_test.go b/pkg/action/pull_test.go index 7cd5d3e85..a483de248 100644 --- a/pkg/action/pull_test.go +++ b/pkg/action/pull_test.go @@ -48,9 +48,7 @@ func TestPullSetRegistryClient(t *testing.T) { func TestPullRun_ChartNotFound(t *testing.T) { srv, err := startLocalServerForTests(t, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() config := actionConfigFixture(t) diff --git a/pkg/action/release_testing_test.go b/pkg/action/release_testing_test.go index 48a3251a1..91cb548a5 100644 --- a/pkg/action/release_testing_test.go +++ b/pkg/action/release_testing_test.go @@ -190,8 +190,7 @@ func TestGetContainerLogs_MultipleContainers(t *testing.T) { rt := &ReleaseTesting{Namespace: "default"} var buf bytes.Buffer - err := rt.getContainerLogs(&buf, client, "test-pod") - require.NoError(t, err) + require.NoError(t, rt.getContainerLogs(&buf, client, "test-pod")) output := buf.String() assert.Contains(t, output, "POD LOGS: test-pod (main)") assert.Contains(t, output, "POD LOGS: test-pod (sidecar)") @@ -217,8 +216,7 @@ func TestGetContainerLogs_WithInitContainers(t *testing.T) { rt := &ReleaseTesting{Namespace: "default"} var buf bytes.Buffer - err := rt.getContainerLogs(&buf, client, "test-pod") - require.NoError(t, err) + require.NoError(t, rt.getContainerLogs(&buf, client, "test-pod")) output := buf.String() // Init containers should appear before regular containers assert.Contains(t, output, "POD LOGS: test-pod (init-setup)") @@ -230,8 +228,7 @@ func TestGetContainerLogs_PodNotFound(t *testing.T) { rt := &ReleaseTesting{Namespace: "default"} var buf bytes.Buffer - err := rt.getContainerLogs(&buf, client, "nonexistent-pod") - assert.ErrorContains(t, err, "unable to get pod nonexistent-pod") + assert.ErrorContains(t, rt.getContainerLogs(&buf, client, "nonexistent-pod"), "unable to get pod nonexistent-pod") } func TestGetContainerLogs_OutputHeaderFormat(t *testing.T) { @@ -252,8 +249,7 @@ func TestGetContainerLogs_OutputHeaderFormat(t *testing.T) { rt := &ReleaseTesting{Namespace: "default"} var buf bytes.Buffer - err := rt.getContainerLogs(&buf, client, "multi-test") - require.NoError(t, err) + require.NoError(t, rt.getContainerLogs(&buf, client, "multi-test")) output := buf.String() assert.Contains(t, output, "POD LOGS: multi-test (container-a)") assert.Contains(t, output, "POD LOGS: multi-test (container-b)") diff --git a/pkg/action/rollback_test.go b/pkg/action/rollback_test.go index 01419341b..7ffd90d25 100644 --- a/pkg/action/rollback_test.go +++ b/pkg/action/rollback_test.go @@ -78,8 +78,7 @@ func TestRollback_WaitOptionsPassedDownstream(t *testing.T) { // Access the underlying FailingKubeClient to check recorded options failer := config.KubeClient.(*kubefake.FailingKubeClient) - err := client.Run(rel.Name) - req.NoError(err) + req.NoError(client.Run(rel.Name)) // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") diff --git a/pkg/action/show_test.go b/pkg/action/show_test.go index 0dde7fb74..c6c55ead1 100644 --- a/pkg/action/show_test.go +++ b/pkg/action/show_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -47,9 +48,7 @@ func TestShow(t *testing.T) { } output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := `name: alpine @@ -69,9 +68,7 @@ bar baz ` - if output != expect { - t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) - } + assert.Equal(t, expect, output, "Expected\n%q\nGot\n%q\n", expect, output) } func TestShowNoValues(t *testing.T) { @@ -82,13 +79,9 @@ func TestShowNoValues(t *testing.T) { // Regression tests for missing values. See issue #1024. client.OutputFormat = ShowValues output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if output != "" { - t.Errorf("expected empty values buffer, got %s", output) - } + assert.Empty(t, output, "expected empty values buffer, got %s", output) } func TestShowValuesByJsonPathFormat(t *testing.T) { @@ -97,13 +90,9 @@ func TestShowValuesByJsonPathFormat(t *testing.T) { client.JSONPathTemplate = "{$.nestedKey.simpleKey}" client.chart = buildChart(withSampleValues()) output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := "simpleValue" - if output != expect { - t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) - } + assert.Equal(t, expect, output, "Expected\n%q\nGot\n%q\n", expect, output) } func TestShowCRDs(t *testing.T) { @@ -121,9 +110,7 @@ func TestShowCRDs(t *testing.T) { } output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := `--- foo @@ -135,9 +122,7 @@ bar baz ` - if output != expect { - t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) - } + assert.Equal(t, expect, output, "Expected\n%q\nGot\n%q\n", expect, output) } func TestShowNoReadme(t *testing.T) { @@ -154,9 +139,7 @@ func TestShowNoReadme(t *testing.T) { } output, err := client.Run("") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expect := `name: alpine @@ -167,9 +150,7 @@ foo bar ` - if output != expect { - t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) - } + assert.Equal(t, expect, output, "Expected\n%q\nGot\n%q\n", expect, output) } func TestShowSetRegistryClient(t *testing.T) { diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go index 913ade1a5..f36fe7874 100644 --- a/pkg/action/uninstall_test.go +++ b/pkg/action/uninstall_test.go @@ -121,7 +121,7 @@ func TestUninstallRelease_Wait(t *testing.T) { unAction.cfg.KubeClient = failer resi, err := unAction.Run(rel.Name) req.Error(err) - is.Contains(err.Error(), "U timed out") + req.ErrorContains(err, "U timed out") res, err := releaserToV1Release(resi.Release) req.NoError(err) is.Equal(common.StatusUninstalled, res.Info.Status) @@ -163,7 +163,7 @@ func TestUninstallRelease_Cascade(t *testing.T) { unAction.cfg.KubeClient = failer _, err := unAction.Run(rel.Name) require.Error(t, err) - is.Contains(err.Error(), "failed to delete release: come-fail-away") + is.ErrorContains(err, "failed to delete release: come-fail-away") } func TestUninstallRun_UnreachableKubeClient(t *testing.T) { diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index 7a73c7179..53419b6a8 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -176,8 +176,8 @@ func TestUpgradeRelease_RollbackOnFailure(t *testing.T) { resi, err := upAction.Run(rel.Name, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "arming key removed") - is.Contains(err.Error(), "rollback-on-failure") + req.ErrorContains(err, "arming key removed") + req.ErrorContains(err, "rollback-on-failure") res, err := releaserToV1Release(resi) req.NoError(err) @@ -207,8 +207,8 @@ func TestUpgradeRelease_RollbackOnFailure(t *testing.T) { _, err := upAction.Run(rel.Name, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "update fail") - is.Contains(err.Error(), "an error occurred while rolling back the release") + req.ErrorContains(err, "update fail") + is.ErrorContains(err, "an error occurred while rolling back the release") }) } @@ -240,8 +240,7 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { rel.Info.Status = common.StatusDeployed rel.Config = existingValues - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.ReuseValues = true // setting newValues and upgrading @@ -253,11 +252,8 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { // Now make sure it is actually upgraded updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) req.NoError(err) + req.NotNil(updatedResi, "Updated Release is nil") - if updatedResi == nil { - is.Fail("Updated Release is nil") - return - } updatedRes, err := releaserToV1Release(updatedResi) req.NoError(err) @@ -303,8 +299,7 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { Config: existingValues, Version: 1, } - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.ReuseValues = true sampleChartWithSubChart := buildChart( @@ -322,11 +317,8 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { // Now get the upgraded release updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) req.NoError(err) + req.NotNil(updatedResi, "Updated Release is nil") - if updatedResi == nil { - is.Fail("Updated Release is nil") - return - } updatedRes, err := releaserToV1Release(updatedResi) req.NoError(err) @@ -373,8 +365,7 @@ func TestUpgradeRelease_ResetThenReuseValues(t *testing.T) { rel.Info.Status = common.StatusDeployed rel.Config = existingValues - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.ResetThenReuseValues = true // setting newValues and upgrading @@ -386,11 +377,8 @@ func TestUpgradeRelease_ResetThenReuseValues(t *testing.T) { // Now make sure it is actually upgraded updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) req.NoError(err) + req.NotNil(updatedResi, "Updated Release is nil") - if updatedResi == nil { - is.Fail("Updated Release is nil") - return - } updatedRes, err := releaserToV1Release(updatedResi) req.NoError(err) @@ -417,7 +405,7 @@ func TestUpgradeRelease_Pending(t *testing.T) { vals := map[string]any{} _, err := upAction.Run(rel.Name, buildChart(), vals) - req.Contains(err.Error(), "progress", err) + req.ErrorContains(err, "progress") } func TestUpgradeRelease_Interrupted_Wait(t *testing.T) { @@ -470,7 +458,7 @@ func TestUpgradeRelease_Interrupted_RollbackOnFailure(t *testing.T) { resi, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.Error(err) - is.Contains(err.Error(), "release interrupted-release failed, and has been rolled back due to rollback-on-failure being set: context canceled") + req.ErrorContains(err, "release interrupted-release failed, and has been rolled back due to rollback-on-failure being set: context canceled") res, err := releaserToV1Release(resi) req.NoError(err) // Now make sure it is actually upgraded @@ -491,9 +479,8 @@ func TestMergeCustomLabels(t *testing.T) { {map[string]string{"k1": "v1", "k2": "v2"}, map[string]string{"k1": "null", "k2": "v3"}, map[string]string{"k2": "v3"}}, } for _, test := range tests { - if output := mergeCustomLabels(test[0], test[1]); !reflect.DeepEqual(test[2], output) { - t.Errorf("Expected {%v}, got {%v}", test[2], output) - } + output := mergeCustomLabels(test[0], test[1]) + assert.Truef(t, reflect.DeepEqual(test[2], output), "Expected {%v}, got {%v}", test[2], output) } } @@ -511,8 +498,7 @@ func TestUpgradeRelease_Labels(t *testing.T) { } rel.Info.Status = common.StatusDeployed - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.Labels = map[string]string{ "key1": "null", @@ -528,11 +514,8 @@ func TestUpgradeRelease_Labels(t *testing.T) { // Now make sure it is actually upgraded and labels were merged updatedResi, err := upAction.cfg.Releases.Get(res.Name, 2) req.NoError(err) + req.NotNil(updatedResi, "Updated Release is nil") - if updatedResi == nil { - is.Fail("Updated Release is nil") - return - } updatedRes, err := releaserToV1Release(updatedResi) req.NoError(err) is.Equal(common.StatusDeployed, updatedRes.Info.Status) @@ -541,11 +524,8 @@ func TestUpgradeRelease_Labels(t *testing.T) { // Now make sure it is suppressed release still contains original labels initialResi, err := upAction.cfg.Releases.Get(res.Name, 1) req.NoError(err) + req.NotNil(initialResi, "Initial Release is nil") - if initialResi == nil { - is.Fail("Updated Release is nil") - return - } initialRes, err := releaserToV1Release(initialResi) req.NoError(err) is.Equal(common.StatusSuperseded, initialRes.Info.Status) @@ -566,8 +546,7 @@ func TestUpgradeRelease_SystemLabels(t *testing.T) { } rel.Info.Status = common.StatusDeployed - err := upAction.cfg.Releases.Create(rel) - req.NoError(err) + req.NoError(upAction.cfg.Releases.Create(rel)) upAction.Labels = map[string]string{ "key1": "null", @@ -575,12 +554,10 @@ func TestUpgradeRelease_SystemLabels(t *testing.T) { "owner": "val3", } // setting newValues and upgrading - _, err = upAction.Run(rel.Name, buildChart(), nil) - if err == nil { - t.Fatal("expected an error") - } + _, err := upAction.Run(rel.Name, buildChart(), nil) + require.Error(t, err, "expected an error") - is.Equal(fmt.Errorf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()), err) + is.EqualError(err, fmt.Sprintf("user supplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels())) } func TestUpgradeRelease_DryRun(t *testing.T) { diff --git a/pkg/action/validate_test.go b/pkg/action/validate_test.go index 878bec599..8bd9f1916 100644 --- a/pkg/action/validate_test.go +++ b/pkg/action/validate_test.go @@ -132,7 +132,7 @@ func TestRequireAdoption(t *testing.T) { // Verify that a resource that lacks labels/annotations can be adopted found, err := requireAdoption(resources) require.NoError(t, err) - assert.Len(t, found, 1) + require.Len(t, found, 1) assert.Equal(t, found[0], existing) assert.NotSame(t, found[0], existing) } @@ -157,7 +157,7 @@ func TestExistingResourceConflict(t *testing.T) { // Verify only existing resources are returned found, err := existingResourceConflict(resources, releaseName, releaseNamespace) require.NoError(t, err) - assert.Len(t, found, 1) + require.Len(t, found, 1) assert.Equal(t, found[0], existing) assert.NotSame(t, found[0], existing) @@ -171,45 +171,38 @@ func TestCheckOwnership(t *testing.T) { deployFoo := newDeploymentResource("foo", "ns-a", "") // Verify that a resource that lacks labels/annotations is not owned - err := checkOwnership(deployFoo.Object, "rel-a", "ns-a") - require.EqualError(t, err, `invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a"), `invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set managed by label and verify annotation error message _ = accessor.SetLabels(deployFoo.Object, map[string]string{ appManagedByLabel: appManagedByHelm, }) - err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - require.EqualError(t, err, `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a"), `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "rel-a"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set only the release name annotation and verify missing release namespace error message _ = accessor.SetAnnotations(deployFoo.Object, map[string]string{ helmReleaseNameAnnotation: "rel-a", }) - err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - require.EqualError(t, err, `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a"), `invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "ns-a"`) // Set both release name and namespace annotations and verify no ownership errors _ = accessor.SetAnnotations(deployFoo.Object, map[string]string{ helmReleaseNameAnnotation: "rel-a", helmReleaseNamespaceAnnotation: "ns-a", }) - err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - require.NoError(t, err) + require.NoError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a")) // Verify ownership error for wrong release name - err = checkOwnership(deployFoo.Object, "rel-b", "ns-a") - require.EqualError(t, err, `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-name" must equal "rel-b": current value is "rel-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-b", "ns-a"), `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-name" must equal "rel-b": current value is "rel-a"`) // Verify ownership error for wrong release namespace - err = checkOwnership(deployFoo.Object, "rel-a", "ns-b") - require.EqualError(t, err, `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-namespace" must equal "ns-b": current value is "ns-a"`) + require.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-b"), `invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-namespace" must equal "ns-b": current value is "ns-a"`) // Verify ownership error for wrong manager label _ = accessor.SetLabels(deployFoo.Object, map[string]string{ appManagedByLabel: "helm", }) - err = checkOwnership(deployFoo.Object, "rel-a", "ns-a") - assert.EqualError(t, err, `invalid ownership metadata; label validation error: key "app.kubernetes.io/managed-by" must equal "Helm": current value is "helm"`) + assert.EqualError(t, checkOwnership(deployFoo.Object, "rel-a", "ns-a"), `invalid ownership metadata; label validation error: key "app.kubernetes.io/managed-by" must equal "Helm": current value is "helm"`) } func TestVerifyOwnershipBeforeDelete(t *testing.T) { @@ -249,8 +242,8 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) require.NoError(t, err) - assert.Len(t, ownedList, 1) - assert.Len(t, unownedList, 1) + require.Len(t, ownedList, 1) + require.Len(t, unownedList, 1) assert.Equal(t, "owned", ownedList[0].Name) assert.Equal(t, "unowned", unownedList[0].Name) }) @@ -297,8 +290,8 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { ownedList, unownedList, _, err := verifyOwnershipBeforeDelete(resources, releaseName, releaseNamespace) require.NoError(t, err) - assert.Len(t, ownedList, 1) - assert.Len(t, unownedList, 1) + require.Len(t, ownedList, 1) + require.Len(t, unownedList, 1) assert.Equal(t, "owned", ownedList[0].Name) assert.Equal(t, "unowned", unownedList[0].Name) }) @@ -306,32 +299,26 @@ func TestVerifyOwnershipBeforeDelete(t *testing.T) { func TestSetMetadataVisitor(t *testing.T) { var ( - err error deployFoo = newDeploymentResource("foo", "ns-a", "") deployBar = newDeploymentResource("bar", "ns-a-system", "") resources = kube.ResourceList{deployFoo, deployBar} ) // Set release tracking metadata and verify no error - err = resources.Visit(setMetadataVisitor("rel-a", "ns-a", true)) - require.NoError(t, err) + require.NoError(t, resources.Visit(setMetadataVisitor("rel-a", "ns-a", true))) // Verify that release "b" cannot take ownership of "a" - err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - require.Error(t, err) + require.Error(t, resources.Visit(setMetadataVisitor("rel-b", "ns-a", false))) // Force release "b" to take ownership - err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", true)) - require.NoError(t, err) + require.NoError(t, resources.Visit(setMetadataVisitor("rel-b", "ns-a", true))) // Check that there is now no ownership error when setting metadata without force - err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - require.NoError(t, err) + require.NoError(t, resources.Visit(setMetadataVisitor("rel-b", "ns-a", false))) // Add a new resource that is missing ownership metadata and verify error resources.Append(newDeploymentResource("baz", "default", "")) - err = resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)) - assert.ErrorContains(t, err, `Deployment "baz" in namespace "" cannot be owned`) + assert.ErrorContains(t, resources.Visit(setMetadataVisitor("rel-b", "ns-a", false)), `Deployment "baz" in namespace "" cannot be owned`) } func TestValidateNameAndGenerateName(t *testing.T) { diff --git a/pkg/chart/common/capabilities_test.go b/pkg/chart/common/capabilities_test.go index c8d47581c..b099e3193 100644 --- a/pkg/chart/common/capabilities_test.go +++ b/pkg/chart/common/capabilities_test.go @@ -17,68 +17,44 @@ package common import ( "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestVersionSet(t *testing.T) { vs := VersionSet{"v1", "apps/v1"} - if d := len(vs); d != 2 { - t.Errorf("Expected 2 versions, got %d", d) - } + d := len(vs) + assert.Equalf(t, 2, d, "Expected 2 versions, got %d", d) - if !vs.Has("apps/v1") { - t.Error("Expected to find apps/v1") - } + assert.True(t, vs.Has("apps/v1"), "Expected to find apps/v1") - if vs.Has("Spanish/inquisition") { - t.Error("No one expects the Spanish/inquisition") - } + assert.False(t, vs.Has("Spanish/inquisition"), "No one expects the Spanish/inquisition") } func TestDefaultVersionSet(t *testing.T) { - if !DefaultVersionSet.Has("v1") { - t.Error("Expected core v1 version set") - } + assert.True(t, DefaultVersionSet.Has("v1"), "Expected core v1 version set") } func TestDefaultCapabilities(t *testing.T) { caps := DefaultCapabilities kv := caps.KubeVersion - if kv.String() != "v1.20.0" { - t.Errorf("Expected default KubeVersion.String() to be v1.20.0, got %q", kv.String()) - } - if kv.Version != "v1.20.0" { - t.Errorf("Expected default KubeVersion.Version to be v1.20.0, got %q", kv.Version) - } - if kv.GitVersion() != "v1.20.0" { - t.Errorf("Expected default KubeVersion.GitVersion() to be v1.20.0, got %q", kv.Version) - } - if kv.Major != "1" { - t.Errorf("Expected default KubeVersion.Major to be 1, got %q", kv.Major) - } - if kv.Minor != "20" { - t.Errorf("Expected default KubeVersion.Minor to be 20, got %q", kv.Minor) - } + assert.Equalf(t, "v1.20.0", kv.String(), "Expected default KubeVersion.String() to be v1.20.0, got %q", kv.String()) + assert.Equalf(t, "v1.20.0", kv.Version, "Expected default KubeVersion.Version to be v1.20.0, got %q", kv.Version) + assert.Equalf(t, "v1.20.0", kv.GitVersion(), "Expected default KubeVersion.GitVersion() to be v1.20.0, got %q", kv.Version) + assert.Equalf(t, "1", kv.Major, "Expected default KubeVersion.Major to be 1, got %q", kv.Major) + assert.Equalf(t, "20", kv.Minor, "Expected default KubeVersion.Minor to be 20, got %q", kv.Minor) hv := caps.HelmVersion - if hv.Version != "v4.2" { - t.Errorf("Expected default HelmVersion to be v4.2, got %q", hv.Version) - } + assert.Equalf(t, "v4.2", hv.Version, "Expected default HelmVersion to be v4.2, got %q", hv.Version) } func TestParseKubeVersion(t *testing.T) { kv, err := ParseKubeVersion("v1.16.0") - if err != nil { - t.Error("Expected v1.16.0 to parse successfully") - } - if kv.Version != "v1.16.0" { - t.Errorf("Expected parsed KubeVersion.Version to be v1.16.0, got %q", kv.String()) - } - if kv.Major != "1" { - t.Errorf("Expected parsed KubeVersion.Major to be 1, got %q", kv.Major) - } - if kv.Minor != "16" { - t.Errorf("Expected parsed KubeVersion.Minor to be 16, got %q", kv.Minor) - } + require.NoError(t, err, "Expected v1.16.0 to parse successfully") + assert.Equalf(t, "v1.16.0", kv.Version, "Expected parsed KubeVersion.Version to be v1.16.0, got %q", kv.String()) + assert.Equalf(t, "1", kv.Major, "Expected parsed KubeVersion.Major to be 1, got %q", kv.Major) + assert.Equalf(t, "16", kv.Minor, "Expected parsed KubeVersion.Minor to be 16, got %q", kv.Minor) } func TestParseKubeVersionWithVendorSuffixes(t *testing.T) { @@ -101,21 +77,11 @@ func TestParseKubeVersionWithVendorSuffixes(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { kv, err := ParseKubeVersion(tt.input) - if err != nil { - t.Fatalf("ParseKubeVersion() error = %v", err) - } - if kv.Version != tt.wantVer { - t.Errorf("Version = %q, want %q", kv.Version, tt.wantVer) - } - if kv.String() != tt.wantString { - t.Errorf("String() = %q, want %q", kv.String(), tt.wantString) - } - if kv.Major != tt.wantMajor { - t.Errorf("Major = %q, want %q", kv.Major, tt.wantMajor) - } - if kv.Minor != tt.wantMinor { - t.Errorf("Minor = %q, want %q", kv.Minor, tt.wantMinor) - } + require.NoErrorf(t, err, "ParseKubeVersion()") + assert.Equalf(t, tt.wantVer, kv.Version, "Version = %q, want %q", kv.Version, tt.wantVer) + assert.Equalf(t, tt.wantString, kv.String(), "String() = %q, want %q", kv.String(), tt.wantString) + assert.Equalf(t, tt.wantMajor, kv.Major, "Major = %q, want %q", kv.Major, tt.wantMajor) + assert.Equalf(t, tt.wantMinor, kv.Minor, "Minor = %q, want %q", kv.Minor, tt.wantMinor) }) } } diff --git a/pkg/chart/common/util/coalesce_test.go b/pkg/chart/common/util/coalesce_test.go index d7f46a1da..e058bd996 100644 --- a/pkg/chart/common/util/coalesce_test.go +++ b/pkg/chart/common/util/coalesce_test.go @@ -141,9 +141,7 @@ func TestCoalesceValues(t *testing.T) { ) vals, err := common.ReadValues(testCoalesceValuesYaml) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // taking a copy of the values before passing it // to CoalesceValues as argument, so that we can @@ -152,9 +150,7 @@ func TestCoalesceValues(t *testing.T) { maps.Copy(valsCopy, vals) v, err := CoalesceValues(c, vals) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) j, _ := json.MarshalIndent(v, "", " ") t.Logf("Coalesced Values: %s", string(j)) @@ -211,32 +207,26 @@ func TestCoalesceValues(t *testing.T) { nullKeys := []string{"bottom", "right", "left", "front"} for _, nullKey := range nullKeys { - if _, ok := v[nullKey]; ok { - t.Errorf("Expected key %q to be removed, still present", nullKey) - } + _, ok := v[nullKey] + assert.Falsef(t, ok, "Expected key %q to be removed, still present", nullKey) } - if _, ok := v["nested"].(map[string]any)["boat"]; ok { - t.Error("Expected nested boat key to be removed, still present") - } + _, ok := v["nested"].(map[string]any)["boat"] + assert.False(t, ok, "Expected nested boat key to be removed, still present") subchart := v["pequod"].(map[string]any) - if _, ok := subchart["boat"]; ok { - t.Error("Expected subchart boat key to be removed, still present") - } + _, ok = subchart["boat"] + assert.False(t, ok, "Expected subchart boat key to be removed, still present") subsubchart := subchart["ahab"].(map[string]any) - if _, ok := subsubchart["boat"]; ok { - t.Error("Expected sub-subchart ahab boat key to be removed, still present") - } + _, ok = subsubchart["boat"] + assert.False(t, ok, "Expected sub-subchart ahab boat key to be removed, still present") - if _, ok := subsubchart["nested"].(map[string]any)["boat"]; ok { - t.Error("Expected sub-subchart nested boat key to be removed, still present") - } + _, ok = subsubchart["nested"].(map[string]any)["boat"] + assert.False(t, ok, "Expected sub-subchart nested boat key to be removed, still present") - if _, ok := subsubchart["object"]; ok { - t.Error("Expected sub-subchart object map to be removed, still present") - } + _, ok = subsubchart["object"] + assert.False(t, ok, "Expected sub-subchart object map to be removed, still present") // CoalesceValues should not mutate the passed arguments is.Equal(valsCopy, vals) @@ -306,9 +296,7 @@ func TestMergeValues(t *testing.T) { ) vals, err := common.ReadValues(testCoalesceValuesYaml) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // taking a copy of the values before passing it // to MergeValues as argument, so that we can @@ -317,9 +305,7 @@ func TestMergeValues(t *testing.T) { maps.Copy(valsCopy, vals) v, err := MergeValues(c, vals) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) j, _ := json.MarshalIndent(v, "", " ") t.Logf("Coalesced Values: %s", string(j)) @@ -377,25 +363,19 @@ func TestMergeValues(t *testing.T) { // removed. nullKeys := []string{"bottom", "right", "left", "front"} for _, nullKey := range nullKeys { - if vv, ok := v[nullKey]; !ok { - t.Errorf("Expected key %q to be present but it was removed", nullKey) - } else if vv != nil { - t.Errorf("Expected key %q to be null but it has a value of %v", nullKey, vv) - } + vv, ok := v[nullKey] + assert.Truef(t, ok, "Expected key %q to be present but it was removed", nullKey) + assert.Nilf(t, vv, "Expected key %q to be null but it has a value of %v", nullKey, vv) } - if _, ok := v["nested"].(map[string]any)["boat"]; !ok { - t.Error("Expected nested boat key to be present but it was removed") - } + _, ok := v["nested"].(map[string]any)["boat"] + assert.True(t, ok, "Expected nested boat key to be present but it was removed") subchart := v["pequod"].(map[string]any)["ahab"].(map[string]any) - if _, ok := subchart["boat"]; !ok { - t.Error("Expected subchart boat key to be present but it was removed") - } + assert.Contains(t, subchart, "boat", "Expected subchart boat key to be present but it was removed") - if _, ok := subchart["nested"].(map[string]any)["bar"]; !ok { - t.Error("Expected subchart nested bar key to be present but it was removed") - } + _, ok = subchart["nested"].(map[string]any)["bar"] + assert.True(t, ok, "Expected subchart nested bar key to be present but it was removed") // CoalesceValues should not mutate the passed arguments is.Equal(valsCopy, vals) @@ -433,47 +413,27 @@ func TestCoalesceTables(t *testing.T) { // otherwise the values are coalesced. CoalesceTables(dst, src) - if dst["name"] != "Ishmael" { - t.Errorf("Unexpected name: %s", dst["name"]) - } - if dst["occupation"] != "whaler" { - t.Errorf("Unexpected occupation: %s", dst["occupation"]) - } + assert.Equal(t, "Ishmael", dst["name"], "Unexpected name: %s", dst["name"]) + assert.Equal(t, "whaler", dst["occupation"], "Unexpected occupation: %s", dst["occupation"]) addr, ok := dst["address"].(map[string]any) - if !ok { - t.Fatal("Address went away.") - } - - if addr["street"].(string) != "123 Spouter Inn Ct." { - t.Errorf("Unexpected address: %v", addr["street"]) - } + require.True(t, ok, "Address went away.") + assert.Equal(t, "123 Spouter Inn Ct.", addr["street"].(string), "Unexpected address: %v", addr["street"]) + assert.Equal(t, "Nantucket", addr["city"].(string), "Unexpected city: %v", addr["city"]) + assert.Equal(t, "MA", addr["state"].(string), "Unexpected state: %v", addr["state"]) - if addr["city"].(string) != "Nantucket" { - t.Errorf("Unexpected city: %v", addr["city"]) - } + _, ok = addr["country"] + assert.False(t, ok, "The country is not left out.") - if addr["state"].(string) != "MA" { - t.Errorf("Unexpected state: %v", addr["state"]) - } + det, ok := dst["details"].(map[string]any) + require.Truef(t, ok, "Details is the wrong type: %v", dst["details"]) - if _, ok = addr["country"]; ok { - t.Error("The country is not left out.") - } + _, ok = det["friends"] + assert.True(t, ok, "Could not find your friends. Maybe you don't have any. :-(") + assert.Equal(t, "pequod", dst["boat"].(string), "Expected boat string, got %v", dst["boat"]) - if det, ok := dst["details"].(map[string]any); !ok { - t.Fatalf("Details is the wrong type: %v", dst["details"]) - } else if _, ok := det["friends"]; !ok { - t.Error("Could not find your friends. Maybe you don't have any. :-(") - } - - if dst["boat"].(string) != "pequod" { - t.Errorf("Expected boat string, got %v", dst["boat"]) - } - - if _, ok = dst["hole"]; ok { - t.Error("The hole still exists.") - } + _, ok = dst["hole"] + assert.False(t, ok, "The hole still exists.") dst2 := map[string]any{ "name": "Ishmael", @@ -493,40 +453,21 @@ func TestCoalesceTables(t *testing.T) { // this happens when the --reuse-values flag is set but the chart has no modifications yet CoalesceTables(dst2, nil) - if dst2["name"] != "Ishmael" { - t.Errorf("Unexpected name: %s", dst2["name"]) - } + assert.Equal(t, "Ishmael", dst2["name"], "Unexpected name: %s", dst2["name"]) addr2, ok := dst2["address"].(map[string]any) - if !ok { - t.Fatal("Address went away.") - } - - if addr2["street"].(string) != "123 Spouter Inn Ct." { - t.Errorf("Unexpected address: %v", addr2["street"]) - } - - if addr2["city"].(string) != "Nantucket" { - t.Errorf("Unexpected city: %v", addr2["city"]) - } - - if addr2["country"].(string) != "US" { - t.Errorf("Unexpected Country: %v", addr2["country"]) - } - - if det2, ok := dst2["details"].(map[string]any); !ok { - t.Fatalf("Details is the wrong type: %v", dst2["details"]) - } else if _, ok := det2["friends"]; !ok { - t.Error("Could not find your friends. Maybe you don't have any. :-(") - } - - if dst2["boat"].(string) != "pequod" { - t.Errorf("Expected boat string, got %v", dst2["boat"]) - } - - if dst2["hole"].(string) != "black" { - t.Errorf("Expected hole string, got %v", dst2["boat"]) - } + require.True(t, ok, "Address went away.") + assert.Equal(t, "123 Spouter Inn Ct.", addr2["street"].(string), "Unexpected address: %v", addr2["street"]) + assert.Equal(t, "Nantucket", addr2["city"].(string), "Unexpected city: %v", addr2["city"]) + assert.Equal(t, "US", addr2["country"].(string), "Unexpected Country: %v", addr2["country"]) + + det2, ok := dst2["details"].(map[string]any) + require.Truef(t, ok, "Details is the wrong type: %v", dst2["details"]) + + _, ok = det2["friends"] + assert.True(t, ok, "Could not find your friends. Maybe you don't have any. :-(") + assert.Equal(t, "pequod", dst2["boat"].(string), "Expected boat string, got %v", dst2["boat"]) + assert.Equal(t, "black", dst2["hole"].(string), "Expected hole string, got %v", dst2["boat"]) } func TestMergeTables(t *testing.T) { @@ -561,51 +502,30 @@ func TestMergeTables(t *testing.T) { // otherwise the values are coalesced. MergeTables(dst, src) - if dst["name"] != "Ishmael" { - t.Errorf("Unexpected name: %s", dst["name"]) - } - if dst["occupation"] != "whaler" { - t.Errorf("Unexpected occupation: %s", dst["occupation"]) - } + assert.Equal(t, "Ishmael", dst["name"], "Unexpected name: %s", dst["name"]) + assert.Equal(t, "whaler", dst["occupation"], "Unexpected occupation: %s", dst["occupation"]) addr, ok := dst["address"].(map[string]any) - if !ok { - t.Fatal("Address went away.") - } - - if addr["street"].(string) != "123 Spouter Inn Ct." { - t.Errorf("Unexpected address: %v", addr["street"]) - } - - if addr["city"].(string) != "Nantucket" { - t.Errorf("Unexpected city: %v", addr["city"]) - } - - if addr["state"].(string) != "MA" { - t.Errorf("Unexpected state: %v", addr["state"]) - } + require.True(t, ok, "Address went away.") + assert.Equal(t, "123 Spouter Inn Ct.", addr["street"].(string), "Unexpected address: %v", addr["street"]) + assert.Equal(t, "Nantucket", addr["city"].(string), "Unexpected city: %v", addr["city"]) + assert.Equal(t, "MA", addr["state"].(string), "Unexpected state: %v", addr["state"]) // This is one test that is different from CoalesceTables. Because country // is a nil value and it's not removed it's still present. - if _, ok = addr["country"]; !ok { - t.Error("The country is left out.") - } + _, ok = addr["country"] + assert.True(t, ok, "The country is left out.") - if det, ok := dst["details"].(map[string]any); !ok { - t.Fatalf("Details is the wrong type: %v", dst["details"]) - } else if _, ok := det["friends"]; !ok { - t.Error("Could not find your friends. Maybe you don't have any. :-(") - } + det, ok := dst["details"].(map[string]any) + require.Truef(t, ok, "Details is the wrong type: %v", dst["details"]) - if dst["boat"].(string) != "pequod" { - t.Errorf("Expected boat string, got %v", dst["boat"]) - } + _, ok = det["friends"] + assert.True(t, ok, "Could not find your friends. Maybe you don't have any. :-(") + assert.Equal(t, "pequod", dst["boat"].(string), "Expected boat string, got %v", dst["boat"]) // This is one test that is different from CoalesceTables. Because hole // is a nil value and it's not removed it's still present. - if _, ok = dst["hole"]; !ok { - t.Error("The hole no longer exists.") - } + assert.Contains(t, dst, "hole", "The hole no longer exists.") dst2 := map[string]any{ "name": "Ishmael", @@ -626,44 +546,21 @@ func TestMergeTables(t *testing.T) { // this happens when the --reuse-values flag is set but the chart has no modifications yet MergeTables(dst2, nil) - if dst2["name"] != "Ishmael" { - t.Errorf("Unexpected name: %s", dst2["name"]) - } + assert.Equal(t, "Ishmael", dst2["name"], "Unexpected name: %s", dst2["name"]) addr2, ok := dst2["address"].(map[string]any) - if !ok { - t.Fatal("Address went away.") - } - - if addr2["street"].(string) != "123 Spouter Inn Ct." { - t.Errorf("Unexpected address: %v", addr2["street"]) - } - - if addr2["city"].(string) != "Nantucket" { - t.Errorf("Unexpected city: %v", addr2["city"]) - } - - if addr2["country"].(string) != "US" { - t.Errorf("Unexpected Country: %v", addr2["country"]) - } - - if det2, ok := dst2["details"].(map[string]any); !ok { - t.Fatalf("Details is the wrong type: %v", dst2["details"]) - } else if _, ok := det2["friends"]; !ok { - t.Error("Could not find your friends. Maybe you don't have any. :-(") - } - - if dst2["boat"].(string) != "pequod" { - t.Errorf("Expected boat string, got %v", dst2["boat"]) - } - - if dst2["hole"].(string) != "black" { - t.Errorf("Expected hole string, got %v", dst2["boat"]) - } - - if dst2["nilval"] != nil { - t.Error("Expected nilvalue to have nil value but it does not") - } + require.True(t, ok, "Address went away.") + assert.Equal(t, "123 Spouter Inn Ct.", addr2["street"].(string), "Unexpected address: %v", addr2["street"]) + assert.Equal(t, "Nantucket", addr2["city"].(string), "Unexpected city: %v", addr2["city"]) + assert.Equal(t, "US", addr2["country"].(string), "Unexpected Country: %v", addr2["country"]) + + det2, ok := dst2["details"].(map[string]any) + require.Truef(t, ok, "Details is the wrong type: %v", dst2["details"]) + + assert.Contains(t, det2, "friends", "Could not find your friends. Maybe you don't have any. :-(") + assert.Equal(t, "pequod", dst2["boat"].(string), "Expected boat string, got %v", dst2["boat"]) + assert.Equal(t, "black", dst2["hole"].(string), "Expected hole string, got %v", dst2["hole"]) + assert.Nil(t, dst2["nilval"], "Expected nilvalue to have nil value but it does not") } func TestCoalesceValuesWarnings(t *testing.T) { @@ -716,9 +613,7 @@ func TestCoalesceValuesWarnings(t *testing.T) { } _, err := coalesce(printf, c, vals, "", false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) t.Logf("vals: %v", vals) assert.Contains(t, warnings, "warning: skipped value for level1.level2.level3.boat: Not a table.") @@ -761,8 +656,7 @@ func TestCoalesceValuesEmptyMapWithNils(t *testing.T) { is.Equal("bar", data["foo"]) // "baz" should be preserved with nil value since it wasn't in chart defaults - _, ok = data["baz"] - is.True(ok, "Expected data.baz key to be present but it was removed") + is.Contains(data, "baz", "Expected data.baz key to be present but it was removed") is.Nil(data["baz"], "Expected data.baz key to be nil but it is not") } @@ -926,7 +820,6 @@ func TestCoalesceValuesSubchartNilCleanedWhenUserPartiallyOverrides(t *testing.T keyMapping, ok := childVals["keyMapping"].(map[string]any) is.True(ok, "keyMapping should be a map") - is.Equal("sha256", keyMapping["format"], "User override should be preserved") _, ok = keyMapping["password"] diff --git a/pkg/chart/common/util/jsonschema_test.go b/pkg/chart/common/util/jsonschema_test.go index 838d152a1..90fdc9b11 100644 --- a/pkg/chart/common/util/jsonschema_test.go +++ b/pkg/chart/common/util/jsonschema_test.go @@ -20,75 +20,47 @@ import ( "net/http" "net/http/httptest" "os" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" ) func TestValidateAgainstSingleSchema(t *testing.T) { values, err := common.ReadValuesFile("./testdata/test-values.yaml") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } - schema, err := os.ReadFile("./testdata/test-values.schema.json") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } + require.NoError(t, err, "Error reading YAML file") - if err := ValidateAgainstSingleSchema(values, schema); err != nil { - t.Errorf("Error validating Values against Schema: %s", err) - } + schema, err := os.ReadFile("./testdata/test-values.schema.json") + require.NoError(t, err, "Error reading YAML file") + assert.NoErrorf(t, ValidateAgainstSingleSchema(values, schema), "Error validating Values against Schema") } func TestValidateAgainstInvalidSingleSchema(t *testing.T) { values, err := common.ReadValuesFile("./testdata/test-values.yaml") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } - schema, err := os.ReadFile("./testdata/test-values-invalid.schema.json") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } + require.NoError(t, err, "Error reading YAML file") - var errString string - if err := ValidateAgainstSingleSchema(values, schema); err == nil { - t.Fatal("Expected an error, but got nil") - } else { - errString = err.Error() - } + schema, err := os.ReadFile("./testdata/test-values-invalid.schema.json") + require.NoError(t, err, "Error reading YAML file") expectedErrString := `"file:///values.schema.json#" is not valid against metaschema: jsonschema validation failed with 'https://json-schema.org/draft/2020-12/schema#' - at '': got number, want boolean or object` - if errString != expectedErrString { - t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) - } + assert.EqualError(t, ValidateAgainstSingleSchema(values, schema), expectedErrString) } func TestValidateAgainstSingleSchemaNegative(t *testing.T) { values, err := common.ReadValuesFile("./testdata/test-values-negative.yaml") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } - schema, err := os.ReadFile("./testdata/test-values.schema.json") - if err != nil { - t.Fatalf("Error reading JSON file: %s", err) - } + require.NoError(t, err, "Error reading YAML file") - var errString string - if err := ValidateAgainstSingleSchema(values, schema); err == nil { - t.Fatal("Expected an error, but got nil") - } else { - errString = err.Error() - } + schema, err := os.ReadFile("./testdata/test-values.schema.json") + require.NoError(t, err, "Error reading JSON file") expectedErrString := `- at '': missing property 'employmentInfo' - at '/age': minimum: got -5, want 0 ` - if errString != expectedErrString { - t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) - } + assert.EqualError(t, ValidateAgainstSingleSchema(values, schema), expectedErrString) } const subchartSchema = `{ @@ -145,9 +117,7 @@ func TestValidateAgainstSchema(t *testing.T) { }, } - if err := ValidateAgainstSchema(chrt, vals); err != nil { - t.Errorf("Error validating Values against Schema: %s", err) - } + assert.NoErrorf(t, ValidateAgainstSchema(chrt, vals), "Error validating Values against Schema") } func TestValidateAgainstSchemaNegative(t *testing.T) { @@ -170,19 +140,10 @@ func TestValidateAgainstSchemaNegative(t *testing.T) { "subchart": map[string]any{}, } - var errString string - if err := ValidateAgainstSchema(chrt, vals); err == nil { - t.Fatal("Expected an error, but got nil") - } else { - errString = err.Error() - } - expectedErrString := `subchart: - at '': missing property 'age' ` - if errString != expectedErrString { - t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) - } + assert.EqualError(t, ValidateAgainstSchema(chrt, vals), expectedErrString) } func TestValidateAgainstSchema2020(t *testing.T) { @@ -207,9 +168,7 @@ func TestValidateAgainstSchema2020(t *testing.T) { }, } - if err := ValidateAgainstSchema(chrt, vals); err != nil { - t.Errorf("Error validating Values against Schema: %s", err) - } + assert.NoErrorf(t, ValidateAgainstSchema(chrt, vals), "Error validating Values against Schema") } func TestValidateAgainstSchema2020Negative(t *testing.T) { @@ -234,20 +193,11 @@ func TestValidateAgainstSchema2020Negative(t *testing.T) { }, } - var errString string - if err := ValidateAgainstSchema(chrt, vals); err == nil { - t.Fatal("Expected an error, but got nil") - } else { - errString = err.Error() - } - expectedErrString := `subchart: - at '/data': no items match contains schema - at '/data/0': got number, want string ` - if errString != expectedErrString { - t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) - } + assert.EqualError(t, ValidateAgainstSchema(chrt, vals), expectedErrString) } func TestHTTPURLLoader_Load(t *testing.T) { @@ -262,12 +212,8 @@ func TestHTTPURLLoader_Load(t *testing.T) { loader := newHTTPURLLoader() result, err := loader.Load(server.URL) - if err != nil { - t.Fatalf("Expected no error, got: %v", err) - } - if result == nil { - t.Fatal("Expected result to be non-nil") - } + require.NoError(t, err, "Expected no error, got") + require.NotNil(t, result, "Expected result to be non-nil") }) t.Run("HTTP error status", func(t *testing.T) { @@ -278,12 +224,8 @@ func TestHTTPURLLoader_Load(t *testing.T) { loader := newHTTPURLLoader() _, err := loader.Load(server.URL) - if err == nil { - t.Fatal("Expected error for HTTP 404") - } - if !strings.Contains(err.Error(), "404") { - t.Errorf("Expected error message to contain '404', got: %v", err) - } + require.Error(t, err, "Expected error for HTTP 404") + assert.ErrorContains(t, err, "404", "Expected error message to contain '404'") }) } @@ -295,9 +237,7 @@ func TestValidateAgainstSingleSchema_UnresolvedURN_Ignored(t *testing.T) { "$ref": "urn:example:helm:schemas:v1:helm-schema-validation-conditions:v1/helmSchemaValidation-true" }`) vals := map[string]any{"any": "value"} - if err := ValidateAgainstSingleSchema(vals, schema); err != nil { - t.Fatalf("expected no error when URN unresolved is ignored, got: %v", err) - } + require.NoErrorf(t, ValidateAgainstSingleSchema(vals, schema), "expected no error when URN unresolved is ignored, got") } // Non-regression tests for https://github.com/helm/helm/issues/31202 @@ -323,14 +263,10 @@ func TestValidateAgainstSchema_MissingSubchartValues_NoPanic(t *testing.T) { } defer func() { - if r := recover(); r != nil { - t.Fatalf("ValidateAgainstSchema panicked (missing subchart values): %v", r) - } + require.Nilf(t, recover(), "ValidateAgainstSchema panicked (missing subchart values)") }() - if err := ValidateAgainstSchema(chrt, vals); err != nil { - t.Fatalf("expected no error when subchart values are missing, got: %v", err) - } + require.NoErrorf(t, ValidateAgainstSchema(chrt, vals), "expected no error when subchart values are missing, got") } func TestValidateAgainstSchema_SubchartNil_NoPanic(t *testing.T) { @@ -351,14 +287,10 @@ func TestValidateAgainstSchema_SubchartNil_NoPanic(t *testing.T) { } defer func() { - if r := recover(); r != nil { - t.Fatalf("ValidateAgainstSchema panicked (nil subchart values): %v", r) - } + require.Nilf(t, recover(), "ValidateAgainstSchema panicked (nil subchart values)") }() - if err := ValidateAgainstSchema(chrt, vals); err != nil { - t.Fatalf("expected no error when subchart values are nil, got: %v", err) - } + require.NoErrorf(t, ValidateAgainstSchema(chrt, vals), "expected no error when subchart values are nil, got") } func TestValidateAgainstSchema_InvalidSubchartValuesType_NoPanic(t *testing.T) { @@ -379,13 +311,9 @@ func TestValidateAgainstSchema_InvalidSubchartValuesType_NoPanic(t *testing.T) { } defer func() { - if r := recover(); r != nil { - t.Fatalf("ValidateAgainstSchema panicked (invalid subchart values type): %v", r) - } + require.Nilf(t, recover(), "ValidateAgainstSchema panicked (invalid subchart values type)") }() // We expect a non-nil error (invalid type), but crucially no panic. - if err := ValidateAgainstSchema(chrt, vals); err == nil { - t.Fatal("expected an error when subchart values have invalid type, got nil") - } + require.Error(t, ValidateAgainstSchema(chrt, vals), "expected an error when subchart values have invalid type, got nil") } diff --git a/pkg/chart/common/util/values_test.go b/pkg/chart/common/util/values_test.go index 1882fd0c4..e87a69237 100644 --- a/pkg/chart/common/util/values_test.go +++ b/pkg/chart/common/util/values_test.go @@ -20,6 +20,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" ) @@ -61,42 +64,26 @@ func TestToRenderValues(t *testing.T) { } res, err := ToRenderValuesWithSchemaValidation(c, overrideValues, o, nil, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Ensure that the top-level values are all set. metamap := res["Chart"].(map[string]any) - if name := metamap["Name"]; name.(string) != "test" { - t.Errorf("Expected chart name 'test', got %q", name) - } + name := metamap["Name"] + assert.Equalf(t, "test", name.(string), "Expected chart name 'test', got %q", name) relmap := res["Release"].(map[string]any) - if name := relmap["Name"]; name.(string) != "Seven Voyages" { - t.Errorf("Expected release name 'Seven Voyages', got %q", name) - } - if namespace := relmap["Namespace"]; namespace.(string) != "default" { - t.Errorf("Expected namespace 'default', got %q", namespace) - } - if revision := relmap["Revision"]; revision.(int) != 1 { - t.Errorf("Expected revision '1', got %d", revision) - } - if relmap["IsUpgrade"].(bool) { - t.Error("Expected upgrade to be false.") - } - if !relmap["IsInstall"].(bool) { - t.Error("Expected install to be true.") - } - if !res["Capabilities"].(*common.Capabilities).APIVersions.Has("v1") { - t.Error("Expected Capabilities to have v1 as an API") - } - if res["Capabilities"].(*common.Capabilities).KubeVersion.Major != "1" { - t.Error("Expected Capabilities to have a Kube version") - } + name = relmap["Name"] + assert.Equalf(t, "Seven Voyages", name.(string), "Expected release name 'Seven Voyages', got %q", name) + namespace := relmap["Namespace"] + assert.Equalf(t, "default", namespace.(string), "Expected namespace 'default', got %q", namespace) + revision := relmap["Revision"] + assert.Equalf(t, 1, revision.(int), "Expected revision '1', got %d", revision) + assert.False(t, relmap["IsUpgrade"].(bool), "Expected upgrade to be false.") + assert.True(t, relmap["IsInstall"].(bool), "Expected install to be true.") + assert.True(t, res["Capabilities"].(*common.Capabilities).APIVersions.Has("v1"), "Expected Capabilities to have v1 as an API") + assert.Equal(t, "1", res["Capabilities"].(*common.Capabilities).KubeVersion.Major, "Expected Capabilities to have a Kube version") vals := res["Values"].(common.Values) - if vals["name"] != "Haroun" { - t.Errorf("Expected 'Haroun', got %q (%v)", vals["name"], vals) - } + assert.Equal(t, "Haroun", vals["name"], "Expected 'Haroun', got %q (%v)", vals["name"], vals) where := vals["where"].(map[string]any) expects := map[string]string{ "city": "Baghdad", @@ -104,8 +91,7 @@ func TestToRenderValues(t *testing.T) { "title": "caliph", } for field, expect := range expects { - if got := where[field]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, where) - } + got := where[field] + assert.Equalf(t, got, expect, "Expected %q, got %q (%v)", expect, got, where) } } diff --git a/pkg/chart/common/values_test.go b/pkg/chart/common/values_test.go index 9743869ec..803513c32 100644 --- a/pkg/chart/common/values_test.go +++ b/pkg/chart/common/values_test.go @@ -21,6 +21,9 @@ import ( "fmt" "testing" "text/template" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestReadValues(t *testing.T) { @@ -46,29 +49,21 @@ water: ` data, err := ReadValues([]byte(doc)) - if err != nil { - t.Fatalf("Error parsing bytes: %s", err) - } + require.NoErrorf(t, err, "Error parsing bytes") matchValues(t, data) tests := []string{`poet: "Coleridge"`, "# Just a comment", ""} for _, tt := range tests { data, err = ReadValues([]byte(tt)) - if err != nil { - t.Fatalf("Error parsing bytes (%s): %s", tt, err) - } - if data == nil { - t.Errorf(`YAML string "%s" gave a nil map`, tt) - } + require.NoErrorf(t, err, "Error parsing bytes (%s)", tt) + require.NotNilf(t, data, `YAML string "%s" gave a nil map`, tt) } } func TestReadValuesFile(t *testing.T) { data, err := ReadValuesFile("./testdata/coleridge.yaml") - if err != nil { - t.Fatalf("Error reading YAML file: %s", err) - } + require.NoErrorf(t, err, "Error reading YAML file") matchValues(t, data) } @@ -108,56 +103,40 @@ chapter: title: "The Spouter Inn" ` d, err := ReadValues([]byte(doc)) - if err != nil { - t.Fatalf("Failed to parse the White Whale: %s", err) - } + require.NoErrorf(t, err, "Failed to parse the White Whale") - if _, err := d.Table("title"); err == nil { - t.Fatal("Title is not a table.") - } + _, err = d.Table("title") + require.Error(t, err, "Title is not a table.") - if _, err := d.Table("chapter"); err != nil { - t.Fatalf("Failed to get the chapter table: %s\n%v", err, d) - } + _, err = d.Table("chapter") + require.NoErrorf(t, err, "Failed to get the chapter table: %v", d) - if v, err := d.Table("chapter.one"); err != nil { - t.Errorf("Failed to get chapter.one: %s", err) - } else if v["title"] != "Loomings" { - t.Errorf("Unexpected title: %s", v["title"]) - } + v, err := d.Table("chapter.one") + require.NoErrorf(t, err, "Failed to get chapter.one") + assert.Equalf(t, "Loomings", v["title"], "Unexpected title: %s", v["title"]) - if _, err := d.Table("chapter.three"); err != nil { - t.Errorf("Chapter three is missing: %s\n%v", err, d) - } + _, err = d.Table("chapter.three") + require.NoErrorf(t, err, "Chapter three is missing: %v", d) - if _, err := d.Table("chapter.OneHundredThirtySix"); err == nil { - t.Error("I think you mean 'Epilogue'") - } + _, err = d.Table("chapter.OneHundredThirtySix") + assert.Error(t, err, "I think you mean 'Epilogue'") } func matchValues(t *testing.T, data map[string]any) { t.Helper() - if data["poet"] != "Coleridge" { - t.Errorf("Unexpected poet: %s", data["poet"]) - } + assert.Equalf(t, "Coleridge", data["poet"], "Unexpected poet: %s", data["poet"]) - if o, err := ttpl("{{len .stanza}}", data); err != nil { - t.Errorf("len stanza: %s", err) - } else if o != "6" { - t.Errorf("Expected 6, got %s", o) - } + o, err := ttpl("{{len .stanza}}", data) + require.NoErrorf(t, err, "len stanza") + assert.Equalf(t, "6", o, "Expected 6, got %s", o) - if o, err := ttpl("{{.mariner.shot}}", data); err != nil { - t.Errorf(".mariner.shot: %s", err) - } else if o != "ALBATROSS" { - t.Error("Expected that mariner shot ALBATROSS") - } + o, err = ttpl("{{.mariner.shot}}", data) + require.NoErrorf(t, err, ".mariner.shot") + assert.Equal(t, "ALBATROSS", o, "Expected that mariner shot ALBATROSS") - if o, err := ttpl("{{.water.water.where}}", data); err != nil { - t.Errorf(".water.water.where: %s", err) - } else if o != "everywhere" { - t.Error("Expected water water everywhere") - } + o, err = ttpl("{{.water.water.where}}", data) + require.NoErrorf(t, err, ".water.water.where") + assert.Equal(t, "everywhere", o, "Expected water water everywhere") } func ttpl(tpl string, v map[string]any) (string, error) { @@ -179,27 +158,18 @@ chapter: title: "The Spouter Inn" ` d, err := ReadValues([]byte(doc)) - if err != nil { - t.Fatalf("Failed to parse the White Whale: %s", err) - } - - if v, err := d.PathValue("chapter.one.title"); err != nil { - t.Errorf("Got error instead of title: %s\n%v", err, d) - } else if v != "Loomings" { - t.Errorf("No error but got wrong value for title: %s\n%v", err, d) - } - if _, err := d.PathValue("chapter.one.doesnotexist"); err == nil { - t.Errorf("Non-existent key should return error: %s\n%v", err, d) - } - if _, err := d.PathValue("chapter.doesnotexist.one"); err == nil { - t.Errorf("Non-existent key in middle of path should return error: %s\n%v", err, d) - } - if _, err := d.PathValue(""); err == nil { - t.Error("Asking for the value from an empty path should yield an error") - } - if v, err := d.PathValue("title"); err == nil { - if v != "Moby Dick" { - t.Error("Failed to return values for root key title") - } - } + require.NoErrorf(t, err, "Failed to parse the White Whale") + + v, err := d.PathValue("chapter.one.title") + require.NoErrorf(t, err, "Got error instead of title: %v", d) + assert.Equalf(t, "Loomings", v, "No error but got wrong value for title: %v", d) + _, err = d.PathValue("chapter.one.doesnotexist") + require.Errorf(t, err, "Non-existent key should return error: %v", d) + _, err = d.PathValue("chapter.doesnotexist.one") + require.Errorf(t, err, "Non-existent key in middle of path should return error: %v", d) + _, err = d.PathValue("") + require.Error(t, err, "Asking for the value from an empty path should yield an error") + v, err = d.PathValue("title") + require.NoErrorf(t, err, "Failed to get title: %v", d) + assert.Equalf(t, "Moby Dick", v, "Failed to return values for root key title: got %s\n%v", v, d) } diff --git a/pkg/chart/loader/archive/archive_test.go b/pkg/chart/loader/archive/archive_test.go index 2fe09e9b2..3c3d336c3 100644 --- a/pkg/chart/loader/archive/archive_test.go +++ b/pkg/chart/loader/archive/archive_test.go @@ -21,6 +21,8 @@ import ( "bytes" "compress/gzip" "testing" + + "github.com/stretchr/testify/require" ) func TestLoadArchiveFiles(t *testing.T) { @@ -34,9 +36,7 @@ func TestLoadArchiveFiles(t *testing.T) { generate: func(_ *tar.Writer) {}, check: func(t *testing.T, _ []*BufferedFile, err error) { t.Helper() - if err.Error() != "no files in chart archive" { - t.Fatalf(`expected "no files in chart archive", got [%#v]`, err) - } + require.EqualError(t, err, "no files in chart archive") }, }, { @@ -44,32 +44,21 @@ func TestLoadArchiveFiles(t *testing.T) { generate: func(w *tar.Writer) { // simulate the presence of a `pax_global_header` file like you would get when // processing a GitHub release archive. - err := w.WriteHeader(&tar.Header{ + require.NoError(t, w.WriteHeader(&tar.Header{ Typeflag: tar.TypeXGlobalHeader, Name: "pax_global_header", - }) - if err != nil { - t.Fatal(err) - } + })) // we need to have at least one file, otherwise we'll get the "no files in chart archive" error - err = w.WriteHeader(&tar.Header{ + require.NoError(t, w.WriteHeader(&tar.Header{ Typeflag: tar.TypeReg, Name: "dir/empty", - }) - if err != nil { - t.Fatal(err) - } + })) }, check: func(t *testing.T, files []*BufferedFile, err error) { t.Helper() - if err != nil { - t.Fatalf(`got unwanted error [%#v] for tar file with pax_global_header content`, err) - } - - if len(files) != 1 { - t.Fatalf(`expected to get one file but got [%v]`, files) - } + require.NoErrorf(t, err, `got unwanted error for tar file with pax_global_header content`) + require.Lenf(t, files, 1, `expected to get one file but got [%v]`, files) }, }, } diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go index a42861eac..3834fad7a 100644 --- a/pkg/chart/loader/load_test.go +++ b/pkg/chart/loader/load_test.go @@ -24,10 +24,12 @@ import ( "io" "maps" "path/filepath" - "strings" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + c3 "helm.sh/helm/v4/internal/chart/v3" "helm.sh/helm/v4/pkg/chart" c2 "helm.sh/helm/v4/pkg/chart/v2" @@ -59,20 +61,13 @@ description: A test chart Size: int64(len(data)), ModTime: time.Now(), } - if err := tw.WriteHeader(header); err != nil { - t.Fatalf("Failed to write tar header for %s: %v", name, err) - } - if _, err := tw.Write(data); err != nil { - t.Fatalf("Failed to write tar data for %s: %v", name, err) - } + require.NoErrorf(t, tw.WriteHeader(header), "Failed to write tar header for %s", name) + _, err := tw.Write(data) + require.NoErrorf(t, err, "Failed to write tar data for %s", name) } - if err := tw.Close(); err != nil { - t.Fatalf("Failed to close tar writer: %v", err) - } - if err := gw.Close(); err != nil { - t.Fatalf("Failed to close gzip writer: %v", err) - } + require.NoErrorf(t, tw.Close(), "Failed to close tar writer") + require.NoErrorf(t, gw.Close(), "Failed to close gzip writer") return &buf } @@ -149,37 +144,26 @@ func TestLoadArchive(t *testing.T) { loadedChart, err := LoadArchive(reader) if tc.expectedError != "" { - if err == nil || !strings.Contains(err.Error(), tc.expectedError) { - t.Errorf("Expected error containing %q, but got %v", tc.expectedError, err) - } - return - } + require.Errorf(t, err, "Expected error containing %q, but got no error", tc.expectedError) + assert.ErrorContains(t, err, tc.expectedError) + } else { + require.NoError(t, err) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - lac, err := chart.NewAccessor(loadedChart) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - eac, err := chart.NewAccessor(tc.expectedChart) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } + lac, err := chart.NewAccessor(loadedChart) + require.NoError(t, err) - if lac.Name() != eac.Name() { - t.Errorf("Expected chart name %q, got %q", eac.Name(), lac.Name()) - } + eac, err := chart.NewAccessor(tc.expectedChart) + require.NoError(t, err) + assert.Equalf(t, lac.Name(), eac.Name(), "Expected chart name %q, got %q", eac.Name(), lac.Name()) - var loadedAPIVersion string - switch lc := loadedChart.(type) { - case *c2.Chart: - loadedAPIVersion = lc.Metadata.APIVersion - case *c3.Chart: - loadedAPIVersion = lc.Metadata.APIVersion - } - if loadedAPIVersion != tc.apiVersion { - t.Errorf("Expected API version %q, got %q", tc.apiVersion, loadedAPIVersion) + var loadedAPIVersion string + switch lc := loadedChart.(type) { + case *c2.Chart: + loadedAPIVersion = lc.Metadata.APIVersion + case *c3.Chart: + loadedAPIVersion = lc.Metadata.APIVersion + } + assert.Equalf(t, loadedAPIVersion, tc.apiVersion, "Expected API version %q, got %q", tc.apiVersion, loadedAPIVersion) } }) } diff --git a/pkg/chart/v2/chart_test.go b/pkg/chart/v2/chart_test.go index 813669366..313d65480 100644 --- a/pkg/chart/v2/chart_test.go +++ b/pkg/chart/v2/chart_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" ) @@ -76,15 +77,12 @@ func TestSaveChartNoRawData(t *testing.T) { } is := assert.New(t) + req := require.New(t) data, err := json.Marshal(chrt) - if err != nil { - t.Fatal(err) - } + req.NoError(err) res := &Chart{} - if err := json.Unmarshal(data, res); err != nil { - t.Fatal(err) - } + req.NoError(json.Unmarshal(data, res)) is.Equal([]*common.File(nil), res.Raw) } diff --git a/pkg/chart/v2/dependency_test.go b/pkg/chart/v2/dependency_test.go index 35919bd7a..f44a6b06f 100644 --- a/pkg/chart/v2/dependency_test.go +++ b/pkg/chart/v2/dependency_test.go @@ -17,6 +17,8 @@ package v2 import ( "testing" + + "github.com/stretchr/testify/require" ) func TestValidateDependency(t *testing.T) { @@ -35,10 +37,10 @@ func TestValidateDependency(t *testing.T) { } { dep.Alias = value res := dep.Validate() - if res != nil && !shouldFail { - t.Errorf("Failed on case %q", dep.Alias) - } else if res == nil && shouldFail { - t.Errorf("Expected failure for %q", dep.Alias) + if shouldFail { + require.Errorf(t, res, "Expected failure for %q", dep.Alias) + } else { + require.NoErrorf(t, res, "Failed on case %q", dep.Alias) } } } diff --git a/pkg/chart/v2/lint/lint.go b/pkg/chart/v2/lint/lint.go index 23a93c551..204c15861 100644 --- a/pkg/chart/v2/lint/lint.go +++ b/pkg/chart/v2/lint/lint.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package lint // import "helm.sh/helm/v4/pkg/chart/v2/lint" +package lint import ( "path/filepath" diff --git a/pkg/chart/v2/lint/lint_test.go b/pkg/chart/v2/lint/lint_test.go index 85960131b..c4705872d 100644 --- a/pkg/chart/v2/lint/lint_test.go +++ b/pkg/chart/v2/lint/lint_test.go @@ -97,40 +97,28 @@ func TestBadChart(t *testing.T) { func TestInvalidYaml(t *testing.T) { var values map[string]any m := RunAll(badYamlFileDir, values, namespace).Messages - if len(m) != 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "deliberateSyntaxError") { - t.Error("All didn't have the error for deliberateSyntaxError") - } + require.Len(t, m, 1, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "deliberateSyntaxError", "All didn't have the error for deliberateSyntaxError") } func TestInvalidChartYaml(t *testing.T) { var values map[string]any m := RunAll(invalidChartFileDir, values, namespace).Messages - if len(m) != 2 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "failed to strictly parse chart metadata file") { - t.Error("All didn't have the error for duplicate YAML keys") - } + require.Len(t, m, 2, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "failed to strictly parse chart metadata file", "All didn't have the error for duplicate YAML keys") } func TestBadValues(t *testing.T) { var values map[string]any m := RunAll(badValuesFileDir, values, namespace).Messages - if len(m) < 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "unable to parse YAML") { - t.Errorf("All didn't have the error for invalid key format: %s", m[0].Err) - } + require.GreaterOrEqualf(t, len(m), 1, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "unable to parse YAML", "All didn't have the error for invalid key format: %s", m[0].Err) } func TestBadCrdFile(t *testing.T) { var values map[string]any m := RunAll(badCrdFileDir, values, namespace).Messages - assert.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) + require.Lenf(t, m, 2, "All didn't fail with expected errors, got %#v", m) require.ErrorContains(t, m[0].Err, "apiVersion is not in 'apiextensions.k8s.io'") assert.ErrorContains(t, m[1].Err, "object kind is not 'CustomResourceDefinition'") } @@ -138,8 +126,7 @@ func TestBadCrdFile(t *testing.T) { func TestGoodChart(t *testing.T) { var values map[string]any m := RunAll(goodChartDir, values, namespace).Messages - if len(m) != 0 { - t.Error("All returned linter messages when it shouldn't have") + if !assert.Empty(t, m, "All returned linter messages when it shouldn't have") { for i, msg := range m { t.Logf("Message %d: %s", i, msg) } @@ -154,22 +141,17 @@ func TestHelmCreateChart(t *testing.T) { dir := t.TempDir() createdChart, err := chartutil.Create("testhelmcreatepasseslint", dir) - if err != nil { - t.Error(err) - // Fatal is bad because of the defer. - return - } + require.NoError(t, err) // Note: we test with strict=true here, even though others have // strict = false. m := RunAll(createdChart, values, namespace, WithSkipSchemaValidation(true)).Messages - if ll := len(m); ll != 1 { - t.Errorf("All should have had exactly 1 error. Got %d", ll) + if !assert.Len(t, m, 1, "All should have had exactly 1 error") { for i, msg := range m { t.Logf("Message %d: %s", i, msg.Error()) } - } else if msg := m[0].Err.Error(); !strings.Contains(msg, "icon is recommended") { - t.Errorf("Unexpected lint error: %s", msg) + } else { + assert.ErrorContains(t, m[0].Err, "icon is recommended") } } @@ -182,10 +164,7 @@ func TestHelmCreateChart(t *testing.T) { // of the `--set` flag. func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) { createdChart, err := chartutil.Create("checkdeprecatedwarnings", t.TempDir()) - if err != nil { - t.Error(err) - return - } + require.NoError(t, err) // Add values to enable hpa, and ingress which are disabled by default. // This is the equivalent of: @@ -215,8 +194,7 @@ func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) { func TestSubChartValuesChart(t *testing.T) { var values map[string]any m := RunAll(subChartValuesDir, values, namespace).Messages - if len(m) != 0 { - t.Error("All returned linter messages when it shouldn't have") + if !assert.Empty(t, m, "All returned linter messages when it shouldn't have") { for i, msg := range m { t.Logf("Message %d: %s", i, msg) } @@ -238,11 +216,7 @@ func TestMalformedTemplate(t *testing.T) { case <-c: t.Fatal("lint malformed template timeout") case <-ch: - if len(m) != 1 { - t.Fatalf("All didn't fail with expected errors, got %#v", m) - } - if !strings.Contains(m[0].Err.Error(), "invalid character '{'") { - t.Error("All didn't have the error for invalid character '{'") - } + require.Len(t, m, 1, "All didn't fail with expected errors, got %#v", m) + assert.ErrorContains(t, m[0].Err, "invalid character '{'", "All didn't have the error for invalid character '{'") } } diff --git a/pkg/chart/v2/lint/rules/chartfile.go b/pkg/chart/v2/lint/rules/chartfile.go index 08508f46e..f867daa21 100644 --- a/pkg/chart/v2/lint/rules/chartfile.go +++ b/pkg/chart/v2/lint/rules/chartfile.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" +package rules import ( "errors" diff --git a/pkg/chart/v2/lint/rules/chartfile_test.go b/pkg/chart/v2/lint/rules/chartfile_test.go index c9e202770..1cc331a74 100644 --- a/pkg/chart/v2/lint/rules/chartfile_test.go +++ b/pkg/chart/v2/lint/rules/chartfile_test.go @@ -20,9 +20,11 @@ import ( "errors" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/lint/support" chartutil "helm.sh/helm/v4/pkg/chart/v2/util" @@ -47,35 +49,17 @@ var badChartName, _ = chartutil.LoadChartfile(badChartNamePath) func TestValidateChartYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingChartFilePath, os.ModePerm) defer os.Remove(nonExistingChartFilePath) - - err := validateChartYamlNotDirectory(nonExistingChartFilePath) - if err == nil { - t.Error("validateChartYamlNotDirectory to return a linter error, got no error") - } + assert.Error(t, validateChartYamlNotDirectory(nonExistingChartFilePath), "validateChartYamlNotDirectory to return a linter error, got no error") } func TestValidateChartYamlFormat(t *testing.T) { - err := validateChartYamlFormat(errors.New("Read error")) - if err == nil { - t.Error("validateChartYamlFormat to return a linter error, got no error") - } - - err = validateChartYamlFormat(nil) - if err != nil { - t.Error("validateChartYamlFormat to return no error, got a linter error") - } + require.Error(t, validateChartYamlFormat(errors.New("Read error")), "validateChartYamlFormat to return a linter error, got no error") + assert.NoError(t, validateChartYamlFormat(nil), "validateChartYamlFormat to return no error, got a linter error") } func TestValidateChartName(t *testing.T) { - err := validateChartName(badChart) - if err == nil { - t.Error("validateChartName to return a linter error, got no error") - } - - err = validateChartName(badChartName) - if err == nil { - t.Error("expected validateChartName to return a linter error for an invalid name, got no error") - } + require.Error(t, validateChartName(badChart), "validateChartName to return a linter error, got no error") + assert.Error(t, validateChartName(badChartName), "expected validateChartName to return a linter error for an invalid name, got no error") } func TestValidateChartVersion(t *testing.T) { @@ -93,18 +77,12 @@ func TestValidateChartVersion(t *testing.T) { for _, test := range failTest { badChart.Version = test.Version - err := validateChartVersion(badChart) - if err == nil || !strings.Contains(err.Error(), test.ErrorMsg) { - t.Errorf("validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) - } + require.ErrorContainsf(t, validateChartVersion(badChart), test.ErrorMsg, "validateChartVersion(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) } for _, version := range successTest { badChart.Version = version - err := validateChartVersion(badChart) - if err != nil { - t.Errorf("validateChartVersion(%s) to return no error, got a linter error", version) - } + assert.NoError(t, validateChartVersion(badChart), "validateChartVersion(%s) to return no error, got a linter error", version) } } @@ -122,18 +100,12 @@ func TestValidateChartVersionStrictSemVerV2(t *testing.T) { for _, test := range failTest { badChart.Version = test.Version - err := validateChartVersionStrictSemVerV2(badChart) - if err == nil || !strings.Contains(err.Error(), test.ErrorMsg) { - t.Errorf("validateChartVersionStrictSemVerV2(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) - } + require.ErrorContainsf(t, validateChartVersionStrictSemVerV2(badChart), test.ErrorMsg, "validateChartVersionStrictSemVerV2(%s) to return \"%s\", got no error", test.Version, test.ErrorMsg) } for _, version := range successTest { badChart.Version = version - err := validateChartVersionStrictSemVerV2(badChart) - if err != nil { - t.Errorf("validateChartVersionStrictSemVerV2(%s) to return no error, got a linter error", version) - } + assert.NoError(t, validateChartVersionStrictSemVerV2(badChart), "validateChartVersionStrictSemVerV2(%s) to return no error, got a linter error", version) } } @@ -158,29 +130,17 @@ func TestValidateChartMaintainer(t *testing.T) { for _, test := range failTest { badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - if err == nil || !strings.Contains(err.Error(), test.ErrorMsg) { - t.Errorf("validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) - } + require.ErrorContainsf(t, validateChartMaintainer(badChart), test.ErrorMsg, "validateChartMaintainer(%s, %s) to return \"%s\", got no error", test.Name, test.Email, test.ErrorMsg) } for _, test := range successTest { badChart.Maintainers = []*chart.Maintainer{{Name: test.Name, Email: test.Email}} - err := validateChartMaintainer(badChart) - if err != nil { - t.Errorf("validateChartMaintainer(%s, %s) to return no error, got %s", test.Name, test.Email, err.Error()) - } + require.NoError(t, validateChartMaintainer(badChart), "validateChartMaintainer(%s, %s)", test.Name, test.Email) } // Testing for an empty maintainer badChart.Maintainers = []*chart.Maintainer{nil} - err := validateChartMaintainer(badChart) - if err == nil { - t.Error("validateChartMaintainer did not return error for nil maintainer as expected") - } - if err.Error() != "a maintainer entry is empty" { - t.Errorf("validateChartMaintainer returned unexpected error for nil maintainer: %s", err.Error()) - } + assert.EqualError(t, validateChartMaintainer(badChart), "a maintainer entry is empty") } func TestValidateChartSources(t *testing.T) { @@ -188,18 +148,12 @@ func TestValidateChartSources(t *testing.T) { var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish"} for _, test := range failTest { badChart.Sources = []string{test} - err := validateChartSources(badChart) - if err == nil || !strings.Contains(err.Error(), "invalid source URL") { - t.Errorf("validateChartSources(%s) to return \"invalid source URL\", got no error", test) - } + require.ErrorContainsf(t, validateChartSources(badChart), "invalid source URL", "validateChartSources(%s) to return \"invalid source URL\", got no error", test) } for _, test := range successTest { badChart.Sources = []string{test} - err := validateChartSources(badChart) - if err != nil { - t.Errorf("validateChartSources(%s) to return no error, got %s", test, err.Error()) - } + assert.NoError(t, validateChartSources(badChart), "validateChartSources(%s) to return no error", test) } } @@ -209,24 +163,13 @@ func TestValidateChartIconPresence(t *testing.T) { Icon: "", } - err := validateChartIconPresence(testChart) - - if err == nil { - t.Error("validateChartIconPresence to return a linter error, got no error") - } else if !strings.Contains(err.Error(), "icon is recommended") { - t.Errorf("expected %q, got %q", "icon is recommended", err.Error()) - } + assert.ErrorContainsf(t, validateChartIconPresence(testChart), "icon is recommended", "expected %q", "icon is recommended") }) t.Run("Icon present", func(t *testing.T) { testChart := &chart.Metadata{ Icon: "http://example.org/icon.png", } - - err := validateChartIconPresence(testChart) - - if err != nil { - t.Errorf("Unexpected error: %q", err.Error()) - } + assert.NoError(t, validateChartIconPresence(testChart)) }) } @@ -235,18 +178,12 @@ func TestValidateChartIconURL(t *testing.T) { var successTest = []string{"http://riverrun.io", "https://riverrun.io", "https://riverrun.io/blackfish.png"} for _, test := range failTest { badChart.Icon = test - err := validateChartIconURL(badChart) - if err == nil || !strings.Contains(err.Error(), "invalid icon URL") { - t.Errorf("validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) - } + require.ErrorContainsf(t, validateChartIconURL(badChart), "invalid icon URL", "validateChartIconURL(%s) to return \"invalid icon URL\", got no error", test) } for _, test := range successTest { badChart.Icon = test - err := validateChartSources(badChart) - if err != nil { - t.Errorf("validateChartIconURL(%s) to return no error, got %s", test, err.Error()) - } + assert.NoError(t, validateChartSources(badChart), "validateChartIconURL(%s) to return no error", test) } } @@ -257,37 +194,14 @@ func TestChartfile(t *testing.T) { msgs := linter.Messages expectedNumberOfErrorMessages := 7 - if len(msgs) != expectedNumberOfErrorMessages { - t.Errorf("Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) - return - } - - if !strings.Contains(msgs[0].Err.Error(), "name is required") { - t.Errorf("Unexpected message 0: %s", msgs[0].Err) - } - - if !strings.Contains(msgs[1].Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { - t.Errorf("Unexpected message 1: %s", msgs[1].Err) - } - - if !strings.Contains(msgs[2].Err.Error(), "version '0.0.0.0' is not a valid SemVer") { - t.Errorf("Unexpected message 2: %s", msgs[2].Err) - } - - if !strings.Contains(msgs[3].Err.Error(), "icon is recommended") { - t.Errorf("Unexpected message 3: %s", msgs[3].Err) - } - - if !strings.Contains(msgs[4].Err.Error(), "chart type is not valid in apiVersion") { - t.Errorf("Unexpected message 4: %s", msgs[4].Err) - } - - if !strings.Contains(msgs[5].Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { - t.Errorf("Unexpected message 5: %s", msgs[5].Err) - } - if !strings.Contains(msgs[6].Err.Error(), "version '0.0.0.0' is not a valid SemVerV2") { - t.Errorf("Unexpected message 6: %s", msgs[6].Err) - } + require.Lenf(t, msgs, expectedNumberOfErrorMessages, "Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) + require.ErrorContains(t, msgs[0].Err, "name is required", "Unexpected message 0: %s", msgs[0].Err) + require.ErrorContains(t, msgs[1].Err, "apiVersion is required. The value must be either \"v1\" or \"v2\"", "Unexpected message 1: %s", msgs[1].Err) + require.ErrorContains(t, msgs[2].Err, "version '0.0.0.0' is not a valid SemVer", "Unexpected message 2: %s", msgs[2].Err) + require.ErrorContains(t, msgs[3].Err, "icon is recommended", "Unexpected message 3: %s", msgs[3].Err) + require.ErrorContains(t, msgs[4].Err, "chart type is not valid in apiVersion", "Unexpected message 4: %s", msgs[4].Err) + require.ErrorContains(t, msgs[5].Err, "dependencies are not valid in the Chart file with apiVersion", "Unexpected message 5: %s", msgs[5].Err) + assert.ErrorContains(t, msgs[6].Err, "version '0.0.0.0' is not a valid SemVerV2", "Unexpected message 6: %s", msgs[6].Err) }) t.Run("Chart.yaml validity issues due to type mismatch", func(t *testing.T) { @@ -296,24 +210,10 @@ func TestChartfile(t *testing.T) { msgs := linter.Messages expectedNumberOfErrorMessages := 4 - if len(msgs) != expectedNumberOfErrorMessages { - t.Errorf("Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) - return - } - - if !strings.Contains(msgs[0].Err.Error(), "version should be of type string") { - t.Errorf("Unexpected message 0: %s", msgs[0].Err) - } - - if !strings.Contains(msgs[1].Err.Error(), "version '7.2445e+06' is not a valid SemVer") { - t.Errorf("Unexpected message 1: %s", msgs[1].Err) - } - - if !strings.Contains(msgs[2].Err.Error(), "appVersion should be of type string") { - t.Errorf("Unexpected message 2: %s", msgs[2].Err) - } - if !strings.Contains(msgs[3].Err.Error(), "version '7.2445e+06' is not a valid SemVerV2") { - t.Errorf("Unexpected message 3: %s", msgs[3].Err) - } + require.Len(t, msgs, expectedNumberOfErrorMessages, "Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) + require.ErrorContains(t, msgs[0].Err, "version should be of type string", "Unexpected message 0: %s", msgs[0].Err) + require.ErrorContains(t, msgs[1].Err, "version '7.2445e+06' is not a valid SemVer", "Unexpected message 1: %s", msgs[1].Err) + require.ErrorContains(t, msgs[2].Err, "appVersion should be of type string", "Unexpected message 2: %s", msgs[2].Err) + assert.ErrorContains(t, msgs[3].Err, "version '7.2445e+06' is not a valid SemVerV2", "Unexpected message 3: %s", msgs[3].Err) }) } diff --git a/pkg/chart/v2/lint/rules/crds_test.go b/pkg/chart/v2/lint/rules/crds_test.go index 7016c4d9a..d0790692f 100644 --- a/pkg/chart/v2/lint/rules/crds_test.go +++ b/pkg/chart/v2/lint/rules/crds_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/v2/lint/support" ) @@ -33,7 +34,7 @@ func TestInvalidCrdsDir(t *testing.T) { Crds(&linter) res := linter.Messages - assert.Len(t, res, 1) + require.Len(t, res, 1) assert.ErrorContains(t, res[0].Err, "not a directory") } diff --git a/pkg/chart/v2/lint/rules/dependencies.go b/pkg/chart/v2/lint/rules/dependencies.go index d944a016d..616984c08 100644 --- a/pkg/chart/v2/lint/rules/dependencies.go +++ b/pkg/chart/v2/lint/rules/dependencies.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" +package rules import ( "fmt" diff --git a/pkg/chart/v2/lint/rules/dependencies_test.go b/pkg/chart/v2/lint/rules/dependencies_test.go index c50fc4b2d..4bd7b3e37 100644 --- a/pkg/chart/v2/lint/rules/dependencies_test.go +++ b/pkg/chart/v2/lint/rules/dependencies_test.go @@ -19,6 +19,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/lint/support" chartutil "helm.sh/helm/v4/pkg/chart/v2/util" @@ -62,18 +65,12 @@ func chartWithBadDependencies() chart.Chart { func TestValidateDependencyInChartsDir(t *testing.T) { c := chartWithBadDependencies() - - if err := validateDependencyInChartsDir(&c); err == nil { - t.Error("chart should have been flagged for missing deps in chart directory") - } + assert.Error(t, validateDependencyInChartsDir(&c), "chart should have been flagged for missing deps in chart directory") } func TestValidateDependencyInMetadata(t *testing.T) { c := chartWithBadDependencies() - - if err := validateDependencyInMetadata(&c); err == nil { - t.Error("chart should have been flagged for missing deps in chart metadata") - } + assert.Error(t, validateDependencyInMetadata(&c), "chart should have been flagged for missing deps in chart metadata") } func TestValidateDependenciesUnique(t *testing.T) { @@ -131,9 +128,7 @@ func TestValidateDependenciesUnique(t *testing.T) { } for _, tt := range tests { - if err := validateDependenciesUnique(&tt.chart); err == nil { - t.Error("chart should have been flagged for dependency shadowing") - } + assert.Error(t, validateDependenciesUnique(&tt.chart), "chart should have been flagged for dependency shadowing") } } @@ -141,15 +136,11 @@ func TestDependencies(t *testing.T) { tmp := t.TempDir() c := chartWithBadDependencies() - err := chartutil.SaveDir(&c, tmp) - if err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&c, tmp)) linter := support.Linter{ChartDir: filepath.Join(tmp, c.Metadata.Name)} Dependencies(&linter) - if l := len(linter.Messages); l != 2 { - t.Errorf("expected 2 linter errors for bad chart dependencies. Got %d.", l) + if !assert.Len(t, linter.Messages, 2, "expected 2 linter errors for bad chart dependencies") { for i, msg := range linter.Messages { t.Logf("Message: %d, Error: %#v", i, msg) } diff --git a/pkg/chart/v2/lint/rules/deprecations.go b/pkg/chart/v2/lint/rules/deprecations.go index 76626659b..2ed682891 100644 --- a/pkg/chart/v2/lint/rules/deprecations.go +++ b/pkg/chart/v2/lint/rules/deprecations.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" +package rules import ( "fmt" diff --git a/pkg/chart/v2/lint/rules/deprecations_test.go b/pkg/chart/v2/lint/rules/deprecations_test.go index 86643f1c9..3c8553cce 100644 --- a/pkg/chart/v2/lint/rules/deprecations_test.go +++ b/pkg/chart/v2/lint/rules/deprecations_test.go @@ -14,9 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rules // import "helm.sh/helm/v4/pkg/chart/v2/lint/rules" +package rules -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) func TestValidateNoDeprecations(t *testing.T) { deprecated := &k8sYamlStruct{ @@ -24,18 +29,13 @@ func TestValidateNoDeprecations(t *testing.T) { Kind: "Deployment", } err := validateNoDeprecations(deprecated, nil) - if err == nil { - t.Fatal("Expected deprecated extension to be flagged") - } - depErr := err.(deprecatedAPIError) - if depErr.Message == "" { - t.Fatalf("Expected error message to be non-blank: %v", err) - } + require.Error(t, err, "Expected deprecated extension to be flagged") + var depErr deprecatedAPIError + require.ErrorAs(t, err, &depErr) + require.NotEmptyf(t, depErr.Message, "Expected error message to be non-blank") - if err := validateNoDeprecations(&k8sYamlStruct{ + assert.NoError(t, validateNoDeprecations(&k8sYamlStruct{ APIVersion: "v1", Kind: "Pod", - }, nil); err != nil { - t.Error("Expected a v1 Pod to not be deprecated") - } + }, nil), "Expected a v1 Pod to not be deprecated") } diff --git a/pkg/chart/v2/lint/rules/template_test.go b/pkg/chart/v2/lint/rules/template_test.go index f0eb008b3..ab78450b9 100644 --- a/pkg/chart/v2/lint/rules/template_test.go +++ b/pkg/chart/v2/lint/rules/template_test.go @@ -20,10 +20,12 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/lint/support" @@ -35,17 +37,11 @@ const templateTestBasedir = "./testdata/albatross" func TestValidateAllowedExtension(t *testing.T) { var failTest = []string{"/foo", "/test.toml"} for _, test := range failTest { - err := validateAllowedExtension(test) - if err == nil || !strings.Contains(err.Error(), "Valid extensions are .yaml, .yml, .tpl, or .txt") { - t.Errorf("validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) - } + require.ErrorContainsf(t, validateAllowedExtension(test), "Valid extensions are .yaml, .yml, .tpl, or .txt", "validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { - err := validateAllowedExtension(test) - if err != nil { - t.Errorf("validateAllowedExtension('%s') to return no error but got \"%s\"", test, err.Error()) - } + assert.NoError(t, validateAllowedExtension(test), "validateAllowedExtension('%s') to return no error", test) } } @@ -62,13 +58,8 @@ func TestTemplateParsing(t *testing.T) { TemplateLinterSkipSchemaValidation(false)) res := linter.Messages - if len(res) != 1 { - t.Fatalf("Expected one error, got %d, %v", len(res), res) - } - - if !strings.Contains(res[0].Err.Error(), "deliberateSyntaxError") { - t.Errorf("Unexpected error: %s", res[0]) - } + require.Len(t, res, 1, "Expected one error, got %d, %v", len(res), res) + assert.ErrorContains(t, res[0].Err, "deliberateSyntaxError") } var wrongTemplatePath = filepath.Join(templateTestBasedir, "templates", "fail.yaml") @@ -89,9 +80,7 @@ func TestTemplateIntegrationHappyPath(t *testing.T) { TemplateLinterSkipSchemaValidation(false)) res := linter.Messages - if len(res) != 0 { - t.Fatalf("Expected no error, got %d, %v", len(res), res) - } + require.Empty(t, res, "Expected no error, got %d, %v", len(res), res) } func TestMultiTemplateFail(t *testing.T) { @@ -103,13 +92,8 @@ func TestMultiTemplateFail(t *testing.T) { TemplateLinterSkipSchemaValidation(false)) res := linter.Messages - if len(res) != 1 { - t.Fatalf("Expected 1 error, got %d, %v", len(res), res) - } - - if !strings.Contains(res[0].Err.Error(), "object name does not conform to Kubernetes naming requirements") { - t.Errorf("Unexpected error: %s", res[0].Err) - } + require.Len(t, res, 1, "Expected 1 error, got %d, %v", len(res), res) + assert.ErrorContains(t, res[0].Err, "object name does not conform to Kubernetes naming requirements") } func TestValidateMetadataName(t *testing.T) { @@ -187,8 +171,11 @@ func TestValidateMetadataName(t *testing.T) { } for _, tt := range tests { t.Run(fmt.Sprintf("%s/%s", tt.obj.Kind, tt.obj.Metadata.Name), func(t *testing.T) { - if err := validateMetadataName(tt.obj); (err != nil) != tt.wantErr { - t.Errorf("validateMetadataName() error = %v, wantErr %v", err, tt.wantErr) + err := validateMetadataName(tt.obj) + if tt.wantErr { + require.Error(t, err, "validateMetadataName()") + } else { + require.NoError(t, err, "validateMetadataName()") } }) } @@ -218,9 +205,7 @@ func TestDeprecatedAPIFails(t *testing.T) { } tmpdir := t.TempDir() - if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&mychart, tmpdir)) linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates( @@ -228,17 +213,16 @@ func TestDeprecatedAPIFails(t *testing.T) { namespace, values, TemplateLinterSkipSchemaValidation(false)) - if l := len(linter.Messages); l != 1 { + if !assert.Len(t, linter.Messages, 1) { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) } - t.Fatalf("Expected 1 lint error, got %d", l) } + require.Len(t, linter.Messages, 1, "Expected 1 lint error") - err := linter.Messages[0].Err.(deprecatedAPIError) - if err.Deprecated != "apps/v1beta1 Deployment" { - t.Errorf("Surprised to learn that %q is deprecated", err.Deprecated) - } + var depErr deprecatedAPIError + require.ErrorAs(t, linter.Messages[0].Err, &depErr) + assert.Equalf(t, "apps/v1beta1 Deployment", depErr.Deprecated, "Surprised to learn that %q is deprecated", depErr.Deprecated) } const manifest = `apiVersion: v1 @@ -277,9 +261,7 @@ func TestStrictTemplateParsingMapError(t *testing.T) { }, } dir := t.TempDir() - if err := chartutil.SaveDir(&ch, dir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&ch, dir)) linter := &support.Linter{ ChartDir: filepath.Join(dir, ch.Metadata.Name), } @@ -288,8 +270,7 @@ func TestStrictTemplateParsingMapError(t *testing.T) { namespace, ch.Values, TemplateLinterSkipSchemaValidation(false)) - if len(linter.Messages) != 0 { - t.Errorf("expected zero messages, got %d", len(linter.Messages)) + if !assert.Empty(t, linter.Messages, "expected zero messages") { for i, msg := range linter.Messages { t.Logf("Message %d: %q", i, msg) } @@ -325,9 +306,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err != nil { - t.Error(err) - } + require.NoError(t, validateMatchSelector(md, manifest)) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -349,9 +328,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err != nil { - t.Error(err) - } + require.NoError(t, validateMatchSelector(md, manifest)) manifest = ` apiVersion: apps/v1 kind: Deployment @@ -370,9 +347,7 @@ spec: - name: nginx image: nginx:1.14.2 ` - if err := validateMatchSelector(md, manifest); err == nil { - t.Error("expected Deployment with no selector to fail") - } + assert.Error(t, validateMatchSelector(md, manifest), "expected Deployment with no selector to fail") } func TestValidateTopIndentLevel(t *testing.T) { @@ -385,9 +360,14 @@ func TestValidateTopIndentLevel(t *testing.T) { " apiVersion:foo": true, "\n\n apiVersion:foo\n\n": true, } { - if err := validateTopIndentLevel(doc); (err == nil) == shouldFail { - t.Errorf("Expected %t for %q", shouldFail, doc) - } + t.Run(doc, func(t *testing.T) { + err := validateTopIndentLevel(doc) + if shouldFail { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) } } @@ -411,9 +391,7 @@ func TestEmptyWithCommentsManifests(t *testing.T) { } tmpdir := t.TempDir() - if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(&mychart, tmpdir)) linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} Templates( @@ -421,12 +399,12 @@ func TestEmptyWithCommentsManifests(t *testing.T) { namespace, values, TemplateLinterSkipSchemaValidation(false)) - if l := len(linter.Messages); l > 0 { + if !assert.Empty(t, linter.Messages) { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) } - t.Fatalf("Expected 0 lint errors, got %d", l) } + require.Empty(t, linter.Messages, "Expected 0 lint errors") } func TestValidateListAnnotations(t *testing.T) { md := &k8sYamlStruct{ @@ -446,10 +424,7 @@ items: annotations: helm.sh/resource-policy: keep ` - - if err := validateListAnnotations(md, manifest); err == nil { - t.Fatal("expected list with nested keep annotations to fail") - } + require.Error(t, validateListAnnotations(md, manifest), "expected list with nested keep annotations to fail") manifest = ` apiVersion: v1 @@ -461,10 +436,7 @@ items: - apiVersion: v1 kind: ConfigMap ` - - if err := validateListAnnotations(md, manifest); err != nil { - t.Fatalf("List objects keep annotations should pass. got: %s", err) - } + require.NoErrorf(t, validateListAnnotations(md, manifest), "List objects keep annotations should pass. got") } func TestIsYamlFileExtension(t *testing.T) { @@ -480,8 +452,6 @@ func TestIsYamlFileExtension(t *testing.T) { for _, test := range tests { result := isYamlFileExtension(test.filename) - if result != test.expected { - t.Errorf("isYamlFileExtension(%s) = %v; want %v", test.filename, result, test.expected) - } + assert.Equal(t, test.expected, result, "isYamlFileExtension(%s) = %v; want %v", test.filename, result, test.expected) } } diff --git a/pkg/chart/v2/lint/rules/values_test.go b/pkg/chart/v2/lint/rules/values_test.go index 470904049..82e8e660e 100644 --- a/pkg/chart/v2/lint/rules/values_test.go +++ b/pkg/chart/v2/lint/rules/values_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/internal/test/ensure" ) @@ -54,11 +55,7 @@ const testSchema = ` func TestValidateValuesYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingValuesFilePath, os.ModePerm) defer os.Remove(nonExistingValuesFilePath) - - err := validateValuesFileExistence(nonExistingValuesFilePath) - if err == nil { - t.Error("validateValuesFileExistence to return a linter error, got no error") - } + assert.Error(t, validateValuesFileExistence(nonExistingValuesFilePath), "validateValuesFileExistence to return a linter error, got no error") } func TestValidateValuesFileWellFormed(t *testing.T) { @@ -67,9 +64,7 @@ func TestValidateValuesFileWellFormed(t *testing.T) { ` tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml)) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err == nil { - t.Fatal("expected values file to fail parsing") - } + require.Error(t, validateValuesFile(valfile, map[string]any{}, false), "expected values file to fail parsing") } func TestValidateValuesFileSchema(t *testing.T) { @@ -78,9 +73,7 @@ func TestValidateValuesFileSchema(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err != nil { - t.Fatalf("Failed validation with %s", err) - } + require.NoErrorf(t, validateValuesFile(valfile, map[string]any{}, false), "Failed validation") } func TestValidateValuesFileSchemaFailure(t *testing.T) { @@ -90,9 +83,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, map[string]any{}, false) - assert.ErrorContains(t, err, "- at '/username': got number, want string") + assert.ErrorContains(t, validateValuesFile(valfile, map[string]any{}, false), "- at '/username': got number, want string") } func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T) { @@ -102,11 +93,7 @@ func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, map[string]any{}, true) - if err != nil { - t.Fatal("expected values file to pass parsing because of skipSchemaValidation") - } + require.NoError(t, validateValuesFile(valfile, map[string]any{}, true), "expected values file to pass parsing because of skipSchemaValidation") } func TestValidateValuesFileSchemaOverrides(t *testing.T) { @@ -118,9 +105,7 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) { createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, overrides, false); err != nil { - t.Fatalf("Failed validation with %s", err) - } + require.NoErrorf(t, validateValuesFile(valfile, overrides, false), "Failed validation") } func TestValidateValuesFile(t *testing.T) { @@ -157,13 +142,10 @@ func TestValidateValuesFile(t *testing.T) { err := validateValuesFile(valfile, tt.overrides, false) - switch { - case err != nil && tt.errorMessage == "": - t.Errorf("Failed validation with %s", err) - case err == nil && tt.errorMessage != "": - t.Error("expected values file to fail parsing") - case err != nil && tt.errorMessage != "": - assert.ErrorContains(t, err, tt.errorMessage, "Failed with unexpected error") + if tt.errorMessage == "" { + require.NoErrorf(t, err, "Failed validation with") + } else { + assert.ErrorContains(t, err, tt.errorMessage) } }) } @@ -172,8 +154,6 @@ func TestValidateValuesFile(t *testing.T) { func createTestingSchema(t *testing.T, dir string) string { t.Helper() schemafile := filepath.Join(dir, "values.schema.json") - if err := os.WriteFile(schemafile, []byte(testSchema), 0o700); err != nil { - t.Fatalf("Failed to write schema to tmpdir: %s", err) - } + require.NoErrorf(t, os.WriteFile(schemafile, []byte(testSchema), 0o700), "Failed to write schema to tmpdir") return schemafile } diff --git a/pkg/chart/v2/lint/support/doc.go b/pkg/chart/v2/lint/support/doc.go index 7e050b8c2..80b1d2169 100644 --- a/pkg/chart/v2/lint/support/doc.go +++ b/pkg/chart/v2/lint/support/doc.go @@ -20,4 +20,4 @@ Package support contains tools for linting charts. Linting is the process of testing charts for errors or warnings regarding formatting, compilation, or standards compliance. */ -package support // import "helm.sh/helm/v4/pkg/chart/v2/lint/support" +package support diff --git a/pkg/chart/v2/lint/support/message_test.go b/pkg/chart/v2/lint/support/message_test.go index ce5b5e42e..6d09df688 100644 --- a/pkg/chart/v2/lint/support/message_test.go +++ b/pkg/chart/v2/lint/support/message_test.go @@ -19,6 +19,9 @@ package support import ( "errors" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var errLint = errors.New("lint failed") @@ -47,33 +50,19 @@ func TestRunLinterRule(t *testing.T) { linter := Linter{} for _, test := range tests { isValid := linter.RunLinterRule(test.Severity, "chart", test.LintError) - if len(linter.Messages) != test.ExpectedMessages { - t.Errorf("RunLinterRule(%d, \"chart\", %v), linter.Messages should now have %d message, we got %d", test.Severity, test.LintError, test.ExpectedMessages, len(linter.Messages)) - } - - if linter.HighestSeverity != test.ExpectedHighestSeverity { - t.Errorf("RunLinterRule(%d, \"chart\", %v), linter.HighestSeverity should be %d, we got %d", test.Severity, test.LintError, test.ExpectedHighestSeverity, linter.HighestSeverity) - } - - if isValid != test.ExpectedReturn { - t.Errorf("RunLinterRule(%d, \"chart\", %v), should have returned %t but returned %t", test.Severity, test.LintError, test.ExpectedReturn, isValid) - } + assert.Lenf(t, linter.Messages, test.ExpectedMessages, "RunLinterRule(%d, \"chart\", %v), linter.Messages should now have %d message, we got %d", test.Severity, test.LintError, test.ExpectedMessages, len(linter.Messages)) + assert.Equalf(t, linter.HighestSeverity, test.ExpectedHighestSeverity, "RunLinterRule(%d, \"chart\", %v), linter.HighestSeverity should be %d, we got %d", test.Severity, test.LintError, test.ExpectedHighestSeverity, linter.HighestSeverity) + assert.Equalf(t, isValid, test.ExpectedReturn, "RunLinterRule(%d, \"chart\", %v), should have returned %t but returned %t", test.Severity, test.LintError, test.ExpectedReturn, isValid) } } func TestMessage(t *testing.T) { m := Message{ErrorSev, "Chart.yaml", errors.New("Foo")} - if m.Error() != "[ERROR] Chart.yaml: Foo" { - t.Errorf("Unexpected output: %s", m.Error()) - } + require.EqualError(t, m, "[ERROR] Chart.yaml: Foo") m = Message{WarningSev, "templates/", errors.New("Bar")} - if m.Error() != "[WARNING] templates/: Bar" { - t.Errorf("Unexpected output: %s", m.Error()) - } + require.EqualError(t, m, "[WARNING] templates/: Bar") m = Message{InfoSev, "templates/rc.yaml", errors.New("FooBar")} - if m.Error() != "[INFO] templates/rc.yaml: FooBar" { - t.Errorf("Unexpected output: %s", m.Error()) - } + assert.EqualError(t, m, "[INFO] templates/rc.yaml: FooBar") } diff --git a/pkg/chart/v2/loader/load_test.go b/pkg/chart/v2/loader/load_test.go index 46d17e899..4d73cb0d6 100644 --- a/pkg/chart/v2/loader/load_test.go +++ b/pkg/chart/v2/loader/load_test.go @@ -25,12 +25,12 @@ import ( "log" "os" "path/filepath" - "reflect" "runtime" "strings" "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/chart/common" @@ -40,13 +40,9 @@ import ( func TestLoadDir(t *testing.T) { l, err := Loader("testdata/frobnitz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -59,33 +55,24 @@ func TestLoadDirWithDevNull(t *testing.T) { } l, err := Loader("testdata/frobnitz_with_dev_null") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } - if _, err := l.Load(); err == nil { - t.Error("packages with an irregular file (/dev/null) should not load") - } + require.NoError(t, err, "Failed to load testdata") + _, err = l.Load() + assert.Error(t, err, "packages with an irregular file (/dev/null) should not load") } func TestLoadDirWithSymlink(t *testing.T) { sym := filepath.Join("..", "LICENSE") link := filepath.Join("testdata", "frobnitz_with_symlink", "LICENSE") - if err := os.Symlink(sym, link); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Symlink(sym, link)) defer os.Remove(link) l, err := Loader("testdata/frobnitz_with_symlink") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -102,18 +89,13 @@ func TestBomTestData(t *testing.T) { } archive, err := os.ReadFile("testdata/frobnitz_with_bom.tgz") - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoError(t, err, "Error reading archive frobnitz_with_bom.tgz") unzipped, err := gzip.NewReader(bytes.NewReader(archive)) - if err != nil { - t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) - } + require.NoError(t, err, "Error reading archive frobnitz_with_bom.tgz") defer unzipped.Close() for _, testFile := range testFiles { data := make([]byte, 3) - err := unzipped.Reset(bytes.NewReader(archive)) - require.NoErrorf(t, err, "Error reading archive frobnitz_with_bom.tgz") + require.NoErrorf(t, unzipped.Reset(bytes.NewReader(archive)), "Error reading archive frobnitz_with_bom.tgz") tr := tar.NewReader(unzipped) for { file, err := tr.Next() @@ -135,13 +117,9 @@ func TestBomTestData(t *testing.T) { func TestLoadDirWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -151,13 +129,9 @@ func TestLoadDirWithUTFBOM(t *testing.T) { func TestLoadArchiveWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -167,39 +141,27 @@ func TestLoadArchiveWithUTFBOM(t *testing.T) { func TestLoadV1(t *testing.T) { l, err := Loader("testdata/frobnitz.v1") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyDependencies(t, c) verifyDependenciesLock(t, c) } func TestLoadFileV1(t *testing.T) { l, err := Loader("testdata/frobnitz.v1.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyDependencies(t, c) verifyDependenciesLock(t, c) } func TestLoadFile(t *testing.T) { l, err := Loader("testdata/frobnitz-1.2.3.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyFrobnitz(t, c) verifyChart(t, c) verifyDependencies(t, c) @@ -223,12 +185,8 @@ func TestLoadFiles_BadCases(t *testing.T) { expectError: "validation: chart.metadata.apiVersion is required"}, } { _, err := LoadFiles(tt.bufferedFiles) - if err == nil { - t.Fatal("expected error when load illegal files") - } - if !strings.Contains(err.Error(), tt.expectError) { - t.Errorf("Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.name) - } + require.Error(t, err, "expected error when load illegal files") + assert.ErrorContains(t, err, tt.expectError, "Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.name) } } @@ -280,36 +238,16 @@ icon: https://example.com/64x64.png } c, err := LoadFiles(goodFiles) - if err != nil { - t.Errorf("Expected good files to be loaded, got %v", err) - } - - if c.Name() != "frobnitz" { - t.Errorf("Expected chart name to be 'frobnitz', got %s", c.Name()) - } - - if c.Values["var"] != "some values" { - t.Error("Expected chart values to be populated with default values") - } - - if len(c.Raw) != 5 { - t.Errorf("Expected %d files, got %d", 5, len(c.Raw)) - } - - if !bytes.Equal(c.Schema, []byte("type: Values")) { - t.Error("Expected chart schema to be populated with default values") - } - - if len(c.Templates) != 2 { - t.Errorf("Expected number of templates == 2, got %d", len(c.Templates)) - } - - if _, err = LoadFiles([]*archive.BufferedFile{}); err == nil { - t.Fatal("Expected err to be non-nil") - } - if err.Error() != "Chart.yaml file is missing" { - t.Errorf("Expected chart metadata missing error, got '%s'", err.Error()) - } + require.NoError(t, err, "Expected good files to be loaded") + assert.Equal(t, "frobnitz", c.Name(), "Expected chart name to be 'frobnitz', got %s", c.Name()) + assert.Equal(t, "some values", c.Values["var"], "Expected chart values to be populated with default values") + assert.Len(t, c.Raw, 5, "Expected %d files, got %d", 5, len(c.Raw)) + assert.True(t, bytes.Equal(c.Schema, []byte("type: Values")), "Expected chart schema to be populated with default values") + assert.Len(t, c.Templates, 2, "Expected number of templates == 2, got %d", len(c.Templates)) + + _, err = LoadFiles([]*archive.BufferedFile{}) + require.Error(t, err, "Expected err to be non-nil") + assert.EqualError(t, err, "Chart.yaml file is missing") } // Test the order of file loading. The Chart.yaml file needs to come first for @@ -365,9 +303,7 @@ icon: https://example.com/64x64.png // Capture stderr to make sure message about Chart.yaml handle dependencies // is not present r, w, err := os.Pipe() - if err != nil { - t.Fatalf("Unable to create pipe: %s", err) - } + require.NoError(t, err, "Unable to create pipe") stderr := log.Writer() log.SetOutput(w) defer func() { @@ -375,25 +311,19 @@ icon: https://example.com/64x64.png }() _, err = LoadFiles(goodFiles) - if err != nil { - t.Errorf("Expected good files to be loaded, got %v", err) - } + require.NoError(t, err, "Expected good files to be loaded") w.Close() var text bytes.Buffer io.Copy(&text, r) - if text.String() != "" { - t.Errorf("Expected no message to Stderr, got %s", text.String()) - } + assert.Empty(t, text.String(), "Expected no message to Stderr, got %s", text.String()) } // Packaging the chart on a Windows machine will produce an // archive that has \\ as delimiters. Test that we support these archives func TestLoadFileBackslash(t *testing.T) { c, err := Load("testdata/frobnitz_backslash-1.2.3.tgz") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyChartFileAndTemplate(t, c, "frobnitz_backslash") verifyChart(t, c) verifyDependencies(t, c) @@ -401,13 +331,9 @@ func TestLoadFileBackslash(t *testing.T) { func TestLoadV2WithReqs(t *testing.T) { l, err := Loader("testdata/frobnitz.v2.reqs") - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") c, err := l.Load() - if err != nil { - t.Fatalf("Failed to load testdata: %s", err) - } + require.NoError(t, err, "Failed to load testdata") verifyDependencies(t, c) verifyDependenciesLock(t, c) } @@ -417,9 +343,7 @@ func TestLoadInvalidArchive(t *testing.T) { writeTar := func(filename, internalPath string, body []byte) { dest, err := os.Create(filename) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) zipper := gzip.NewWriter(dest) tw := tar.NewWriter(zipper) @@ -429,12 +353,9 @@ func TestLoadInvalidArchive(t *testing.T) { Size: int64(len(body)), ModTime: time.Now(), } - if err := tw.WriteHeader(h); err != nil { - t.Fatal(err) - } - if _, err := tw.Write(body); err != nil { - t.Fatal(err) - } + require.NoError(t, tw.WriteHeader(h)) + _, err = tw.Write(body) + require.NoError(t, err) tw.Close() zipper.Close() dest.Close() @@ -463,40 +384,32 @@ func TestLoadInvalidArchive(t *testing.T) { {"illegal-abspath5.tgz", "/./c://foo", "chart contains illegally named files"}, {"illegal-abspath6.tgz", "\\\\?\\Some\\windows\\magic", "chart illegally contains absolute paths"}, } { - illegalChart := filepath.Join(tmpdir, tt.chartname) - writeTar(illegalChart, tt.internal, []byte("hello: world")) - _, err := Load(illegalChart) - if err == nil { - t.Fatal("expected error when unpacking illegal files") - } - if !strings.Contains(err.Error(), tt.expectError) { - t.Errorf("Expected error to contain %q, got %q for %s", tt.expectError, err.Error(), tt.chartname) - } + t.Run(tt.chartname, func(t *testing.T) { + illegalChart := filepath.Join(tmpdir, tt.chartname) + writeTar(illegalChart, tt.internal, []byte("hello: world")) + _, err := Load(illegalChart) + require.Error(t, err, "expected error when unpacking illegal files") + require.ErrorContains(t, err, tt.expectError) + }) } // Make sure that absolute path gets interpreted as relative illegalChart := filepath.Join(tmpdir, "abs-path.tgz") writeTar(illegalChart, "/Chart.yaml", []byte("hello: world")) _, err := Load(illegalChart) - if err.Error() != "validation: chart.metadata.name is required" { - t.Error(err) - } + require.EqualError(t, err, "validation: chart.metadata.name is required") // And just to validate that the above was not spurious illegalChart = filepath.Join(tmpdir, "abs-path2.tgz") writeTar(illegalChart, "files/whatever.yaml", []byte("hello: world")) _, err = Load(illegalChart) - if err.Error() != "Chart.yaml file is missing" { - t.Errorf("Unexpected error message: %s", err) - } + require.EqualError(t, err, "Chart.yaml file is missing") // Finally, test that drive letter gets stripped off on Windows illegalChart = filepath.Join(tmpdir, "abs-winpath.tgz") writeTar(illegalChart, "c:\\Chart.yaml", []byte("hello: world")) _, err = Load(illegalChart) - if err.Error() != "validation: chart.metadata.name is required" { - t.Error(err) - } + assert.EqualError(t, err, "validation: chart.metadata.name is required") } func TestLoadValues(t *testing.T) { @@ -543,12 +456,8 @@ foo: for testName, testCase := range testCases { t.Run(testName, func(tt *testing.T) { values, err := LoadValues(bytes.NewReader(testCase.data)) - if err != nil { - tt.Fatal(err) - } - if !reflect.DeepEqual(values, testCase.expctedValues) { - tt.Errorf("Expected values: %v, got %v", testCase.expctedValues, values) - } + require.NoError(tt, err) + assert.Equal(t, testCase.expctedValues, values) }) } } @@ -576,22 +485,13 @@ func TestMergeValuesV2(t *testing.T) { } testMap := MergeMaps(flatMap, nestedMap) - equal := reflect.DeepEqual(testMap, nestedMap) - if !equal { - t.Errorf("Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) - } + assert.Equal(t, testMap, nestedMap, "Expected a nested map to overwrite a flat value. Expected: %v, got %v", nestedMap, testMap) testMap = MergeMaps(nestedMap, flatMap) - equal = reflect.DeepEqual(testMap, flatMap) - if !equal { - t.Errorf("Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) - } + assert.Equal(t, testMap, flatMap, "Expected a flat value to overwrite a map. Expected: %v, got %v", flatMap, testMap) testMap = MergeMaps(nestedMap, anotherNestedMap) - equal = reflect.DeepEqual(testMap, anotherNestedMap) - if !equal { - t.Errorf("Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) - } + assert.Equal(t, testMap, anotherNestedMap, "Expected a nested map to overwrite another nested map. Expected: %v, got %v", anotherNestedMap, testMap) testMap = MergeMaps(anotherFlatMap, anotherNestedMap) expectedMap := map[string]any{ @@ -602,32 +502,23 @@ func TestMergeValuesV2(t *testing.T) { "awesome": "stuff", }, } - equal = reflect.DeepEqual(testMap, expectedMap) - if !equal { - t.Errorf("Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) - } + assert.Equal(t, expectedMap, testMap, "Expected a map with different keys to merge properly with another map. Expected: %v, got %v", expectedMap, testMap) } func verifyChart(t *testing.T, c *chart.Chart) { t.Helper() - if c.Name() == "" { - t.Fatalf("No chart metadata found on %v", c) - } + require.NotEmpty(t, c.Name(), "No chart metadata found on %v", c) t.Logf("Verifying chart %s", c.Name()) - if len(c.Templates) != 1 { - t.Errorf("Expected 1 template, got %d", len(c.Templates)) - } + assert.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) numfiles := 6 - if len(c.Files) != numfiles { - t.Errorf("Expected %d extra files, got %d", numfiles, len(c.Files)) + if !assert.Len(t, c.Files, numfiles) { for _, n := range c.Files { t.Logf("\t%s", n.Name) } } - if len(c.Dependencies()) != 2 { - t.Errorf("Expected 2 dependencies, got %d (%v)", len(c.Dependencies()), c.Dependencies()) + if !assert.Len(t, c.Dependencies(), 2, "Expected 2 dependencies") { for _, d := range c.Dependencies() { t.Logf("\tSubchart: %s\n", d.Name()) } @@ -643,62 +534,40 @@ func verifyChart(t *testing.T, c *chart.Chart) { } for _, dep := range c.Dependencies() { - if dep.Metadata == nil { - t.Fatalf("expected metadata on dependency: %v", dep) - } + require.NotNil(t, dep.Metadata, "expected metadata on dependency: %v", dep) exp, ok := expect[dep.Name()] - if !ok { - t.Fatalf("Unknown dependency %s", dep.Name()) - } - if exp["version"] != dep.Metadata.Version { - t.Errorf("Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version) - } + require.True(t, ok, "Unknown dependency %s", dep.Name()) + assert.Equal(t, dep.Metadata.Version, exp["version"], "Expected %s version %s, got %s", dep.Name(), exp["version"], dep.Metadata.Version) } } func verifyDependencies(t *testing.T, c *chart.Chart) { t.Helper() - if len(c.Metadata.Dependencies) != 2 { - t.Errorf("Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) - } + require.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, } for i, tt := range tests { d := c.Metadata.Dependencies[i] - if d.Name != tt.Name { - t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) - } - if d.Version != tt.Version { - t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) - } - if d.Repository != tt.Repository { - t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) - } + assert.Equal(t, tt.Name, d.Name, "Expected dependency named %q, got %q", tt.Name, d.Name) + assert.Equal(t, tt.Version, d.Version, "Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) + assert.Equal(t, tt.Repository, d.Repository, "Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) } } func verifyDependenciesLock(t *testing.T, c *chart.Chart) { t.Helper() - if len(c.Metadata.Dependencies) != 2 { - t.Errorf("Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) - } + require.Len(t, c.Metadata.Dependencies, 2, "Expected 2 dependencies, got %d", len(c.Metadata.Dependencies)) tests := []*chart.Dependency{ {Name: "alpine", Version: "0.1.0", Repository: "https://example.com/charts"}, {Name: "mariner", Version: "4.3.2", Repository: "https://example.com/charts"}, } for i, tt := range tests { d := c.Metadata.Dependencies[i] - if d.Name != tt.Name { - t.Errorf("Expected dependency named %q, got %q", tt.Name, d.Name) - } - if d.Version != tt.Version { - t.Errorf("Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) - } - if d.Repository != tt.Repository { - t.Errorf("Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) - } + assert.Equal(t, tt.Name, d.Name, "Expected dependency named %q, got %q", tt.Name, d.Name) + assert.Equal(t, tt.Version, d.Version, "Expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, d.Version) + assert.Equal(t, tt.Repository, d.Repository, "Expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, d.Repository) } } @@ -709,53 +578,25 @@ func verifyFrobnitz(t *testing.T, c *chart.Chart) { func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { t.Helper() - if c.Metadata == nil { - t.Fatal("Metadata is nil") - } - if c.Name() != name { - t.Errorf("Expected %s, got %s", name, c.Name()) - } - if len(c.Templates) != 1 { - t.Fatalf("Expected 1 template, got %d", len(c.Templates)) - } - if c.Templates[0].Name != "templates/template.tpl" { - t.Errorf("Unexpected template: %s", c.Templates[0].Name) - } - if len(c.Templates[0].Data) == 0 { - t.Error("No template data.") - } - if len(c.Files) != 6 { - t.Fatalf("Expected 6 Files, got %d", len(c.Files)) - } - if len(c.Dependencies()) != 2 { - t.Fatalf("Expected 2 Dependency, got %d", len(c.Dependencies())) - } - if len(c.Metadata.Dependencies) != 2 { - t.Fatalf("Expected 2 Dependencies.Dependency, got %d", len(c.Metadata.Dependencies)) - } - if len(c.Lock.Dependencies) != 2 { - t.Fatalf("Expected 2 Lock.Dependency, got %d", len(c.Lock.Dependencies)) - } + require.NotNil(t, c.Metadata, "Metadata is nil") + assert.Equal(t, name, c.Name(), "Expected %s, got %s", name, c.Name()) + require.Len(t, c.Templates, 1, "Expected 1 template, got %d", len(c.Templates)) + assert.Equal(t, "templates/template.tpl", c.Templates[0].Name, "Unexpected template: %s", c.Templates[0].Name) + assert.NotEmpty(t, c.Templates[0].Data, "No template data.") + require.Len(t, c.Files, 6, "Expected 6 Files, got %d", len(c.Files)) + require.Len(t, c.Dependencies(), 2, "Expected 2 Dependency, got %d", len(c.Dependencies())) + require.Len(t, c.Metadata.Dependencies, 2, "Expected 2 Dependencies.Dependency, got %d", len(c.Metadata.Dependencies)) + require.Len(t, c.Lock.Dependencies, 2, "Expected 2 Lock.Dependency, got %d", len(c.Lock.Dependencies)) for _, dep := range c.Dependencies() { switch dep.Name() { case "mariner": case "alpine": - if len(dep.Templates) != 1 { - t.Fatalf("Expected 1 template, got %d", len(dep.Templates)) - } - if dep.Templates[0].Name != "templates/alpine-pod.yaml" { - t.Errorf("Unexpected template: %s", dep.Templates[0].Name) - } - if len(dep.Templates[0].Data) == 0 { - t.Error("No template data.") - } - if len(dep.Files) != 1 { - t.Fatalf("Expected 1 Files, got %d", len(dep.Files)) - } - if len(dep.Dependencies()) != 2 { - t.Fatalf("Expected 2 Dependency, got %d", len(dep.Dependencies())) - } + require.Len(t, dep.Templates, 1, "Expected 1 template, got %d", len(dep.Templates)) + assert.Equal(t, "templates/alpine-pod.yaml", dep.Templates[0].Name, "Unexpected template: %s", dep.Templates[0].Name) + assert.NotEmpty(t, dep.Templates[0].Data, "No template data.") + require.Len(t, dep.Files, 1, "Expected 1 Files, got %d", len(dep.Files)) + require.Len(t, dep.Dependencies(), 2, "Expected 2 Dependency, got %d", len(dep.Dependencies())) default: t.Errorf("Unexpected dependency %s", dep.Name()) } @@ -765,8 +606,6 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { func verifyBomStripped(t *testing.T, files []*common.File) { t.Helper() for _, file := range files { - if bytes.HasPrefix(file.Data, utf8bom) { - t.Errorf("Byte Order Mark still present in processed file %s", file.Name) - } + assert.Falsef(t, bytes.HasPrefix(file.Data, utf8bom), "Byte Order Mark still present in processed file %s", file.Name) } } diff --git a/pkg/chart/v2/metadata_test.go b/pkg/chart/v2/metadata_test.go index 63dd99e52..720ca4886 100644 --- a/pkg/chart/v2/metadata_test.go +++ b/pkg/chart/v2/metadata_test.go @@ -16,8 +16,10 @@ limitations under the License. package v2 import ( - "errors" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestValidate(t *testing.T) { @@ -192,21 +194,13 @@ func TestValidate(t *testing.T) { for _, tt := range tests { result := tt.md.Validate() - if !errors.Is(result, tt.err) { - t.Errorf("expected %q, got %q in test %q", tt.err, result, tt.name) - } + assert.ErrorIs(t, result, tt.err, "expected %q, got %q in test %q", tt.err, result, tt.name) } } func TestValidate_sanitize(t *testing.T) { md := &Metadata{APIVersion: "v2", Name: "test", Version: "1.0", Description: "\adescr\u0081iption\rtest", Maintainers: []*Maintainer{{Name: "\r"}}} - if err := md.Validate(); err != nil { - t.Fatalf("unexpected error: %s", err) - } - if md.Description != "description test" { - t.Fatalf("description was not sanitized: %q", md.Description) - } - if md.Maintainers[0].Name != " " { - t.Fatal("maintainer name was not sanitized") - } + require.NoError(t, md.Validate()) + require.Equal(t, "description test", md.Description, "description was not sanitized: %q", md.Description) + require.Equal(t, " ", md.Maintainers[0].Name, "maintainer name was not sanitized") } diff --git a/pkg/chart/v2/util/chartfile_test.go b/pkg/chart/v2/util/chartfile_test.go index 068977eef..981d0e131 100644 --- a/pkg/chart/v2/util/chartfile_test.go +++ b/pkg/chart/v2/util/chartfile_test.go @@ -19,6 +19,9 @@ package util import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" ) @@ -26,96 +29,40 @@ const testfile = "testdata/chartfiletest.yaml" func TestLoadChartfile(t *testing.T) { f, err := LoadChartfile(testfile) - if err != nil { - t.Errorf("Failed to open %s: %s", testfile, err) - return - } + require.NoErrorf(t, err, "Failed to open %s", testfile) verifyChartfile(t, f, "frobnitz") } func verifyChartfile(t *testing.T, f *chart.Metadata, name string) { t.Helper() - if f == nil { - t.Fatal("Failed verifyChartfile because f is nil") - } - - if f.APIVersion != chart.APIVersionV1 { - t.Errorf("Expected API Version %q, got %q", chart.APIVersionV1, f.APIVersion) - } - - if f.Name != name { - t.Errorf("Expected %s, got %s", name, f.Name) - } - - if f.Description != "This is a frobnitz." { - t.Errorf("Unexpected description %q", f.Description) - } - - if f.Version != "1.2.3" { - t.Errorf("Unexpected version %q", f.Version) - } - - if len(f.Maintainers) != 2 { - t.Errorf("Expected 2 maintainers, got %d", len(f.Maintainers)) - } - - if f.Maintainers[0].Name != "The Helm Team" { - t.Error("Unexpected maintainer name.") - } - - if f.Maintainers[1].Email != "nobody@example.com" { - t.Error("Unexpected maintainer email.") - } - - if len(f.Sources) != 1 { - t.Fatal("Unexpected number of sources") - } - - if f.Sources[0] != "https://example.com/foo/bar" { - t.Errorf("Expected https://example.com/foo/bar, got %s", f.Sources) - } - - if f.Home != "http://example.com" { - t.Error("Unexpected home.") - } - - if f.Icon != "https://example.com/64x64.png" { - t.Errorf("Unexpected icon: %q", f.Icon) - } - - if len(f.Keywords) != 3 { - t.Error("Unexpected keywords") - } - - if len(f.Annotations) != 2 { - t.Fatal("Unexpected annotations") - } - - if want, got := "extravalue", f.Annotations["extrakey"]; want != got { - t.Errorf("Want %q, but got %q", want, got) - } - - if want, got := "anothervalue", f.Annotations["anotherkey"]; want != got { - t.Errorf("Want %q, but got %q", want, got) - } + require.NotNil(t, f, "Failed verifyChartfile because f is nil") + assert.Equal(t, chart.APIVersionV1, f.APIVersion, "Expected API Version %q, got %q", chart.APIVersionV1, f.APIVersion) + assert.Equal(t, name, f.Name, "Expected %s, got %s", name, f.Name) + assert.Equal(t, "This is a frobnitz.", f.Description, "Unexpected description %q", f.Description) + assert.Equal(t, "1.2.3", f.Version, "Unexpected version %q", f.Version) + assert.Len(t, f.Maintainers, 2, "Expected 2 maintainers, got %d", len(f.Maintainers)) + assert.Equal(t, "The Helm Team", f.Maintainers[0].Name, "Unexpected maintainer name.") + assert.Equal(t, "nobody@example.com", f.Maintainers[1].Email, "Unexpected maintainer email.") + require.Len(t, f.Sources, 1, "Unexpected number of sources") + assert.Equal(t, "https://example.com/foo/bar", f.Sources[0], "Expected https://example.com/foo/bar, got %s", f.Sources) + assert.Equal(t, "http://example.com", f.Home, "Unexpected home.") + assert.Equal(t, "https://example.com/64x64.png", f.Icon, "Unexpected icon: %q", f.Icon) + assert.Len(t, f.Keywords, 3, "Unexpected keywords") + require.Len(t, f.Annotations, 2, "Unexpected annotations") + assert.Equal(t, "extravalue", f.Annotations["extrakey"]) + assert.Equal(t, "anothervalue", f.Annotations["anotherkey"]) kk := []string{"frobnitz", "sprocket", "dodad"} for i, k := range f.Keywords { - if kk[i] != k { - t.Errorf("Expected %q, got %q", kk[i], k) - } + assert.Equal(t, kk[i], k, "Expected %q, got %q", kk[i], k) } } func TestIsChartDir(t *testing.T) { validChartDir, err := IsChartDir("testdata/frobnitz") - if !validChartDir { - t.Errorf("unexpected error while reading chart-directory: (%v)", err) - return - } + require.NoError(t, err) + require.True(t, validChartDir, "expected valid chart directory") validChartDir, err = IsChartDir("testdata") - if validChartDir || err == nil { - t.Error("expected error but did not get any") - return - } + require.Error(t, err) + require.False(t, validChartDir, "expected invalid chart directory") } diff --git a/pkg/chart/v2/util/compatible_test.go b/pkg/chart/v2/util/compatible_test.go index e17d33e35..9a57ef64a 100644 --- a/pkg/chart/v2/util/compatible_test.go +++ b/pkg/chart/v2/util/compatible_test.go @@ -17,7 +17,11 @@ limitations under the License. // Package version represents the current version of the project. package util -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func TestIsCompatibleRange(t *testing.T) { tests := []struct { @@ -36,8 +40,6 @@ func TestIsCompatibleRange(t *testing.T) { } for _, tt := range tests { - if IsCompatibleRange(tt.constraint, tt.ver) != tt.expected { - t.Errorf("expected constraint %s to be %v for %s", tt.constraint, tt.expected, tt.ver) - } + assert.Equal(t, tt.expected, IsCompatibleRange(tt.constraint, tt.ver), "expected constraint %s to be %v for %s", tt.constraint, tt.expected, tt.ver) } } diff --git a/pkg/chart/v2/util/create_test.go b/pkg/chart/v2/util/create_test.go index 367b755d9..69ba1336d 100644 --- a/pkg/chart/v2/util/create_test.go +++ b/pkg/chart/v2/util/create_test.go @@ -22,6 +22,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" ) @@ -30,20 +33,13 @@ func TestCreate(t *testing.T) { tdir := t.TempDir() c, err := Create("foo", tdir) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) dir := filepath.Join(tdir, "foo") mychart, err := loader.LoadDir(c) - if err != nil { - t.Fatalf("Failed to load newly created chart %q: %s", c, err) - } - - if mychart.Name() != "foo" { - t.Errorf("Expected name to be 'foo', got %q", mychart.Name()) - } + require.NoError(t, err, "Failed to load newly created chart %q", c) + assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) for _, f := range []string{ ChartfileName, @@ -58,9 +54,8 @@ func TestCreate(t *testing.T) { TestConnectionName, ValuesfileName, } { - if _, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } + _, err := os.Stat(filepath.Join(dir, f)) + assert.NoErrorf(t, err, "Expected %s file", f) } } @@ -74,38 +69,26 @@ func TestCreateFrom(t *testing.T) { } srcdir := "./testdata/frobnitz/charts/mariner" - if err := CreateFrom(cf, tdir, srcdir); err != nil { - t.Fatal(err) - } + require.NoError(t, CreateFrom(cf, tdir, srcdir)) dir := filepath.Join(tdir, "foo") c := filepath.Join(tdir, cf.Name) mychart, err := loader.LoadDir(c) - if err != nil { - t.Fatalf("Failed to load newly created chart %q: %s", c, err) - } - - if mychart.Name() != "foo" { - t.Errorf("Expected name to be 'foo', got %q", mychart.Name()) - } + require.NoError(t, err, "Failed to load newly created chart %q", c) + assert.Equal(t, "foo", mychart.Name(), "Expected name to be 'foo', got %q", mychart.Name()) for _, f := range []string{ ChartfileName, ValuesfileName, filepath.Join(TemplatesDir, "placeholder.tpl"), } { - if _, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } + _, err := os.Stat(filepath.Join(dir, f)) + require.NoErrorf(t, err, "Expected %s file", f) // Check each file to make sure has been replaced b, err := os.ReadFile(filepath.Join(dir, f)) - if err != nil { - t.Errorf("Unable to read file %s: %s", f, err) - } - if bytes.Contains(b, []byte("")) { - t.Errorf("File %s contains ", f) - } + require.NoError(t, err, "Unable to read file %s", f) + assert.Falsef(t, bytes.Contains(b, []byte("")), "File %s contains ", f) } } @@ -115,9 +98,8 @@ func TestCreate_Overwrite(t *testing.T) { var errlog bytes.Buffer - if _, err := Create("foo", tdir); err != nil { - t.Fatal(err) - } + _, err := Create("foo", tdir) + require.NoError(t, err) dir := filepath.Join(tdir, "foo") @@ -126,22 +108,13 @@ func TestCreate_Overwrite(t *testing.T) { // Now re-run the create Stderr = &errlog - if _, err := Create("foo", tdir); err != nil { - t.Fatal(err) - } + _, err = Create("foo", tdir) + require.NoError(t, err) data, err := os.ReadFile(tplname) - if err != nil { - t.Fatal(err) - } - - if string(data) == "FOO" { - t.Fatal("File that should have been modified was not.") - } - - if errlog.Len() == 0 { - t.Error("Expected warnings about overwriting files.") - } + require.NoError(t, err) + require.NotEqual(t, "FOO", string(data), "File that should have been modified was not.") + assert.NotEqual(t, 0, errlog.Len(), "Expected warnings about overwriting files.") } func TestValidateChartName(t *testing.T) { @@ -165,8 +138,11 @@ func TestValidateChartName(t *testing.T) { "abcdefghijklmnopqrstuvwxyz-_." + "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.": false, } { - if err := validateChartName(name); (err != nil) == shouldPass { - t.Errorf("test for %q failed", name) + err := validateChartName(name) + if shouldPass { + assert.NoError(t, err) + } else { + assert.Error(t, err) } } } diff --git a/pkg/chart/v2/util/dependencies_test.go b/pkg/chart/v2/util/dependencies_test.go index 90a8806ec..097663783 100644 --- a/pkg/chart/v2/util/dependencies_test.go +++ b/pkg/chart/v2/util/dependencies_test.go @@ -21,6 +21,9 @@ import ( "strconv" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" @@ -29,9 +32,7 @@ import ( func loadChart(t *testing.T, path string) *chart.Chart { t.Helper() c, err := loader.Load(path) - if err != nil { - t.Fatalf("failed to load testdata: %s", err) - } + require.NoError(t, err, "failed to load testdata") return c } @@ -42,19 +43,11 @@ func TestLoadDependency(t *testing.T) { } check := func(deps []*chart.Dependency) { - if len(deps) != 2 { - t.Errorf("expected 2 dependencies, got %d", len(deps)) - } + require.Len(t, deps, 2, "expected 2 dependencies, got %d", len(deps)) for i, tt := range tests { - if deps[i].Name != tt.Name { - t.Errorf("expected dependency named %q, got %q", tt.Name, deps[i].Name) - } - if deps[i].Version != tt.Version { - t.Errorf("expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, deps[i].Version) - } - if deps[i].Repository != tt.Repository { - t.Errorf("expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, deps[i].Repository) - } + assert.Equal(t, tt.Name, deps[i].Name, "expected dependency named %q, got %q", tt.Name, deps[i].Name) + assert.Equal(t, tt.Version, deps[i].Version, "expected dependency named %q to have version %q, got %q", tt.Name, tt.Version, deps[i].Version) + assert.Equal(t, tt.Repository, deps[i].Repository, "expected dependency named %q to have repository %q, got %q", tt.Name, tt.Repository, deps[i].Repository) } } c := loadChart(t, "testdata/frobnitz") @@ -117,18 +110,12 @@ func TestDependencyEnabled(t *testing.T) { for _, tc := range tests { c := loadChart(t, "testdata/subpop") t.Run(tc.name, func(t *testing.T) { - if err := processDependencyEnabled(c, tc.v, ""); err != nil { - t.Fatalf("error processing enabled dependencies %v", err) - } + require.NoErrorf(t, processDependencyEnabled(c, tc.v, ""), "error processing enabled dependencies") names := extractChartNames(c) - if len(names) != len(tc.e) { - t.Fatalf("slice lengths do not match got %v, expected %v", len(names), len(tc.e)) - } + require.Len(t, names, len(tc.e), "slice lengths do not match got %v, expected %v", len(names), len(tc.e)) for i := range names { - if names[i] != tc.e[i] { - t.Fatalf("slice values do not match got %v, expected %v", names, tc.e) - } + require.Equal(t, tc.e[i], names[i], "slice values do not match got %v, expected %v", names, tc.e) } }) } @@ -219,68 +206,44 @@ func TestProcessDependencyImportValues(t *testing.T) { e["SCBexported2A"] = "blaster" e["global.SC1exported2.all.SC1exported3"] = "SC1expstr" - if err := processDependencyImportValues(c, false); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoErrorf(t, processDependencyImportValues(c, false), "processing import values dependencies") cc := common.Values(c.Values) for kk, vv := range e { pv, err := cc.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } + require.NoError(t, err, "retrieving import values table %v", kk) switch pv := pv.(type) { case float64: - if s := strconv.FormatFloat(pv, 'f', -1, 64); s != vv { - t.Errorf("failed to match imported float value %v with expected %v for key %q", s, vv, kk) - } + s := strconv.FormatFloat(pv, 'f', -1, 64) + assert.Equalf(t, s, vv, "failed to match imported float value %v with expected %v for key %q", s, vv, kk) case bool: - if b := strconv.FormatBool(pv); b != vv { - t.Errorf("failed to match imported bool value %v with expected %v for key %q", b, vv, kk) - } + b := strconv.FormatBool(pv) + assert.Equalf(t, b, vv, "failed to match imported bool value %v with expected %v for key %q", b, vv, kk) default: - if pv != vv { - t.Errorf("failed to match imported string value %q with expected %q for key %q", pv, vv, kk) - } + assert.Equal(t, vv, pv, "failed to match imported string value %q with expected %q for key %q", pv, vv, kk) } } // Since this was processed with coalescing there should be no null values. // Here we verify that. _, err := cc.PathValue("ensurenull") - if err == nil { - t.Error("expect nil value not found but found it") - } - switch xerr := err.(type) { - case common.ErrNoValue: - // We found what we expected - default: - t.Errorf("expected an ErrNoValue but got %q instead", xerr) - } + require.Error(t, err, "expect nil value not found but found it") + var xerr common.ErrNoValue + require.ErrorAs(t, err, &xerr, "expected an ErrNoValue") c = loadChart(t, "testdata/subpop") - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoErrorf(t, processDependencyImportValues(c, true), "processing import values dependencies") cc = common.Values(c.Values) val, err := cc.PathValue("ensurenull") - if err != nil { - t.Error("expect value but ensurenull was not found") - } - if val != nil { - t.Errorf("expect nil value but got %q instead", val) - } + require.NoError(t, err, "expect value but ensurenull was not found") + assert.Nil(t, val, "expect nil value but got %q instead", val) } func TestProcessDependencyImportValuesFromSharedDependencyToAliases(t *testing.T) { c := loadChart(t, "testdata/chart-with-import-from-aliased-dependencies") - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.NoErrorf(t, processDependencyImportValues(c, true), "processing import values dependencies") e := make(map[string]string) e["foo-defaults.defaultValue"] = "42" @@ -295,12 +258,8 @@ func TestProcessDependencyImportValuesFromSharedDependencyToAliases(t *testing.T cValues := common.Values(c.Values) for kk, vv := range e { pv, err := cValues.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } - if pv != vv { - t.Errorf("failed to match imported value %v with expected %v", pv, vv) - } + require.NoError(t, err, "retrieving import values table %v", kk) + assert.Equal(t, vv, pv, "failed to match imported value %v with expected %v", pv, vv) } } @@ -327,25 +286,18 @@ func TestProcessDependencyImportValuesMultiLevelPrecedence(t *testing.T) { e["app2.service.port"] = "8080" e["app3.service.port"] = "9090" e["app4.service.port"] = "1234" - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } + require.NoErrorf(t, processDependencyImportValues(c, true), "processing import values dependencies") cc := common.Values(c.Values) for kk, vv := range e { pv, err := cc.PathValue(kk) - if err != nil { - t.Fatalf("retrieving import values table %v %v", kk, err) - } + require.NoError(t, err, "retrieving import values table %v", kk) switch pv := pv.(type) { case float64: - if s := strconv.FormatFloat(pv, 'f', -1, 64); s != vv { - t.Errorf("failed to match imported float value %v with expected %v", s, vv) - } + s := strconv.FormatFloat(pv, 'f', -1, 64) + assert.Equalf(t, s, vv, "failed to match imported float value %v with expected %v", s, vv) default: - if pv != vv { - t.Errorf("failed to match imported string value %q with expected %q", pv, vv) - } + assert.Equal(t, vv, pv, "failed to match imported string value %q with expected %q", pv, vv) } } } @@ -354,127 +306,71 @@ func TestProcessDependencyImportValuesForEnabledCharts(t *testing.T) { c := loadChart(t, "testdata/import-values-from-enabled-subchart/parent-chart") nameOverride := "parent-chart-prod" - if err := processDependencyImportValues(c, true); err != nil { - t.Fatalf("processing import values dependencies %v", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 1 { - t.Fatal("expected no changes in dependencies") - } - - if len(c.Metadata.Dependencies) != 1 { - t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) - } - + require.NoErrorf(t, processDependencyImportValues(c, true), "processing import values dependencies") + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 1, "expected no changes in dependencies") + require.Len(t, c.Metadata.Dependencies, 1, "expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) prodDependencyValues := c.Dependencies()[0].Values - if prodDependencyValues["nameOverride"] != nameOverride { - t.Fatalf("dependency chart name should be %s but got %s", nameOverride, prodDependencyValues["nameOverride"]) - } + require.Equal(t, nameOverride, prodDependencyValues["nameOverride"], "dependency chart name should be %s but got %s", nameOverride, prodDependencyValues["nameOverride"]) } func TestGetAliasDependency(t *testing.T) { c := loadChart(t, "testdata/frobnitz") req := c.Metadata.Dependencies - if len(req) == 0 { - t.Fatal("there are no dependencies to test") - } + require.NotEmpty(t, req, "there are no dependencies to test") // Success case aliasChart := getAliasDependency(c.Dependencies(), req[0]) - if aliasChart == nil { - t.Fatalf("failed to get dependency chart for alias %s", req[0].Name) - } + require.NotNil(t, aliasChart, "failed to get dependency chart for alias %s", req[0].Name) if req[0].Alias != "" { - if aliasChart.Name() != req[0].Alias { - t.Fatalf("dependency chart name should be %s but got %s", req[0].Alias, aliasChart.Name()) - } - } else if aliasChart.Name() != req[0].Name { - t.Fatalf("dependency chart name should be %s but got %s", req[0].Name, aliasChart.Name()) + require.Equal(t, req[0].Alias, aliasChart.Name(), "dependency chart name should be %s but got %s", req[0].Alias, aliasChart.Name()) + } else { + require.Equalf(t, aliasChart.Name(), req[0].Name, "dependency chart name should be %s but got %s", req[0].Name, aliasChart.Name()) } if req[0].Version != "" { - if !IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version) { - t.Fatal("dependency chart version is not in the compatible range") - } + require.True(t, IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version), "dependency chart version is not in the compatible range") } // Failure case req[0].Name = "something-else" - if aliasChart := getAliasDependency(c.Dependencies(), req[0]); aliasChart != nil { - t.Fatalf("expected no chart but got %s", aliasChart.Name()) - } + require.Nilf(t, getAliasDependency(c.Dependencies(), req[0]), "expected no chart") req[0].Version = "something else which is not in the compatible range" - if IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version) { - t.Fatal("dependency chart version outside the compatible range should fail, but it succeeded") - } + require.False(t, IsCompatibleRange(req[0].Version, aliasChart.Metadata.Version), "dependency chart version outside the compatible range should fail, but it succeeded") } func TestDependentChartAliases(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-alias") req := c.Metadata.Dependencies - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 3 { - t.Fatal("expected alias dependencies to be added") - } - - if len(c.Dependencies()) != len(c.Metadata.Dependencies) { - t.Fatalf("expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 3, "expected alias dependencies to be added") + require.Len(t, c.Dependencies(), len(c.Metadata.Dependencies), "expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) aliasChart := getAliasDependency(c.Dependencies(), req[2]) - if aliasChart == nil { - t.Fatalf("failed to get dependency chart for alias %s", req[2].Name) - } - if aliasChart.Parent() != c { - t.Fatalf("dependency chart has wrong parent, expected %s but got %s", c.Name(), aliasChart.Parent().Name()) - } + require.NotNil(t, aliasChart, "failed to get dependency chart for alias %s", req[2].Name) + require.Equal(t, c, aliasChart.Parent(), "dependency chart has wrong parent, expected %s but got %s", c.Name(), aliasChart.Parent().Name()) if req[2].Alias != "" { - if aliasChart.Name() != req[2].Alias { - t.Fatalf("dependency chart name should be %s but got %s", req[2].Alias, aliasChart.Name()) - } - } else if aliasChart.Name() != req[2].Name { - t.Fatalf("dependency chart name should be %s but got %s", req[2].Name, aliasChart.Name()) + require.Equal(t, req[2].Alias, aliasChart.Name(), "dependency chart name should be %s but got %s", req[2].Alias, aliasChart.Name()) + } else { + require.Equalf(t, aliasChart.Name(), req[2].Name, "dependency chart name should be %s but got %s", req[2].Name, aliasChart.Name()) } req[2].Name = "dummy-name" - if aliasChart := getAliasDependency(c.Dependencies(), req[2]); aliasChart != nil { - t.Fatalf("expected no chart but got %s", aliasChart.Name()) - } + require.Nilf(t, getAliasDependency(c.Dependencies(), req[2]), "expected no chart") } func TestDependentChartWithSubChartsAbsentInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-no-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") } func TestDependentChartWithSubChartsHelmignore(t *testing.T) { @@ -484,67 +380,37 @@ func TestDependentChartWithSubChartsHelmignore(t *testing.T) { func TestDependentChartsWithSubChartsSymlink(t *testing.T) { joonix := filepath.Join("testdata", "joonix") - if err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz"))) defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) c := loadChart(t, joonix) - if c.Name() != "joonix" { - t.Fatalf("unexpected chart name: %s", c.Name()) - } - if n := len(c.Dependencies()); n != 1 { - t.Fatalf("expected 1 dependency for this chart, but got %d", n) - } + require.Equal(t, "joonix", c.Name(), "unexpected chart name: %s", c.Name()) + require.Lenf(t, c.Dependencies(), 1, "expected 1 dependency for this chart") } func TestDependentChartsWithSubchartsAllSpecifiedInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-with-all-in-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } - - if len(c.Dependencies()) != len(c.Metadata.Dependencies) { - t.Fatalf("expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") + require.Len(t, c.Dependencies(), len(c.Metadata.Dependencies), "expected number of chart dependencies %d, but got %d", len(c.Metadata.Dependencies), len(c.Dependencies())) } func TestDependentChartsWithSomeSubchartsSpecifiedInDependency(t *testing.T) { c := loadChart(t, "testdata/dependent-chart-with-mixed-requirements-yaml") - if len(c.Dependencies()) != 2 { - t.Fatalf("expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) - } - - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected no changes in dependencies") - } - - if len(c.Metadata.Dependencies) != 1 { - t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) - } + require.Len(t, c.Dependencies(), 2, "expected 2 dependencies for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected no changes in dependencies") + require.Len(t, c.Metadata.Dependencies, 1, "expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) } func validateDependencyTree(t *testing.T, c *chart.Chart) { t.Helper() for _, dependency := range c.Dependencies() { if dependency.Parent() != c { - if dependency.Parent() != c { - t.Fatalf("dependency chart %s has wrong parent, expected %s but got %s", dependency.Name(), c.Name(), dependency.Parent().Name()) - } + require.Equal(t, c, dependency.Parent(), "dependency chart %s has wrong parent, expected %s but got %s", dependency.Name(), c.Name(), dependency.Parent().Name()) } // recurse entire tree validateDependencyTree(t, dependency) @@ -554,16 +420,9 @@ func validateDependencyTree(t *testing.T, c *chart.Chart) { func TestChartWithDependencyAliasedTwiceAndDoublyReferencedSubDependency(t *testing.T) { c := loadChart(t, "testdata/chart-with-dependency-aliased-twice") - if len(c.Dependencies()) != 1 { - t.Fatalf("expected one dependency for this chart, but got %d", len(c.Dependencies())) - } + require.Len(t, c.Dependencies(), 1, "expected one dependency for this chart, but got %d", len(c.Dependencies())) + require.NoErrorf(t, processDependencyEnabled(c, c.Values, ""), "expected no errors") + require.Len(t, c.Dependencies(), 2, "expected two dependencies after processing aliases") - if err := processDependencyEnabled(c, c.Values, ""); err != nil { - t.Fatalf("expected no errors but got %q", err) - } - - if len(c.Dependencies()) != 2 { - t.Fatal("expected two dependencies after processing aliases") - } validateDependencyTree(t, c) } diff --git a/pkg/chart/v2/util/expand_test.go b/pkg/chart/v2/util/expand_test.go index e9e298b81..bc8cc7855 100644 --- a/pkg/chart/v2/util/expand_test.go +++ b/pkg/chart/v2/util/expand_test.go @@ -47,19 +47,18 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff fStat, err := f.Stat() require.NoError(t, err) - err = tw.WriteHeader(&tar.Header{ + require.NoError(t, tw.WriteHeader(&tar.Header{ Name: filepath.Join(chartName, relPath), Mode: int64(fStat.Mode()), Size: fStat.Size(), - }) - require.NoError(t, err) + })) data, err := fs.ReadFile(dir, relPath) require.NoError(t, err) tw.Write(data) } - err := fs.WalkDir(dir, ".", func(path string, d os.DirEntry, walkErr error) error { + require.NoError(t, fs.WalkDir(dir, ".", func(path string, d os.DirEntry, walkErr error) error { if walkErr != nil { return walkErr } @@ -71,15 +70,9 @@ func makeTestChartArchive(t *testing.T, chartName, sourceDir string) *bytes.Buff writeFile(path) return nil - }) - if err != nil { - t.Fatal(err) - } - - err = tw.Close() - require.NoError(t, err) - err = gw.Close() - require.NoError(t, err) + })) + require.NoError(t, tw.Close()) + require.NoError(t, gw.Close()) return &result } @@ -88,51 +81,33 @@ func TestExpand(t *testing.T) { dest := t.TempDir() reader, err := os.Open("testdata/frobnitz-1.2.3.tgz") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if err := Expand(dest, reader); err != nil { - t.Fatal(err) - } + require.NoError(t, Expand(dest, reader)) expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) - if err != nil { - t.Fatal(err) - } - if !fi.IsDir() { - t.Fatalf("expected a chart directory at %s", expectedChartPath) - } + require.NoError(t, err) + require.Truef(t, fi.IsDir(), "expected a chart directory at %s", expectedChartPath) dir, err := os.Open(expectedChartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) fis, err := dir.Readdir(0) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expectLen := 11 - if len(fis) != expectLen { - t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) - } + assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // os.Stat can return different values for directories, based on the OS // for Linux, for example, os.Stat always returns the size of the directory // (value-4096) regardless of the size of the contents of the directory mode := expect.Mode() if !mode.IsDir() { - if fi.Size() != expect.Size() { - t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) - } + assert.Equal(t, expect.Size(), fi.Size(), "Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) } } } @@ -151,10 +126,9 @@ func TestExpandError(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { archive := makeTestChartArchive(t, tt.chartName, tt.chartDir) - dest := t.TempDir() - err := Expand(dest, archive) - assert.ErrorContains(t, err, tt.wantErr) + + assert.ErrorContains(t, Expand(dest, archive), tt.wantErr) }) } } @@ -162,47 +136,31 @@ func TestExpandError(t *testing.T) { func TestExpandFile(t *testing.T) { dest := t.TempDir() - if err := ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz"); err != nil { - t.Fatal(err) - } + require.NoError(t, ExpandFile(dest, "testdata/frobnitz-1.2.3.tgz")) expectedChartPath := filepath.Join(dest, "frobnitz") fi, err := os.Stat(expectedChartPath) - if err != nil { - t.Fatal(err) - } - if !fi.IsDir() { - t.Fatalf("expected a chart directory at %s", expectedChartPath) - } + require.NoError(t, err) + require.Truef(t, fi.IsDir(), "expected a chart directory at %s", expectedChartPath) dir, err := os.Open(expectedChartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) fis, err := dir.Readdir(0) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expectLen := 11 - if len(fis) != expectLen { - t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) - } + assert.Len(t, fis, expectLen, "Expected %d files, but got %d", expectLen, len(fis)) for _, fi := range fis { expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // os.Stat can return different values for directories, based on the OS // for Linux, for example, os.Stat always returns the size of the directory // (value-4096) regardless of the size of the contents of the directory mode := expect.Mode() if !mode.IsDir() { - if fi.Size() != expect.Size() { - t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) - } + assert.Equal(t, expect.Size(), fi.Size(), "Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) } } } diff --git a/pkg/chart/v2/util/save_test.go b/pkg/chart/v2/util/save_test.go index 6677c562b..4ed6fa89d 100644 --- a/pkg/chart/v2/util/save_test.go +++ b/pkg/chart/v2/util/save_test.go @@ -38,6 +38,9 @@ import ( "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSave(t *testing.T) { @@ -62,29 +65,16 @@ func TestSave(t *testing.T) { chartWithInvalidJSON := withSchema(*c, []byte("{")) where, err := Save(c, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } - if !strings.HasPrefix(where, dest) { - t.Fatalf("Expected %q to start with %q", where, dest) - } - if !strings.HasSuffix(where, ".tgz") { - t.Fatalf("Expected %q to end with .tgz", where) - } + require.NoError(t, err, "Failed to save") + require.Truef(t, strings.HasPrefix(where, dest), "Expected %q to start with %q", where, dest) + require.Truef(t, strings.HasSuffix(where, ".tgz"), "Expected %q to end with .tgz", where) c2, err := loader.LoadFile(where) - if err != nil { - t.Fatal(err) - } - if c2.Name() != c.Name() { - t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - } - if len(c2.Files) != 1 || c2.Files[0].Name != "scheherazade/shahryar.txt" { - t.Fatal("Files data did not match") - } - if c2.Lock != nil { - t.Fatal("Expected v1 chart archive not to contain Chart.lock file") - } + require.NoError(t, err) + require.Equal(t, c.Name(), c2.Name(), "Expected chart archive to have %q, got %q", c.Name(), c2.Name()) + require.Len(t, c2.Files, 1, "Files data did not match") + require.Equal(t, "scheherazade/shahryar.txt", c2.Files[0].Name, "Files data did not match") + require.Nil(t, c2.Lock, "Expected v1 chart archive not to contain Chart.lock file") if !bytes.Equal(c.Schema, c2.Schema) { indentation := 4 @@ -92,25 +82,16 @@ func TestSave(t *testing.T) { formattedActual := Indent(indentation, string(c2.Schema)) t.Fatalf("Schema data did not match.\nExpected:\n%s\nActual:\n%s", formattedExpected, formattedActual) } - if _, err := Save(&chartWithInvalidJSON, dest); err == nil { - t.Fatal("Invalid JSON was not caught while saving chart") - } + _, err = Save(&chartWithInvalidJSON, dest) + require.Error(t, err, "Invalid JSON was not caught while saving chart") c.Metadata.APIVersion = chart.APIVersionV2 where, err = Save(c, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") c2, err = loader.LoadFile(where) - if err != nil { - t.Fatal(err) - } - if c2.Lock == nil { - t.Fatal("Expected v2 chart archive to contain a Chart.lock file") - } - if c2.Lock.Digest != c.Lock.Digest { - t.Fatal("Chart.lock data did not match") - } + require.NoError(t, err) + require.NotNil(t, c2.Lock, "Expected v2 chart archive to contain a Chart.lock file") + require.Equal(t, c.Lock.Digest, c2.Lock.Digest, "Chart.lock data did not match") }) } @@ -128,9 +109,7 @@ func TestSave(t *testing.T) { }, } _, err := Save(c, tmp) - if err == nil { - t.Fatal("Expected error saving chart with invalid name") - } + require.Error(t, err, "Expected error saving chart with invalid name") } // https://github.com/helm/helm/issues/31844 @@ -145,20 +124,14 @@ func TestSavedGzipExtraFieldIsValid(t *testing.T) { } where, err := Save(c, tmp) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") f, err := os.Open(where) - if err != nil { - t.Fatalf("Failed to open saved file: %s", err) - } + require.NoError(t, err, "Failed to open saved file") defer f.Close() r, err := gzip.NewReader(f) - if err != nil { - t.Fatalf("Failed to create gzip reader: %s", err) - } + require.NoError(t, err, "Failed to create gzip reader") defer r.Close() // RFC 1952 §2.3.1.1: @@ -356,20 +329,14 @@ func TestSavePreservesTimestamps(t *testing.T) { } where, err := Save(c, tmp) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") allHeaders, err := retrieveAllHeadersFromTar(where) - if err != nil { - t.Fatalf("Failed to parse tar: %v", err) - } + require.NoError(t, err, "Failed to parse tar") roundedTime := initialCreateTime.Round(time.Second) for _, header := range allHeaders { - if !header.ModTime.Equal(roundedTime) { - t.Fatalf("File timestamp not preserved: %v", header.ModTime) - } + require.Truef(t, header.ModTime.Equal(roundedTime), "File timestamp not preserved: %v", header.ModTime) } } @@ -390,20 +357,14 @@ func TestSaveWithSourceDateEpoch(t *testing.T) { c.StampModTimes(epoch) where, err := Save(c, tmp) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") allHeaders, err := retrieveAllHeadersFromTar(where) - if err != nil { - t.Fatalf("Failed to parse tar: %v", err) - } + require.NoError(t, err, "Failed to parse tar") expected := epoch.Round(time.Second) for _, header := range allHeaders { - if !header.ModTime.Equal(expected) { - t.Fatalf("Expected SOURCE_DATE_EPOCH timestamp %v, got %v for %q", expected, header.ModTime, header.Name) - } + require.Truef(t, header.ModTime.Equal(expected), "Expected SOURCE_DATE_EPOCH timestamp %v, got %v for %q", expected, header.ModTime, header.Name) } } @@ -459,37 +420,25 @@ func TestSaveDir(t *testing.T) { }, } - if err := SaveDir(c, tmp); err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoErrorf(t, SaveDir(c, tmp), "Failed to save") c2, err := loader.LoadDir(tmp + "/ahab") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if c2.Name() != c.Name() { - t.Fatalf("Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - } + require.Equal(t, c.Name(), c2.Name(), "Expected chart archive to have %q, got %q", c.Name(), c2.Name()) - if len(c2.Templates) != 1 || c2.Templates[0].Name != c.Templates[0].Name { - t.Fatal("Templates data did not match") - } + require.Len(t, c2.Templates, 1, "Templates data did not match") + require.Equal(t, c2.Templates[0].Name, c.Templates[0].Name, "Templates data did not match") - if len(c2.Files) != 1 || c2.Files[0].Name != c.Files[0].Name { - t.Fatal("Files data did not match") - } + require.Len(t, c2.Files, 1, "Files data did not match") + require.Equal(t, c2.Files[0].Name, c.Files[0].Name, "Files data did not match") tmp2 := t.TempDir() c.Metadata.Name = "../ahab" pth := filepath.Join(tmp2, "tmpcharts") - if err := os.MkdirAll(filepath.Join(pth), 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(pth), 0o755)) - if err := SaveDir(c, pth); err.Error() != "\"../ahab\" is not a valid chart name" { - t.Fatalf("Did not get expected error for chart named %q", c.Name()) - } + require.EqualErrorf(t, SaveDir(c, pth), "\"../ahab\" is not a valid chart name", "Did not get expected error for chart named %q", c.Name()) } func TestRepeatableSave(t *testing.T) { @@ -550,18 +499,12 @@ func TestRepeatableSave(t *testing.T) { // create package dest := path.Join(tmp, "newdir") where, err := Save(test.chart, dest) - if err != nil { - t.Fatalf("Failed to save: %s", err) - } + require.NoError(t, err, "Failed to save") // get shasum for package result, err := sha256Sum(where) - if err != nil { - t.Fatalf("Failed to check shasum: %s", err) - } + require.NoError(t, err, "Failed to check shasum") // assert that the package SHA is what we wanted. - if result != test.want { - t.Errorf("FormatName() result = %v, want %v", result, test.want) - } + assert.Equal(t, test.want, result, "FormatName() result = %v, want %v", result, test.want) }) } } diff --git a/pkg/chart/v2/util/validate_name_test.go b/pkg/chart/v2/util/validate_name_test.go index cfc62a0f7..9095dc4dc 100644 --- a/pkg/chart/v2/util/validate_name_test.go +++ b/pkg/chart/v2/util/validate_name_test.go @@ -16,7 +16,11 @@ limitations under the License. package util -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) // TestValidateReleaseName is a regression test for ValidateName // @@ -46,12 +50,11 @@ func TestValidateReleaseName(t *testing.T) { "a1111111111111111111111111111111111111111111111111111111111z": false, } for input, expectPass := range names { - if err := ValidateReleaseName(input); (err == nil) != expectPass { - st := "fail" - if expectPass { - st = "succeed" - } - t.Errorf("Expected %q to %s", input, st) + err := ValidateReleaseName(input) + if expectPass { + assert.NoError(t, err) + } else { + assert.Error(t, err) } } } @@ -80,12 +83,11 @@ func TestValidateMetadataName(t *testing.T) { "a1111111111111111111111111111111111111111111111111111111111z": false, } for input, expectPass := range names { - if err := ValidateMetadataName(input); (err == nil) != expectPass { - st := "fail" - if expectPass { - st = "succeed" - } - t.Errorf("Expected %q to %s", input, st) + err := ValidateMetadataName(input) + if expectPass { + assert.NoError(t, err) + } else { + assert.Error(t, err) } } } diff --git a/pkg/cli/environment_test.go b/pkg/cli/environment_test.go index 9303389a3..fc71038f8 100644 --- a/pkg/cli/environment_test.go +++ b/pkg/cli/environment_test.go @@ -18,6 +18,7 @@ package cli import ( "os" + "path/filepath" "strings" "testing" @@ -119,7 +120,8 @@ func TestEnvSettings(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - defer resetEnv()() + cleanup := resetEnv() + t.Cleanup(cleanup) for k, v := range tt.envvars { t.Setenv(k, v) @@ -218,7 +220,30 @@ func TestEnvOrBool(t *testing.T) { } func TestUserAgentHeaderInK8sRESTClientConfig(t *testing.T) { - defer resetEnv()() + cleanup := resetEnv() + t.Cleanup(cleanup) + + kubeconfigPath := filepath.Join(t.TempDir(), "config") + kubeconfig := `apiVersion: v1 +clusters: +- cluster: + server: https://127.0.0.1:6443 + name: test +contexts: +- context: + cluster: test + user: test-user + name: test +current-context: test +kind: Config +preferences: {} +users: +- name: test-user + user: + token: test-token +` + require.NoError(t, os.WriteFile(kubeconfigPath, []byte(kubeconfig), 0o600), "failed to create test kubeconfig") + t.Setenv("KUBECONFIG", kubeconfigPath) settings := New() restConfig, err := settings.RESTClientGetter().ToRESTConfig() diff --git a/pkg/cli/values/options_test.go b/pkg/cli/values/options_test.go index 40590f33f..6debb693e 100644 --- a/pkg/cli/values/options_test.go +++ b/pkg/cli/values/options_test.go @@ -215,19 +215,17 @@ func TestReadFile(t *testing.T) { got, err := readFile(actualFilePath, tt.providers) require.NoError(t, err, "readFile() expected no error for stdin") assert.Equal(t, testData, got) - return - } - - // Regular test cases - got, err := readFile(actualFilePath, tt.providers) - if tt.expectError { - assert.Error(t, err) - return - } - require.NoError(t, err) - - if tt.expectedData != nil { - assert.Equal(t, tt.expectedData, got) + } else { + // Regular test cases + got, err := readFile(actualFilePath, tt.providers) + if tt.expectError { + assert.Error(t, err) + } else { + require.NoError(t, err) + if tt.expectedData != nil { + assert.Equal(t, tt.expectedData, got) + } + } } }) } @@ -356,10 +354,10 @@ func TestMergeValuesCLI(t *testing.T) { got, err := tt.opts.MergeValues(getter.Providers{}) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected, got) } - require.NoError(t, err) - assert.Equal(t, tt.expected, got) }) } } diff --git a/pkg/cmd/completion_test.go b/pkg/cmd/completion_test.go index 399ff1f0c..296ae457e 100644 --- a/pkg/cmd/completion_test.go +++ b/pkg/cmd/completion_test.go @@ -18,9 +18,11 @@ package cmd import ( "fmt" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/release/common" release "helm.sh/helm/v4/pkg/release/v1" @@ -44,16 +46,11 @@ func checkFileCompletion(t *testing.T, cmdName string, shouldBePerformed bool) { testcmd := fmt.Sprintf("__complete %s ''", cmdName) _, out, err := executeActionCommandC(storage, testcmd) - if err != nil { - t.Errorf("unexpected error, %s", err) - } - if !strings.Contains(out, "ShellCompDirectiveNoFileComp") != shouldBePerformed { - if shouldBePerformed { - t.Errorf("Unexpected directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) - } else { - t.Errorf("Did not receive directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) - } - t.Log(out) + require.NoError(t, err) + if shouldBePerformed { + assert.NotContains(t, out, "ShellCompDirectiveNoFileComp", "Unexpected directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) + } else { + assert.Contains(t, out, "ShellCompDirectiveNoFileComp", "Did not receive directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName) } } diff --git a/pkg/cmd/create_test.go b/pkg/cmd/create_test.go index 1a1289775..6f25d4c63 100644 --- a/pkg/cmd/create_test.go +++ b/pkg/cmd/create_test.go @@ -22,6 +22,9 @@ import ( "slices" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chartv3 "helm.sh/helm/v4/internal/chart/v3" chartutilv3 "helm.sh/helm/v4/internal/chart/v3/util" "helm.sh/helm/v4/internal/gates" @@ -39,38 +42,25 @@ func TestCreateCmd(t *testing.T) { cname := "testchart" // Run a create - if _, _, err := executeActionCommand("create " + cname); err != nil { - t.Fatalf("Failed to run create: %s", err) - } + _, _, err := executeActionCommand("create " + cname) + require.NoErrorf(t, err, "Failed to run create") // Test that the chart is there - if fi, err := os.Stat(cname); err != nil { - t.Fatalf("no chart directory: %s", err) - } else if !fi.IsDir() { - t.Fatal("chart is not directory") - } + fi, err := os.Stat(cname) + require.NoErrorf(t, err, "no chart directory") + require.Truef(t, fi.IsDir(), "chart is not directory") c, err := chartloader.LoadDir(cname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) acc, err := chart.NewAccessor(c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if acc.Name() != cname { - t.Errorf("Expected %q name, got %q", cname, acc.Name()) - } + assert.Equal(t, cname, acc.Name(), "Expected %q name, got %q", cname, acc.Name()) metadata := acc.MetadataAsMap() apiVersion, ok := metadata["APIVersion"].(string) - if !ok { - t.Fatal("APIVersion not found in metadata") - } - if apiVersion != chartv2.APIVersionV2 { - t.Errorf("Wrong API version: %q", apiVersion) - } + require.True(t, ok, "APIVersion not found in metadata") + assert.Equal(t, chartv2.APIVersionV2, apiVersion, "Wrong API version: %q", apiVersion) } func TestCreateStarterCmd(t *testing.T) { @@ -123,15 +113,11 @@ func TestCreateStarterCmd(t *testing.T) { } else { dest, err = chartutil.Create("starterchart", starterchart) } - if err != nil { - t.Fatalf("Could not create chart: %s", err) - } + require.NoError(t, err, "Could not create chart") t.Logf("Created %s", dest) tplpath := filepath.Join(starterchart, "starterchart", "templates", "foo.tpl") - if err := os.WriteFile(tplpath, []byte("test"), 0o644); err != nil { - t.Fatalf("Could not write template: %s", err) - } + require.NoErrorf(t, os.WriteFile(tplpath, []byte("test"), 0o644), "Could not write template") // Build the command starterArg := "starterchart" @@ -147,51 +133,36 @@ func TestCreateStarterCmd(t *testing.T) { cmd += " " + cname // Run create - if _, _, err := executeActionCommand(cmd); err != nil { - t.Fatalf("Failed to run create: %s", err) - } + _, _, err = executeActionCommand(cmd) + require.NoErrorf(t, err, "Failed to run create") // Test that the chart is there - if fi, err := os.Stat(cname); err != nil { - t.Fatalf("no chart directory: %s", err) - } else if !fi.IsDir() { - t.Fatal("chart is not directory") - } + fi, err := os.Stat(cname) + require.NoErrorf(t, err, "no chart directory") + require.Truef(t, fi.IsDir(), "chart is not directory") // Load and verify the chart c, err := chartloader.LoadDir(cname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) acc, err := chart.NewAccessor(c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) chartName := acc.Name() metadata := acc.MetadataAsMap() apiVersion, ok := metadata["APIVersion"].(string) - if !ok { - t.Fatal("APIVersion not found in metadata") - } + require.True(t, ok, "APIVersion not found in metadata") var templates []string for _, tpl := range acc.Templates() { templates = append(templates, tpl.Name) } - if chartName != cname { - t.Errorf("Expected %q name, got %q", cname, chartName) - } - if apiVersion != tt.expectedVersion { - t.Errorf("Wrong API version: expected %q, got %q", tt.expectedVersion, apiVersion) - } + assert.Equal(t, cname, chartName, "Expected %q name, got %q", cname, chartName) + assert.Equal(t, tt.expectedVersion, apiVersion, "Wrong API version: expected %q, got %q", tt.expectedVersion, apiVersion) // Verify custom template exists found := slices.Contains(templates, "templates/foo.tpl") - if !found { - t.Error("Did not find foo.tpl") - } + assert.True(t, found, "Did not find foo.tpl") }) } } @@ -207,38 +178,25 @@ func TestCreateCmdChartAPIVersionV2(t *testing.T) { cname := "testchart" // Run a create with explicit v2 - if _, _, err := executeActionCommand("create --chart-api-version=v2 " + cname); err != nil { - t.Fatalf("Failed to run create: %s", err) - } + _, _, err := executeActionCommand("create --chart-api-version=v2 " + cname) + require.NoErrorf(t, err, "Failed to run create") // Test that the chart is there - if fi, err := os.Stat(cname); err != nil { - t.Fatalf("no chart directory: %s", err) - } else if !fi.IsDir() { - t.Fatal("chart is not directory") - } + fi, err := os.Stat(cname) + require.NoErrorf(t, err, "no chart directory") + require.Truef(t, fi.IsDir(), "chart is not directory") c, err := chartloader.LoadDir(cname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) acc, err := chart.NewAccessor(c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if acc.Name() != cname { - t.Errorf("Expected %q name, got %q", cname, acc.Name()) - } + assert.Equal(t, cname, acc.Name(), "Expected %q name, got %q", cname, acc.Name()) metadata := acc.MetadataAsMap() apiVersion, ok := metadata["APIVersion"].(string) - if !ok { - t.Fatal("APIVersion not found in metadata") - } - if apiVersion != chartv2.APIVersionV2 { - t.Errorf("Wrong API version: expected %q, got %q", chartv2.APIVersionV2, apiVersion) - } + require.True(t, ok, "APIVersion not found in metadata") + assert.Equal(t, chartv2.APIVersionV2, apiVersion, "Wrong API version: expected %q, got %q", chartv2.APIVersionV2, apiVersion) } func TestCreateCmdChartAPIVersionV3(t *testing.T) { @@ -248,38 +206,25 @@ func TestCreateCmdChartAPIVersionV3(t *testing.T) { cname := "testchart" // Run a create with v3 - if _, _, err := executeActionCommand("create --chart-api-version=v3 " + cname); err != nil { - t.Fatalf("Failed to run create: %s", err) - } + _, _, err := executeActionCommand("create --chart-api-version=v3 " + cname) + require.NoErrorf(t, err, "Failed to run create") // Test that the chart is there - if fi, err := os.Stat(cname); err != nil { - t.Fatalf("no chart directory: %s", err) - } else if !fi.IsDir() { - t.Fatal("chart is not directory") - } + fi, err := os.Stat(cname) + require.NoErrorf(t, err, "no chart directory") + require.Truef(t, fi.IsDir(), "chart is not directory") c, err := chartloader.LoadDir(cname) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) acc, err := chart.NewAccessor(c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if acc.Name() != cname { - t.Errorf("Expected %q name, got %q", cname, acc.Name()) - } + assert.Equal(t, cname, acc.Name(), "Expected %q name, got %q", cname, acc.Name()) metadata := acc.MetadataAsMap() apiVersion, ok := metadata["APIVersion"].(string) - if !ok { - t.Fatal("APIVersion not found in metadata") - } - if apiVersion != chartv3.APIVersionV3 { - t.Errorf("Wrong API version: expected %q, got %q", chartv3.APIVersionV3, apiVersion) - } + require.True(t, ok, "APIVersion not found in metadata") + assert.Equal(t, chartv3.APIVersionV3, apiVersion, "Wrong API version: expected %q, got %q", chartv3.APIVersionV3, apiVersion) } func TestCreateCmdInvalidChartAPIVersion(t *testing.T) { @@ -289,12 +234,8 @@ func TestCreateCmdInvalidChartAPIVersion(t *testing.T) { // Run a create with invalid version _, _, err := executeActionCommand("create --chart-api-version=v1 " + cname) - if err == nil { - t.Fatal("Expected error for invalid API version, got nil") - } + require.Error(t, err, "Expected error for invalid API version, got nil") expectedErr := "unsupported chart API version: v1 (supported: v2, v3)" - if err.Error() != expectedErr { - t.Errorf("Expected error %q, got %q", expectedErr, err.Error()) - } + assert.EqualError(t, err, expectedErr, "Expected error %q, got %q", expectedErr, err.Error()) } diff --git a/pkg/cmd/dependency_build_test.go b/pkg/cmd/dependency_build_test.go index 7b3bea28a..485ae18b3 100644 --- a/pkg/cmd/dependency_build_test.go +++ b/pkg/cmd/dependency_build_test.go @@ -19,9 +19,11 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chartutil "helm.sh/helm/v4/pkg/chart/v2/util" "helm.sh/helm/v4/pkg/provenance" "helm.sh/helm/v4/pkg/repo/v1" @@ -39,15 +41,12 @@ func TestDependencyBuildCmd(t *testing.T) { srv.LinkIndices() ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ociChartName := "oci-depending-chart" c := createTestingMetadataForOCI(ociChartName, ociSrv.RegistryURL) - if _, err := chartutil.Save(c, ociSrv.Dir); err != nil { - t.Fatal(err) - } + _, err = chartutil.Save(c, ociSrv.Dir) + require.NoError(t, err) ociSrv.Run(t, repotest.WithDependingChart(c)) dir := func(p ...string) string { @@ -67,25 +66,19 @@ func TestDependencyBuildCmd(t *testing.T) { t.Fatal(err) } - if !strings.Contains(out, `update from the "test" chart repository`) { - t.Errorf("Repo did not get updated\n%s", out) - } + assert.Contains(t, out, `update from the "test" chart repository`, "Repo did not get updated\n%s", out) // Make sure the actual file got downloaded. expect := filepath.Join(rootDir, chartname, "charts", "reqtest-0.1.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) // In the second pass, we want to remove the chart's request dependency, // then see if it restores from the lock. lockfile := filepath.Join(rootDir, chartname, "Chart.lock") - if _, err := os.Stat(lockfile); err != nil { - t.Fatal(err) - } - if err := os.RemoveAll(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(lockfile) + require.NoError(t, err) + require.NoError(t, os.RemoveAll(expect)) _, out, err = executeActionCommand(cmd) if err != nil { @@ -94,28 +87,21 @@ func TestDependencyBuildCmd(t *testing.T) { } // Now repeat the test that the dependency exists. - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) // Make sure that build is also fetching the correct version. hash, err := provenance.DigestFile(expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) i, err := repo.LoadIndexFile(filepath.Join(rootDir, "index.yaml")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) reqver := i.Entries["reqtest"][0] - if h := reqver.Digest; h != hash { - t.Errorf("Failed hash match: expected %s, got %s", hash, h) - } - if v := reqver.Version; v != "0.1.0" { - t.Errorf("mismatched versions. Expected %q, got %q", "0.1.0", v) - } + h := reqver.Digest + assert.Equalf(t, h, hash, "Failed hash match: expected %s, got %s", hash, h) + v := reqver.Version + assert.Equalf(t, "0.1.0", v, "mismatched versions. Expected %q, got %q", "0.1.0", v) skipRefreshCmd := fmt.Sprintf("dependency build '%s' --skip-refresh --repository-config %s --repository-cache %s --plain-http", filepath.Join(rootDir, chartname), repoFile, rootDir) _, out, err = executeActionCommand(skipRefreshCmd) @@ -126,14 +112,10 @@ func TestDependencyBuildCmd(t *testing.T) { t.Fatal(err) } - if strings.Contains(out, `update from the "test" chart repository`) { - t.Errorf("Repo did get updated\n%s", out) - } + assert.NotContains(t, out, `update from the "test" chart repository`, "Repo did get updated\n%s", out) // OCI dependencies - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) cmd = fmt.Sprintf("dependency build '%s' --repository-config %s --repository-cache %s --registry-config %s/config.json --plain-http", dir(ociChartName), dir("repositories.yaml"), @@ -145,9 +127,8 @@ func TestDependencyBuildCmd(t *testing.T) { t.Fatal(err) } expect = dir(ociChartName, "charts/oci-dependent-chart-0.1.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) } func TestDependencyBuildCmdWithHelmV2Hash(t *testing.T) { diff --git a/pkg/cmd/dependency_update_test.go b/pkg/cmd/dependency_update_test.go index f9ff68097..13eb74532 100644 --- a/pkg/cmd/dependency_update_test.go +++ b/pkg/cmd/dependency_update_test.go @@ -16,14 +16,15 @@ limitations under the License. package cmd import ( - "errors" "fmt" "io/fs" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" chart "helm.sh/helm/v4/pkg/chart/v2" chartutil "helm.sh/helm/v4/pkg/chart/v2/util" @@ -42,21 +43,16 @@ func TestDependencyUpdateCmd(t *testing.T) { t.Logf("Listening on directory %s", srv.Root()) ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) contentCache := t.TempDir() ociChartName := "oci-depending-chart" c := createTestingMetadataForOCI(ociChartName, ociSrv.RegistryURL) - if _, err := chartutil.Save(c, ociSrv.Dir); err != nil { - t.Fatal(err) - } + _, err = chartutil.Save(c, ociSrv.Dir) + require.NoError(t, err) ociSrv.Run(t, repotest.WithDependingChart(c)) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) dir := func(p ...string) string { return filepath.Join(append([]string{srv.Root()}, p...)...) @@ -65,9 +61,7 @@ func TestDependencyUpdateCmd(t *testing.T) { chartname := "depup" ch := createTestingMetadata(chartname, srv.URL()) md := ch.Metadata - if err := chartutil.SaveDir(ch, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(ch, dir())) _, out, err := executeActionCommand( fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --content-cache %s --plain-http", dir(chartname), dir("repositories.yaml"), dir(), contentCache), @@ -78,30 +72,22 @@ func TestDependencyUpdateCmd(t *testing.T) { } // This is written directly to stdout, so we have to capture as is. - if !strings.Contains(out, `update from the "test" chart repository`) { - t.Errorf("Repo did not get updated\n%s", out) - } + assert.Contains(t, out, `update from the "test" chart repository`, "Repo did not get updated\n%s", out) // Make sure the actual file got downloaded. expect := dir(chartname, "charts/reqtest-0.1.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) hash, err := provenance.DigestFile(expect) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) i, err := repo.LoadIndexFile(dir(helmpath.CacheIndexFile("test"))) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) reqver := i.Entries["reqtest"][0] - if h := reqver.Digest; h != hash { - t.Errorf("Failed hash match: expected %s, got %s", hash, h) - } + h := reqver.Digest + assert.Equalf(t, h, hash, "Failed hash match: expected %s, got %s", hash, h) // Now change the dependencies and update. This verifies that on update, // old dependencies are cleansed and new dependencies are added. @@ -109,9 +95,7 @@ func TestDependencyUpdateCmd(t *testing.T) { {Name: "reqtest", Version: "0.1.0", Repository: srv.URL()}, {Name: "compressedchart", Version: "0.3.0", Repository: srv.URL()}, } - if err := chartutil.SaveChartfile(dir(chartname, "Chart.yaml"), md); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveChartfile(dir(chartname, "Chart.yaml"), md)) _, out, err = executeActionCommand(fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --content-cache %s --plain-http", dir(chartname), dir("repositories.yaml"), dir(), contentCache)) if err != nil { @@ -122,18 +106,14 @@ func TestDependencyUpdateCmd(t *testing.T) { // In this second run, we should see compressedchart-0.3.0.tgz, and not // the 0.1.0 version. expect = dir(chartname, "charts/compressedchart-0.3.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatalf("Expected %q: %s", expect, err) - } + _, err = os.Stat(expect) + require.NoErrorf(t, err, "Expected %q", expect) unexpected := dir(chartname, "charts/compressedchart-0.1.0.tgz") - if _, err := os.Stat(unexpected); err == nil { - t.Fatalf("Unexpected %q", unexpected) - } + _, err = os.Stat(unexpected) + require.Errorf(t, err, "Unexpected %q", unexpected) // test for OCI charts - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) cmd := fmt.Sprintf("dependency update '%s' --repository-config %s --repository-cache %s --registry-config %s/config.json --content-cache %s --plain-http", dir(ociChartName), dir("repositories.yaml"), @@ -146,9 +126,8 @@ func TestDependencyUpdateCmd(t *testing.T) { t.Fatal(err) } expect = dir(ociChartName, "charts/oci-dependent-chart-0.1.0.tgz") - if _, err := os.Stat(expect); err != nil { - t.Fatal(err) - } + _, err = os.Stat(expect) + require.NoError(t, err) } func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) { @@ -162,9 +141,7 @@ func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) { defer srv.Stop() t.Logf("Listening on directory %s", srv.Root()) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) chartname := "depupdelete" @@ -191,25 +168,18 @@ func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) { // Make sure charts dir still has dependencies files, err := os.ReadDir(filepath.Join(dir(chartname), "charts")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) dependencies := []string{"compressedchart-0.1.0.tgz", "reqtest-0.1.0.tgz"} - if len(dependencies) != len(files) { - t.Fatalf("Expected %d chart dependencies, got %d", len(dependencies), len(files)) - } + require.Len(t, dependencies, len(files), "Expected %d chart dependencies, got %d", len(dependencies), len(files)) for index, file := range files { - if dependencies[index] != file.Name() { - t.Fatalf("Chart dependency %s not matching %s", dependencies[index], file.Name()) - } + require.Equal(t, file.Name(), dependencies[index], "Chart dependency %s not matching %s", dependencies[index], file.Name()) } // Make sure tmpcharts-x is deleted tmpPath := filepath.Join(dir(chartname), fmt.Sprintf("tmpcharts-%d", os.Getpid())) - if _, err := os.Stat(tmpPath); !errors.Is(err, fs.ErrNotExist) { - t.Fatal("tmpcharts dir still exists") - } + _, err = os.Stat(tmpPath) + require.ErrorIs(t, err, fs.ErrNotExist, "tmpcharts dir still exists") } func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) { @@ -231,9 +201,7 @@ func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) { } ch.Metadata.Dependencies = append(ch.Metadata.Dependencies, chartDependency) - if err := chartutil.SaveDir(ch, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(ch, dir())) contentCache := t.TempDir() @@ -248,10 +216,8 @@ func TestDependencyUpdateCmd_WithRepoThatWasNotAdded(t *testing.T) { } // This is written directly to stdout, so we have to capture as is - if !strings.Contains(out, `Getting updates for unmanaged Helm repositories...`) { - t.Errorf("No ‘unmanaged’ Helm repo used in test chartdependency or it doesn’t cause the creation "+ - "of an ‘ad hoc’ repo index cache file\n%s", out) - } + assert.Contains(t, out, `Getting updates for unmanaged Helm repositories...`, "No ‘unmanaged’ Helm repo used in test chartdependency or it doesn’t cause the creation "+ + "of an ‘ad hoc’ repo index cache file\n%s", out) } func setupMockRepoServer(t *testing.T) *repotest.Server { @@ -263,9 +229,7 @@ func setupMockRepoServer(t *testing.T) *repotest.Server { t.Logf("Listening on directory %s", srv.Root()) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) return srv } @@ -306,7 +270,5 @@ func createTestingMetadataForOCI(name, registryURL string) *chart.Chart { func createTestingChart(t *testing.T, dest, name, baseURL string) { t.Helper() cfile := createTestingMetadata(name, baseURL) - if err := chartutil.SaveDir(cfile, dest); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(cfile, dest)) } diff --git a/pkg/cmd/flags.go b/pkg/cmd/flags.go index e7db3dde2..e59487044 100644 --- a/pkg/cmd/flags.go +++ b/pkg/cmd/flags.go @@ -65,6 +65,26 @@ func AddWaitFlag(cmd *cobra.Command, wait *kube.WaitStrategy) { cmd.Flags().Lookup("wait").NoOptDefVal = string(kube.StatusWatcherStrategy) } +// cliDefaultStatusComputeWorkers is the number of concurrent status-compute +// workers the Helm CLI enables by default. This prevents the informer +// notification pipeline from being blocked by slow API calls (e.g. LIST +// ReplicaSets/Pods for Deployments) when many resources are updated +// simultaneously. See https://github.com/fluxcd/cli-utils/pull/20. +// +// SDK consumers (e.g. helm-controller) inherit the zero value and can opt in +// via kube.WithStatusComputeWorkers when they want the same behavior. +const cliDefaultStatusComputeWorkers = 8 + +// defaultCLIWaitOptions returns the set of WaitOptions the Helm CLI applies +// by default to every wait-enabled command. Keeping these in one place keeps +// behavior consistent across install/upgrade/rollback/uninstall and makes the +// CLI-vs-SDK default asymmetry explicit. +func defaultCLIWaitOptions() []kube.WaitOption { + return []kube.WaitOption{ + kube.WithStatusComputeWorkers(cliDefaultStatusComputeWorkers), + } +} + type waitValue kube.WaitStrategy func newWaitValue(defaultValue kube.WaitStrategy, ws *kube.WaitStrategy) *waitValue { diff --git a/pkg/cmd/flags_test.go b/pkg/cmd/flags_test.go index 614970252..09dc61638 100644 --- a/pkg/cmd/flags_test.go +++ b/pkg/cmd/flags_test.go @@ -110,14 +110,11 @@ func TestPostRendererFlagSetOnce(t *testing.T) { }, } // Set the plugin name once - err := str.Set("postrenderer-v1") - require.NoError(t, err) + require.NoError(t, str.Set("postrenderer-v1")) // Set the plugin name again to the same value is not ok - err = str.Set("postrenderer-v1") - require.Error(t, err) + require.Error(t, str.Set("postrenderer-v1")) // Set the plugin name again to a different value is not ok - err = str.Set("cat") - require.Error(t, err) + require.Error(t, str.Set("cat")) } diff --git a/pkg/cmd/helpers_test.go b/pkg/cmd/helpers_test.go index 3db5f38ab..611d1a54c 100644 --- a/pkg/cmd/helpers_test.go +++ b/pkg/cmd/helpers_test.go @@ -56,17 +56,14 @@ func runTestCmd(t *testing.T, tests []cmdTestCase) { storage := storageFixture() for _, rel := range tt.rels { - if err := storage.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, storage.Create(rel)) } t.Logf("running cmd (attempt %d): %s", i+1, tt.cmd) _, out, err := executeActionCommandC(storage, tt.cmd) - if tt.wantError && err == nil { - t.Errorf("expected error, got success with the following output:\n%s", out) - } - if !tt.wantError && err != nil { - t.Errorf("expected no error, got: '%v'", err) + if tt.wantError { + require.Error(t, err, "expected error, got success with the following output:\n%s", out) + } else { + require.NoError(t, err, "expected no error") } if tt.golden != "" { test.AssertGoldenString(t, out, tt.golden) @@ -294,8 +291,7 @@ func TestCmdGetDryRunFlagStrategy(t *testing.T) { if tc.ExpectedLog != nil { logResult := map[string]string{} - err = json.Unmarshal(logBuf.Bytes(), &logResult) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(logBuf.Bytes(), &logResult)) assert.Equal(t, tc.ExpectedLog.Level, logResult["level"]) assert.Equal(t, tc.ExpectedLog.Msg, logResult["msg"]) diff --git a/pkg/cmd/history_test.go b/pkg/cmd/history_test.go index 2bace98e0..cd8e353e7 100644 --- a/pkg/cmd/history_test.go +++ b/pkg/cmd/history_test.go @@ -385,16 +385,16 @@ func TestReleaseInfoUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &info) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.Revision, info.Revision) + assert.Equal(t, tt.expected.Updated.Unix(), info.Updated.Unix()) + assert.Equal(t, tt.expected.Status, info.Status) + assert.Equal(t, tt.expected.Chart, info.Chart) + assert.Equal(t, tt.expected.AppVersion, info.AppVersion) + assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) + assert.Equal(t, tt.expected.Description, info.Description) } - require.NoError(t, err) - assert.Equal(t, tt.expected.Revision, info.Revision) - assert.Equal(t, tt.expected.Updated.Unix(), info.Updated.Unix()) - assert.Equal(t, tt.expected.Status, info.Status) - assert.Equal(t, tt.expected.Chart, info.Chart) - assert.Equal(t, tt.expected.AppVersion, info.AppVersion) - assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) - assert.Equal(t, tt.expected.Description, info.Description) }) } } @@ -415,9 +415,7 @@ func TestReleaseInfoRoundTrip(t *testing.T) { require.NoError(t, err) var decoded releaseInfo - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.Revision, decoded.Revision) assert.Equal(t, original.Updated.Unix(), decoded.Updated.Unix()) assert.Equal(t, original.Status, decoded.Status) @@ -433,11 +431,10 @@ func TestReleaseInfoEmptyStringRoundTrip(t *testing.T) { input := `{"revision":1,"updated":"","status":"deployed","chart":"mychart-1.0.0","app_version":"1.0.0","description":"Test"}` var info releaseInfo - err := json.Unmarshal([]byte(input), &info) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &info)) // Verify time field is zero value - assert.True(t, info.Updated.IsZero()) + assert.Zero(t, info.Updated) assert.Equal(t, 1, info.Revision) assert.Equal(t, "deployed", info.Status) @@ -446,8 +443,7 @@ func TestReleaseInfoEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time value should be omitted assert.NotContains(t, result, "updated") diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index b935ed4d0..b6cee5843 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -131,6 +131,7 @@ charts in a repository, use 'helm search'. func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewInstall(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) valueOpts := &values.Options{} var outfmt output.Format diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go index 8d3435e03..d1e081e5c 100644 --- a/pkg/cmd/install_test.go +++ b/pkg/cmd/install_test.go @@ -23,6 +23,8 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/repo/v1/repotest" ) @@ -39,9 +41,7 @@ func TestInstall(t *testing.T) { })) defer srv2.Close() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) repoFile := filepath.Join(srv.Root(), "repositories.yaml") diff --git a/pkg/cmd/list_test.go b/pkg/cmd/list_test.go index f45616250..41426fedb 100644 --- a/pkg/cmd/list_test.go +++ b/pkg/cmd/list_test.go @@ -426,20 +426,9 @@ func TestReleaseListWriterMethods(t *testing.T) { var buf []byte out := &bytesWriter{buf: &buf} - err := writer.WriteJSON(out) - if err != nil { - t.Errorf("WriteJSON failed: %v", err) - } - - err = writer.WriteYAML(out) - if err != nil { - t.Errorf("WriteYAML failed: %v", err) - } - - err = writer.WriteTable(out) - if err != nil { - t.Errorf("WriteTable failed: %v", err) - } + require.NoError(t, writer.WriteJSON(out), "WriteJSON failed") + require.NoError(t, writer.WriteYAML(out), "WriteYAML failed") + assert.NoError(t, writer.WriteTable(out), "WriteTable failed") }) } @@ -448,20 +437,9 @@ func TestReleaseListWriterMethods(t *testing.T) { var buf []byte out := &bytesWriter{buf: &buf} - err := writer.WriteJSON(out) - if err != nil { - t.Errorf("WriteJSON failed: %v", err) - } - - err = writer.WriteYAML(out) - if err != nil { - t.Errorf("WriteYAML failed: %v", err) - } - - err = writer.WriteTable(out) - if err != nil { - t.Errorf("WriteTable failed: %v", err) - } + require.NoError(t, writer.WriteJSON(out), "WriteJSON failed") + require.NoError(t, writer.WriteYAML(out), "WriteYAML failed") + assert.NoError(t, writer.WriteTable(out), "WriteTable failed") } func TestFilterReleases(t *testing.T) { @@ -512,9 +490,7 @@ func TestFilterReleases(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := filterReleases(tt.releases, tt.ignoredReleaseNames) - if len(result) != tt.expectedCount { - t.Errorf("Expected %d releases, got %d", tt.expectedCount, len(result)) - } + assert.Len(t, result, tt.expectedCount, "Expected %d releases, got %d", tt.expectedCount, len(result)) }) } } @@ -603,13 +579,9 @@ func TestListStatusMapping(t *testing.T) { } writer := newReleaseListWriter(releaseFixture, "", false, false) - if len(writer.releases) != 1 { - t.Errorf("Expected 1 release, got %d", len(writer.releases)) - } + assert.Len(t, writer.releases, 1, "Expected 1 release, got %d", len(writer.releases)) - if writer.releases[0].Status != tc.status.String() { - t.Errorf("Expected status %s, got %s", tc.status.String(), writer.releases[0].Status) - } + assert.Equal(t, tc.status.String(), writer.releases[0].Status, "Expected status %s, got %s", tc.status.String(), writer.releases[0].Status) }) } } diff --git a/pkg/cmd/package_test.go b/pkg/cmd/package_test.go index 5705c9b9e..8b19faf08 100644 --- a/pkg/cmd/package_test.go +++ b/pkg/cmd/package_test.go @@ -23,6 +23,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" @@ -105,18 +108,14 @@ func TestPackage(t *testing.T) { } origDir, err := os.Getwd() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Chdir(t.TempDir()) ensure.HelmHome(t) - if err := os.MkdirAll("toot", 0o777); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll("toot", 0o777)) // This is an unfortunate byproduct of the tmpdir if v, ok := tt.flags["keyring"]; ok && v != "" { @@ -140,26 +139,21 @@ func TestPackage(t *testing.T) { } } _, _, err = executeActionCommand(strings.Join(cmd, " ")) - if err != nil { - if tt.err && re.MatchString(err.Error()) { - return + if tt.err { + require.Error(t, err) + require.True(t, re.MatchString(err.Error())) + } else { + require.NoError(t, err) + if tt.hasfile != "" { + fi, err := os.Stat(tt.hasfile) + require.NoErrorf(t, err, "%q: expected file %q", tt.name, tt.hasfile) + assert.NotEqualf(t, 0, fi.Size(), "%q: file %q has zero bytes.", tt.name, tt.hasfile) } - t.Fatalf("%q: expected error %q, got %q", tt.name, tt.expect, err) - } - if tt.hasfile != "" { - if fi, err := os.Stat(tt.hasfile); err != nil { - t.Errorf("%q: expected file %q, got err %q", tt.name, tt.hasfile, err) - } else if fi.Size() == 0 { - t.Errorf("%q: file %q has zero bytes.", tt.name, tt.hasfile) - } - } - - if v, ok := tt.flags["sign"]; ok && v == "1" { - if fi, err := os.Stat(tt.hasfile + ".prov"); err != nil { - t.Errorf("%q: expected provenance file", tt.name) - } else if fi.Size() == 0 { - t.Errorf("%q: provenance file is empty", tt.name) + if v, ok := tt.flags["sign"]; ok && v == "1" { + fi, err := os.Stat(tt.hasfile + ".prov") + require.NoErrorf(t, err, "%q: expected provenance file", tt.name) + assert.NotEqualf(t, 0, fi.Size(), "%q: provenance file is empty", tt.name) } } }) @@ -178,18 +172,12 @@ func TestSetAppVersion(t *testing.T) { t.Fatal(err) } chartPath := filepath.Join(dir, "alpine-0.1.0.tgz") - if fi, err := os.Stat(chartPath); err != nil { - t.Errorf("expected file %q, got err %q", chartPath, err) - } else if fi.Size() == 0 { - t.Errorf("file %q has zero bytes.", chartPath) - } + fi, err := os.Stat(chartPath) + require.NoErrorf(t, err, "expected file %q", chartPath) + assert.NotEqualf(t, 0, fi.Size(), "file %q has zero bytes.", chartPath) ch, err = loader.Load(chartPath) - if err != nil { - t.Fatalf("unexpected error loading packaged chart: %v", err) - } - if ch.Metadata.AppVersion != expectedAppVersion { - t.Errorf("expected app-version %q, found %q", expectedAppVersion, ch.Metadata.AppVersion) - } + require.NoError(t, err, "unexpected error loading packaged chart") + assert.Equal(t, expectedAppVersion, ch.Metadata.AppVersion, "expected app-version %q, found %q", expectedAppVersion, ch.Metadata.AppVersion) } func TestPackageFileCompletion(t *testing.T) { diff --git a/pkg/cmd/plugin_package_test.go b/pkg/cmd/plugin_package_test.go index b5ecf2bf1..e04498b98 100644 --- a/pkg/cmd/plugin_package_test.go +++ b/pkg/cmd/plugin_package_test.go @@ -19,8 +19,10 @@ import ( "bytes" "os" "path/filepath" - "strings" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // Common plugin.yaml content for v1 format tests @@ -43,14 +45,10 @@ func TestPluginPackageWithoutSigning(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) // Create package options with sign=false o := &pluginPackageOptions{ @@ -61,47 +59,34 @@ func TestPluginPackageWithoutSigning(t *testing.T) { // Run the package command out := &bytes.Buffer{} - err := o.run(out) // Should succeed without error - if err != nil { - t.Errorf("unexpected error: %v", err) - } + require.NoError(t, o.run(out)) // Check that tarball was created with plugin name and version tarballPath := filepath.Join(tempDir, "test-plugin-1.0.0.tgz") - if _, err := os.Stat(tarballPath); os.IsNotExist(err) { - t.Error("tarball should exist when sign=false") - } + _, err := os.Stat(tarballPath) + assert.False(t, os.IsNotExist(err), "tarball should exist when sign=false") // Check that no .prov file was created provPath := tarballPath + ".prov" - if _, err := os.Stat(provPath); !os.IsNotExist(err) { - t.Error("provenance file should not exist when sign=false") - } + _, err = os.Stat(provPath) + assert.True(t, os.IsNotExist(err), "provenance file should not exist when sign=false") // Output should contain warning about skipping signing output := out.String() - if !strings.Contains(output, "WARNING: Skipping plugin signing") { - t.Error("should print warning when signing is skipped") - } - if !strings.Contains(output, "Successfully packaged") { - t.Error("should print success message") - } + assert.Contains(t, output, "WARNING: Skipping plugin signing", "should print warning when signing is skipped") + assert.Contains(t, output, "Successfully packaged", "should print success message") } func TestPluginPackageDefaultRequiresSigning(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) // Create package options with default sign=true and invalid keyring o := &pluginPackageOptions{ @@ -113,32 +98,24 @@ func TestPluginPackageDefaultRequiresSigning(t *testing.T) { // Run the package command out := &bytes.Buffer{} - err := o.run(out) // Should fail because signing is required by default - if err == nil { - t.Error("expected error when signing fails with default settings") - } + require.Error(t, o.run(out), "expected error when signing fails with default settings") // Check that no tarball was created tarballPath := filepath.Join(tempDir, "test-plugin.tgz") - if _, err := os.Stat(tarballPath); !os.IsNotExist(err) { - t.Error("tarball should not exist when signing fails") - } + _, err := os.Stat(tarballPath) + assert.True(t, os.IsNotExist(err), "tarball should not exist when signing fails") } func TestPluginPackageSigningFailure(t *testing.T) { // Create a test plugin directory tempDir := t.TempDir() pluginDir := filepath.Join(tempDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create a plugin.yaml file - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644)) // Create package options with sign flag but invalid keyring o := &pluginPackageOptions{ @@ -150,21 +127,15 @@ func TestPluginPackageSigningFailure(t *testing.T) { // Run the package command out := &bytes.Buffer{} - err := o.run(out) // Should get an error - if err == nil { - t.Error("expected error when signing fails, got nil") - } + require.Error(t, o.run(out), "expected error when signing fails, got nil") // Check that no tarball was created tarballPath := filepath.Join(tempDir, "test-plugin.tgz") - if _, err := os.Stat(tarballPath); !os.IsNotExist(err) { - t.Error("tarball should not exist when signing fails") - } + _, err := os.Stat(tarballPath) + assert.True(t, os.IsNotExist(err), "tarball should not exist when signing fails") // Output should not contain success message - if bytes.Contains(out.Bytes(), []byte("Successfully packaged")) { - t.Error("should not print success message when signing fails") - } + assert.False(t, bytes.Contains(out.Bytes(), []byte("Successfully packaged")), "should not print success message when signing fails") } diff --git a/pkg/cmd/plugin_test.go b/pkg/cmd/plugin_test.go index 476997110..6a7980119 100644 --- a/pkg/cmd/plugin_test.go +++ b/pkg/cmd/plugin_test.go @@ -72,14 +72,10 @@ func TestManuallyProcessArgs(t *testing.T) { known, unknown := manuallyProcessArgs(input) for i, k := range known { - if k != expectKnown[i] { - t.Errorf("expected known flag %d to be %q, got %q", i, expectKnown[i], k) - } + assert.Equal(t, expectKnown[i], k, "expected known flag %d to be %q, got %q", i, expectKnown[i], k) } for i, k := range unknown { - if k != expectUnknown[i] { - t.Errorf("expected unknown flag %d to be %q, got %q", i, expectUnknown[i], k) - } + assert.Equal(t, expectUnknown[i], k, "expected unknown flag %d to be %q, got %q", i, expectUnknown[i], k) } } @@ -130,30 +126,18 @@ func TestLoadCLIPlugins(t *testing.T) { pluginCmd := pluginCmds[i] t.Run(fmt.Sprintf("%s-%d", pluginCmd.Name(), i), func(t *testing.T) { out.Reset() - if pluginCmd.Use != tt.use { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.use, pluginCmd.Use) - } - if pluginCmd.Short != tt.short { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.short, pluginCmd.Short) - } - if pluginCmd.Long != tt.long { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.long, pluginCmd.Long) - } + assert.Equal(t, tt.use, pluginCmd.Use, "%d: Expected Use=%q, got %q", i, tt.use, pluginCmd.Use) + assert.Equal(t, tt.short, pluginCmd.Short, "%d: Expected Use=%q, got %q", i, tt.short, pluginCmd.Short) + assert.Equal(t, tt.long, pluginCmd.Long, "%d: Expected Use=%q, got %q", i, tt.long, pluginCmd.Long) // Currently, plugins assume a Linux subsystem. Skip the execution // tests until this is fixed if runtime.GOOS != "windows" { if err := pluginCmd.RunE(pluginCmd, tt.args); err != nil { - if tt.code > 0 { - cerr, ok := err.(CommandError) - if !ok { - t.Errorf("Expected %s to return pluginError: got %v(%T)", tt.use, err, err) - } - if cerr.ExitCode != tt.code { - t.Errorf("Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) - } - } else { - t.Errorf("Error running %s: %+v", tt.use, err) + if assert.Positive(t, tt.code, "Error running %s", tt.use) { + var cerr CommandError + require.ErrorAs(t, err, &cerr, "Expected %s to return pluginError", tt.use) + assert.Equalf(t, tt.code, cerr.ExitCode, "Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) } } assert.Equal(t, tt.expect, out.String(), "expected output for %q", tt.use) @@ -196,38 +180,24 @@ func TestLoadPluginsWithSpace(t *testing.T) { plugins := cmd.Commands() - if len(plugins) != len(tests) { - t.Fatalf("Expected %d plugins, got %d", len(tests), len(plugins)) - } + require.Len(t, plugins, len(tests), "Expected %d plugins, got %d", len(tests), len(plugins)) for i := range plugins { out.Reset() tt := tests[i] pp := plugins[i] - if pp.Use != tt.use { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.use, pp.Use) - } - if pp.Short != tt.short { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.short, pp.Short) - } - if pp.Long != tt.long { - t.Errorf("%d: Expected Use=%q, got %q", i, tt.long, pp.Long) - } + assert.Equal(t, tt.use, pp.Use, "%d: Expected Use=%q, got %q", i, tt.use, pp.Use) + assert.Equal(t, tt.short, pp.Short, "%d: Expected Use=%q, got %q", i, tt.short, pp.Short) + assert.Equal(t, tt.long, pp.Long, "%d: Expected Use=%q, got %q", i, tt.long, pp.Long) // Currently, plugins assume a Linux subsystem. Skip the execution // tests until this is fixed if runtime.GOOS != "windows" { if err := pp.RunE(pp, tt.args); err != nil { - if tt.code > 0 { - cerr, ok := err.(CommandError) - if !ok { - t.Errorf("Expected %s to return pluginError: got %v(%T)", tt.use, err, err) - } - if cerr.ExitCode != tt.code { - t.Errorf("Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) - } - } else { - t.Errorf("Error running %s: %+v", tt.use, err) + if assert.Positive(t, tt.code, "Error running %s", tt.use) { + var cerr CommandError + require.ErrorAs(t, err, &cerr, "Expected %s to return pluginError", tt.use) + assert.Equalf(t, tt.code, cerr.ExitCode, "Expected %s to return %d: got %d", tt.use, tt.code, cerr.ExitCode) } } assert.Equal(t, tt.expect, out.String(), "expected output for %s", tt.use) @@ -346,9 +316,7 @@ func TestLoadCLIPlugins_HelmNoPlugins(t *testing.T) { loadCLIPlugins(cmd, out) plugins := cmd.Commands() - if len(plugins) != 0 { - t.Fatalf("Expected 0 plugins, got %d", len(plugins)) - } + require.Empty(t, plugins, "Expected 0 plugins, got %d", len(plugins)) } func TestPluginCmdsCompletion(t *testing.T) { diff --git a/pkg/cmd/plugin_uninstall_test.go b/pkg/cmd/plugin_uninstall_test.go index f715b09c8..bd08f6f13 100644 --- a/pkg/cmd/plugin_uninstall_test.go +++ b/pkg/cmd/plugin_uninstall_test.go @@ -21,6 +21,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/plugin" "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/cli" @@ -39,9 +42,7 @@ func TestPluginUninstallCleansUpVersionedFiles(t *testing.T) { // Create plugin directory pluginDir := filepath.Join(pluginsDir, pluginName) - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(pluginDir, 0o755)) // Create plugin.yaml pluginYAML := `name: test-plugin @@ -49,31 +50,21 @@ version: 1.2.3 description: Test plugin command: $HELM_PLUGIN_DIR/test-plugin ` - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(pluginYAML), 0o644)) // Create versioned tarball and provenance files tarballFile := filepath.Join(pluginsDir, "test-plugin-1.2.3.tgz") provFile := filepath.Join(pluginsDir, "test-plugin-1.2.3.tgz.prov") otherVersionTarball := filepath.Join(pluginsDir, "test-plugin-2.0.0.tgz") - if err := os.WriteFile(tarballFile, []byte("fake tarball"), 0o644); err != nil { - t.Fatal(err) - } - if err := os.WriteFile(provFile, []byte("fake provenance"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(tarballFile, []byte("fake tarball"), 0o644)) + require.NoError(t, os.WriteFile(provFile, []byte("fake provenance"), 0o644)) // Create another version that should NOT be removed - if err := os.WriteFile(otherVersionTarball, []byte("other version"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(otherVersionTarball, []byte("other version"), 0o644)) // Load the plugin p, err := plugin.LoadDir(pluginDir) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Create a test uninstall function that uses our test settings testUninstallPlugin := func(plugin plugin.Plugin) error { @@ -112,35 +103,26 @@ command: $HELM_PLUGIN_DIR/test-plugin } // Verify files exist before uninstall - if _, err := os.Stat(tarballFile); os.IsNotExist(err) { - t.Fatal("tarball file should exist before uninstall") - } - if _, err := os.Stat(provFile); os.IsNotExist(err) { - t.Fatal("provenance file should exist before uninstall") - } - if _, err := os.Stat(otherVersionTarball); os.IsNotExist(err) { - t.Fatal("other version tarball should exist before uninstall") - } + _, err = os.Stat(tarballFile) + require.False(t, os.IsNotExist(err), "tarball file should exist before uninstall") + _, err = os.Stat(provFile) + require.False(t, os.IsNotExist(err), "provenance file should exist before uninstall") + _, err = os.Stat(otherVersionTarball) + require.False(t, os.IsNotExist(err), "other version tarball should exist before uninstall") // Uninstall the plugin - if err := testUninstallPlugin(p); err != nil { - t.Fatal(err) - } + require.NoError(t, testUninstallPlugin(p)) // Verify plugin directory is removed - if _, err := os.Stat(pluginDir); !os.IsNotExist(err) { - t.Error("plugin directory should be removed") - } + _, err = os.Stat(pluginDir) + assert.True(t, os.IsNotExist(err), "plugin directory should be removed") // Verify only exact version files are removed - if _, err := os.Stat(tarballFile); !os.IsNotExist(err) { - t.Error("versioned tarball file should be removed") - } - if _, err := os.Stat(provFile); !os.IsNotExist(err) { - t.Error("versioned provenance file should be removed") - } + _, err = os.Stat(tarballFile) + assert.True(t, os.IsNotExist(err), "versioned tarball file should be removed") + _, err = os.Stat(provFile) + assert.True(t, os.IsNotExist(err), "versioned provenance file should be removed") // Verify other version files are NOT removed - if _, err := os.Stat(otherVersionTarball); os.IsNotExist(err) { - t.Error("other version tarball should NOT be removed") - } + _, err = os.Stat(otherVersionTarball) + assert.False(t, os.IsNotExist(err), "other version tarball should NOT be removed") } diff --git a/pkg/cmd/plugin_verify_test.go b/pkg/cmd/plugin_verify_test.go index 4ce664c0c..64e6cc18c 100644 --- a/pkg/cmd/plugin_verify_test.go +++ b/pkg/cmd/plugin_verify_test.go @@ -21,9 +21,11 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/plugin" "helm.sh/helm/v4/internal/test/ensure" ) @@ -35,13 +37,7 @@ func TestPluginVerifyCmd_NoArgs(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when no arguments provided") - } - if !strings.Contains(err.Error(), "requires 1 argument") { - t.Errorf("expected 'requires 1 argument' error, got: %v", err) - } + assert.ErrorContains(t, cmd.Execute(), "requires 1 argument", "expected 'requires 1 argument' error") } func TestPluginVerifyCmd_TooManyArgs(t *testing.T) { @@ -51,13 +47,7 @@ func TestPluginVerifyCmd_TooManyArgs(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{"plugin1", "plugin2"}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when too many arguments provided") - } - if !strings.Contains(err.Error(), "requires 1 argument") { - t.Errorf("expected 'requires 1 argument' error, got: %v", err) - } + assert.ErrorContains(t, cmd.Execute(), "requires 1 argument", "expected 'requires 1 argument' error") } func TestPluginVerifyCmd_NonexistentFile(t *testing.T) { @@ -67,10 +57,7 @@ func TestPluginVerifyCmd_NonexistentFile(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{"/nonexistent/plugin.tgz"}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when plugin file doesn't exist") - } + assert.Error(t, cmd.Execute(), "expected error when plugin file doesn't exist") } func TestPluginVerifyCmd_MissingProvenance(t *testing.T) { @@ -84,13 +71,7 @@ func TestPluginVerifyCmd_MissingProvenance(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{pluginTgz}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when .prov file is missing") - } - if !strings.Contains(err.Error(), "could not find provenance file") { - t.Errorf("expected 'could not find provenance file' error, got: %v", err) - } + assert.ErrorContains(t, cmd.Execute(), "could not find provenance file", "expected 'could not find provenance file' error") } func TestPluginVerifyCmd_InvalidProvenance(t *testing.T) { @@ -102,19 +83,14 @@ func TestPluginVerifyCmd_InvalidProvenance(t *testing.T) { // Create invalid .prov file provFile := pluginTgz + ".prov" - if err := os.WriteFile(provFile, []byte("invalid provenance"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(provFile, []byte("invalid provenance"), 0o644)) defer os.Remove(provFile) out := &bytes.Buffer{} cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{pluginTgz}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when .prov file is invalid") - } + assert.Error(t, cmd.Execute(), "expected error when .prov file is invalid") } func TestPluginVerifyCmd_DirectoryNotSupported(t *testing.T) { @@ -127,13 +103,7 @@ func TestPluginVerifyCmd_DirectoryNotSupported(t *testing.T) { cmd := newPluginVerifyCmd(out) cmd.SetArgs([]string{pluginDir}) - err := cmd.Execute() - if err == nil { - t.Error("expected error when verifying directory") - } - if !strings.Contains(err.Error(), "directory verification not supported") { - t.Errorf("expected 'directory verification not supported' error, got: %v", err) - } + assert.ErrorContains(t, cmd.Execute(), "directory verification not supported", "expected 'directory verification not supported' error") } func TestPluginVerifyCmd_KeyringFlag(t *testing.T) { @@ -157,10 +127,7 @@ func TestPluginVerifyCmd_KeyringFlag(t *testing.T) { cmd.SetArgs([]string{"--keyring", keyring, pluginTgz}) // Should fail with keyring error but command parsing should work - err := cmd.Execute() - if err == nil { - t.Error("expected error with empty keyring") - } + assert.Error(t, cmd.Execute(), "expected error with empty keyring") // The important thing is that the keyring flag was parsed and used } @@ -178,14 +145,10 @@ func createTestPluginDir(t *testing.T) string { // Create temporary directory with plugin structure tmpDir := t.TempDir() pluginDir := filepath.Join(tmpDir, "test-plugin") - if err := os.MkdirAll(pluginDir, 0o755); err != nil { - t.Fatalf("Failed to create plugin directory: %v", err) - } + require.NoErrorf(t, os.MkdirAll(pluginDir, 0o755), "Failed to create plugin directory") // Use the same plugin YAML as other cmd tests - if err := os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644); err != nil { - t.Fatalf("Failed to create plugin.yaml: %v", err) - } + require.NoErrorf(t, os.WriteFile(filepath.Join(pluginDir, "plugin.yaml"), []byte(testPluginYAML), 0o644), "Failed to create plugin.yaml") return pluginDir } @@ -199,14 +162,10 @@ func createTestPluginTarball(t *testing.T) string { tmpDir := filepath.Dir(pluginDir) tgzPath := filepath.Join(tmpDir, "test-plugin-1.0.0.tgz") tarFile, err := os.Create(tgzPath) - if err != nil { - t.Fatalf("Failed to create tarball file: %v", err) - } + require.NoError(t, err, "Failed to create tarball file") defer tarFile.Close() - if err := plugin.CreatePluginTarball(pluginDir, "test-plugin", tarFile); err != nil { - t.Fatalf("Failed to create tarball: %v", err) - } + require.NoErrorf(t, plugin.CreatePluginTarball(pluginDir, "test-plugin", tarFile), "Failed to create tarball") return tgzPath } @@ -218,9 +177,7 @@ func createProvFile(t *testing.T, provFile, pluginTgz, hash string) { if hash == "" { // Calculate actual hash of the tarball data, err := os.ReadFile(pluginTgz) - if err != nil { - t.Fatalf("Failed to read tarball for hashing: %v", err) - } + require.NoError(t, err, "Failed to read tarball for hashing") hashSum := sha256.Sum256(data) hashStr = fmt.Sprintf("sha256:%x", hashSum) } else { @@ -243,9 +200,7 @@ Version: GnuPG v1 iQEcBAEBCAAGBQJktest... -----END PGP SIGNATURE----- `, hashStr) - if err := os.WriteFile(provFile, []byte(provContent), 0o644); err != nil { - t.Fatalf("Failed to create provenance file: %v", err) - } + require.NoErrorf(t, os.WriteFile(provFile, []byte(provContent), 0o644), "Failed to create provenance file") } func createTestKeyring(t *testing.T) string { @@ -256,9 +211,7 @@ func createTestKeyring(t *testing.T) string { keyringPath := filepath.Join(tmpDir, "pubring.gpg") // Create empty keyring for testing - if err := os.WriteFile(keyringPath, []byte{}, 0o644); err != nil { - t.Fatalf("Failed to create test keyring: %v", err) - } + require.NoErrorf(t, os.WriteFile(keyringPath, []byte{}, 0o644), "Failed to create test keyring") return keyringPath } diff --git a/pkg/cmd/pull_test.go b/pkg/cmd/pull_test.go index e1b3e8134..d0371710b 100644 --- a/pkg/cmd/pull_test.go +++ b/pkg/cmd/pull_test.go @@ -25,6 +25,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/repo/v1/repotest" ) @@ -36,14 +39,10 @@ func TestPullCmd(t *testing.T) { defer srv.Stop() ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ociSrv.Run(t) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) helmTestKeyOut := "Signed by: Helm Testing (This key should only be used for testing. DO NOT TRUST.) \n" + "Using Key With Fingerprint: 5E615389B53CA37F0EE60BD3843BBF981FC18762\n" + @@ -229,46 +228,31 @@ func TestPullCmd(t *testing.T) { // Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182 if tt.existFile != "" { file := filepath.Join(outdir, tt.existFile) - if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil { - t.Fatal(err) - } - _, err := os.Create(file) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Dir(file), 0o755)) + _, err = os.Create(file) + require.NoError(t, err) } if tt.existDir != "" { file := filepath.Join(outdir, tt.existDir) - err := os.MkdirAll(file, 0o755) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(file, 0o755)) } _, out, err := executeActionCommand(cmd) - if err != nil { - if tt.wantError { - if tt.wantErrorMsg != "" && tt.wantErrorMsg != err.Error() { - t.Fatalf("Actual error '%s', not equal to expected error '%s'", err, tt.wantErrorMsg) - } - return + if tt.wantError { + if tt.wantErrorMsg != "" { + require.EqualError(t, err, tt.wantErrorMsg, "Actual error '%s', not equal to expected error '%s'", err, tt.wantErrorMsg) } - t.Fatalf("%q reported error: %s", tt.name, err) - } + } else { + require.NoError(t, err) - if tt.expectVerify { - outString := helmTestKeyOut + tt.expectSha + "\n" - if out != outString { - t.Errorf("%q: expected verification output %q, got %q", tt.name, outString, out) + if tt.expectVerify { + outString := helmTestKeyOut + tt.expectSha + "\n" + assert.Equal(t, outString, out, "%q: expected verification output %q, got %q", tt.name, outString, out) } - } - ef := filepath.Join(outdir, tt.expectFile) - fi, err := os.Stat(ef) - if err != nil { - t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err) - } - if fi.IsDir() != tt.expectDir { - t.Errorf("%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) + ef := filepath.Join(outdir, tt.expectFile) + fi, err := os.Stat(ef) + require.NoError(t, err, "%q: expected a file at %s.", tt.name, ef) + assert.Equal(t, tt.expectDir, fi.IsDir(), "%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) } }) } @@ -300,38 +284,24 @@ func runPullTests(t *testing.T, tests []struct { if tt.existFile != "" { file := filepath.Join(outdir, tt.existFile) _, err := os.Create(file) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } if tt.existDir != "" { file := filepath.Join(outdir, tt.existDir) - err := os.MkdirAll(file, 0o755) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(file, 0o755)) } _, _, err := executeActionCommand(cmd) - if tt.wantError && err == nil { - t.Fatalf("%q: expected error but got none", tt.name) - } - if err != nil { - if tt.wantError { - if tt.wantErrorMsg != "" && tt.wantErrorMsg != err.Error() { - t.Fatalf("Actual error '%s', not equal to expected error '%s'", err, tt.wantErrorMsg) - } - return + if tt.wantError { + require.Error(t, err, "%q: expected error but got none", tt.name) + if tt.wantErrorMsg != "" { + require.EqualErrorf(t, err, tt.wantErrorMsg, "Actual error '%s', not equal to expected error '%s'", err, tt.wantErrorMsg) } - t.Fatalf("%q reported error: %s", tt.name, err) - } - - ef := filepath.Join(outdir, tt.expectFile) - fi, err := os.Stat(ef) - if err != nil { - t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err) - } - if fi.IsDir() != tt.expectDir { - t.Errorf("%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) + } else { + require.NoError(t, err, "%q reported error", tt.name) + ef := filepath.Join(outdir, tt.expectFile) + fi, err := os.Stat(ef) + require.NoError(t, err, "%q: expected a file at %s.", tt.name, ef) + assert.Equal(t, tt.expectDir, fi.IsDir(), "%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) } }) } @@ -362,9 +332,7 @@ func TestPullWithCredentialsCmd(t *testing.T) { })) defer srv2.Close() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) // all flags will get "-d outdir" appended. tests := []struct { @@ -445,14 +413,10 @@ func TestPullWithCredentialsCmdOCIRegistry(t *testing.T) { defer srv.Stop() ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ociSrv.Run(t) - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) // all flags will get "-d outdir" appended. tests := []struct { @@ -517,9 +481,7 @@ func TestPullOCIWithTagAndDigest(t *testing.T) { defer srv.Stop() ociSrv, err := repotest.NewOCIServer(t, srv.Root()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result := ociSrv.RunWithReturn(t) contentCache := t.TempDir() @@ -538,9 +500,7 @@ func TestPullOCIWithTagAndDigest(t *testing.T) { ) _, _, err = executeActionCommand(cmd) - if err != nil { - t.Fatalf("pull with tag+digest failed: %v", err) - } + require.NoError(t, err, "pull with tag+digest failed") // Verify the file was downloaded // When digest is present, the filename uses the digest format (e.g. chart@sha256-hex.tgz) @@ -548,12 +508,9 @@ func TestPullOCIWithTagAndDigest(t *testing.T) { if _, err := os.Stat(expectedFile); err != nil { // Try the digest-based filename; parse algorithm:hex to avoid fixed-offset assumptions algorithm, digestPart, ok := strings.Cut(result.PushedChart.Manifest.Digest, ":") - if !ok { - t.Fatalf("digest must be in algorithm:hex format, got %q", result.PushedChart.Manifest.Digest) - } + require.True(t, ok, "digest must be in algorithm:hex format, got %q", result.PushedChart.Manifest.Digest) expectedFile = filepath.Join(outdir, fmt.Sprintf("oci-dependent-chart@%s-%s.tgz", algorithm, digestPart)) - if _, err := os.Stat(expectedFile); err != nil { - t.Errorf("expected chart file not found: %v", err) - } + _, err := os.Stat(expectedFile) + assert.NoErrorf(t, err, "expected chart file not found") } } diff --git a/pkg/cmd/release_testing.go b/pkg/cmd/release_testing.go index 5a6159e7d..6be83c966 100644 --- a/pkg/cmd/release_testing.go +++ b/pkg/cmd/release_testing.go @@ -40,6 +40,7 @@ The tests to be run are defined in the chart that was installed. func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewReleaseTesting(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) outfmt := output.Table var outputLogs bool var filter []string diff --git a/pkg/cmd/release_testing_test.go b/pkg/cmd/release_testing_test.go index fdb5df1e9..a39816843 100644 --- a/pkg/cmd/release_testing_test.go +++ b/pkg/cmd/release_testing_test.go @@ -19,9 +19,11 @@ package cmd import ( "bytes" "io" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" @@ -71,11 +73,7 @@ func TestReleaseTestNotesHandling(t *testing.T) { cmd1 := newReleaseTestCmd(actionConfig, &buf1) cmd1.SetArgs([]string{"test-release"}) err1 := cmd1.Execute() - if err1 != nil { - t.Fatalf("Unexpected error for default test: %v", err1) - } + require.NoError(t, err1, "Unexpected error for default test") output1 := buf1.String() - if strings.Contains(output1, "NOTES:") { - t.Errorf("Expected notes to be hidden by default, but found NOTES section in output: %s", output1) - } + assert.NotContains(t, output1, "NOTES:", "Expected notes to be hidden by default, but found NOTES section in output: %s", output1) } diff --git a/pkg/cmd/repo_add_test.go b/pkg/cmd/repo_add_test.go index ed677f98a..6ed2a7422 100644 --- a/pkg/cmd/repo_add_test.go +++ b/pkg/cmd/repo_add_test.go @@ -17,16 +17,16 @@ limitations under the License. package cmd import ( - "errors" "fmt" "io" "io/fs" "os" "path/filepath" - "strings" "sync" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" "helm.sh/helm/v4/pkg/helmpath" @@ -50,9 +50,7 @@ func TestRepoAddCmd(t *testing.T) { defer srv2.Stop() tmpdir := filepath.Join(t.TempDir(), "path-component.yaml", "data") - if err := os.MkdirAll(tmpdir, 0o777); err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(tmpdir, 0o777)) repoFile := filepath.Join(tmpdir, "repositories.yaml") tests := []cmdTestCase{ @@ -101,37 +99,24 @@ func TestRepoAdd(t *testing.T) { } t.Setenv(xdg.CacheHomeEnvVar, rootDir) - if err := o.run(io.Discard); err != nil { - t.Error(err) - } + require.NoError(t, o.run(io.Discard)) f, err := repo.LoadFile(repoFile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !f.Has(testRepoName) { - t.Errorf("%s was not successfully inserted into %s", testRepoName, repoFile) - } + assert.Truef(t, f.Has(testRepoName), "%s was not successfully inserted into %s", testRepoName, repoFile) idx := filepath.Join(helmpath.CachePath("repository"), helmpath.CacheIndexFile(testRepoName)) - if _, err := os.Stat(idx); errors.Is(err, fs.ErrNotExist) { - t.Errorf("Error cache index file was not created for repository %s", testRepoName) - } + _, err = os.Stat(idx) + require.NotErrorIsf(t, err, fs.ErrNotExist, "Error cache index file was not created for repository %s", testRepoName) idx = filepath.Join(helmpath.CachePath("repository"), helmpath.CacheChartsFile(testRepoName)) - if _, err := os.Stat(idx); errors.Is(err, fs.ErrNotExist) { - t.Errorf("Error cache charts file was not created for repository %s", testRepoName) - } + _, err = os.Stat(idx) + require.NotErrorIsf(t, err, fs.ErrNotExist, "Error cache charts file was not created for repository %s", testRepoName) o.forceUpdate = true - if err := o.run(io.Discard); err != nil { - t.Errorf("Repository was not updated: %s", err) - } - - if err := o.run(io.Discard); err != nil { - t.Error("Duplicate repository name was added") - } + require.NoError(t, o.run(io.Discard), "Repository was not updated") + assert.NoError(t, o.run(io.Discard), "Duplicate repository name was added") } func TestRepoAddCheckLegalName(t *testing.T) { @@ -156,14 +141,7 @@ func TestRepoAddCheckLegalName(t *testing.T) { t.Setenv(xdg.CacheHomeEnvVar, rootDir) wantErrorMsg := fmt.Sprintf("repository name (%s) contains '/', please specify a different name without '/'", testRepoName) - - if err := o.run(io.Discard); err != nil { - if wantErrorMsg != err.Error() { - t.Fatalf("Actual error %s, not equal to expected error %s", err, wantErrorMsg) - } - } else { - t.Fatal("expect reported an error.") - } + require.EqualError(t, o.run(io.Discard), wantErrorMsg) } func TestRepoAddConcurrentGoRoutines(t *testing.T) { @@ -209,29 +187,21 @@ func repoAddConcurrent(t *testing.T, testName, repoFile string) { forceUpdate: false, repoFile: repoFile, } - if err := o.run(io.Discard); err != nil { - t.Error(err) - } + assert.NoError(t, o.run(io.Discard)) }(fmt.Sprintf("%s-%d", testName, i)) } wg.Wait() b, err := os.ReadFile(repoFile) - if err != nil { - t.Error(err) - } + require.NoError(t, err) var f repo.File - if err := yaml.Unmarshal(b, &f); err != nil { - t.Error(err) - } + require.NoError(t, yaml.Unmarshal(b, &f)) var name string for i := range 3 { name = fmt.Sprintf("%s-%d", testName, i) - if !f.Has(name) { - t.Errorf("%s was not successfully inserted into %s: %s", name, repoFile, f.Repositories[0]) - } + assert.Truef(t, f.Has(name), "%s was not successfully inserted into %s: %s", name, repoFile, f.Repositories[0]) } } @@ -252,9 +222,7 @@ func TestRepoAddWithPasswordFromStdin(t *testing.T) { defer resetEnv()() in, err := os.Open("testdata/password") - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) tmpdir := t.TempDir() repoFile := filepath.Join(tmpdir, "repositories.yaml") @@ -266,11 +234,7 @@ func TestRepoAddWithPasswordFromStdin(t *testing.T) { cmd := fmt.Sprintf("repo add %s %s --repository-config %s --repository-cache %s --username %s --password-stdin", testName, srv.URL(), repoFile, tmpdir, username) var result string _, result, err = executeActionCommandStdinC(store, in, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - if !strings.Contains(result, fmt.Sprintf("%q has been added to your repositories", testName)) { - t.Errorf("Repo was not successfully added. Output: %s", result) - } + require.NoError(t, err) + assert.Contains(t, result, fmt.Sprintf("%q has been added to your repositories", testName), "Repo was not successfully added. Output: %s", result) } diff --git a/pkg/cmd/repo_index_test.go b/pkg/cmd/repo_index_test.go index 68f105d6d..67984f3b7 100644 --- a/pkg/cmd/repo_index_test.go +++ b/pkg/cmd/repo_index_test.go @@ -24,6 +24,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/repo/v1" ) @@ -31,134 +34,81 @@ func TestRepoIndexCmd(t *testing.T) { dir := t.TempDir() comp := filepath.Join(dir, "compressedchart-0.1.0.tgz") - if err := linkOrCopy("testdata/testcharts/compressedchart-0.1.0.tgz", comp); err != nil { - t.Fatal(err) - } + require.NoError(t, linkOrCopy("testdata/testcharts/compressedchart-0.1.0.tgz", comp)) comp2 := filepath.Join(dir, "compressedchart-0.2.0.tgz") - if err := linkOrCopy("testdata/testcharts/compressedchart-0.2.0.tgz", comp2); err != nil { - t.Fatal(err) - } + require.NoError(t, linkOrCopy("testdata/testcharts/compressedchart-0.2.0.tgz", comp2)) buf := bytes.NewBuffer(nil) c := newRepoIndexCmd(buf) - if err := c.RunE(c, []string{dir}); err != nil { - t.Error(err) - } + require.NoError(t, c.RunE(c, []string{dir})) destIndex := filepath.Join(dir, "index.yaml") index, err := repo.LoadIndexFile(destIndex) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(index.Entries) != 1 { - t.Errorf("expected 1 entry, got %d: %#v", len(index.Entries), index.Entries) - } + require.Len(t, index.Entries, 1, "expected 1 entry, got %d: %#v", len(index.Entries), index.Entries) vs := index.Entries["compressedchart"] - if len(vs) != 2 { - t.Errorf("expected 2 versions, got %d: %#v", len(vs), vs) - } + require.Len(t, vs, 2, "expected 2 versions") expectedVersion := "0.2.0" - if vs[0].Version != expectedVersion { - t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) - } + assert.Equal(t, expectedVersion, vs[0].Version, "expected %q, got %q", expectedVersion, vs[0].Version) b, err := os.ReadFile(destIndex) - if err != nil { - t.Fatal(err) - } - if json.Valid(b) { - t.Error("did not expect index file to be valid json") - } + require.NoError(t, err) + assert.False(t, json.Valid(b), "did not expect index file to be valid json") // Test with `--json` c.ParseFlags([]string{"--json", "true"}) - if err := c.RunE(c, []string{dir}); err != nil { - t.Error(err) - } + require.NoError(t, c.RunE(c, []string{dir})) - if b, err = os.ReadFile(destIndex); err != nil { - t.Fatal(err) - } - if !json.Valid(b) { - t.Error("index file is not valid json") - } + b, err = os.ReadFile(destIndex) + require.NoError(t, err) + assert.True(t, json.Valid(b), "index file is not valid json") // Test with `--merge` // Remove first two charts. - if err := os.Remove(comp); err != nil { - t.Fatal(err) - } - if err := os.Remove(comp2); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Remove(comp)) + require.NoError(t, os.Remove(comp2)) // Add a new chart and a new version of an existing chart - if err := linkOrCopy("testdata/testcharts/reqtest-0.1.0.tgz", filepath.Join(dir, "reqtest-0.1.0.tgz")); err != nil { - t.Fatal(err) - } - if err := linkOrCopy("testdata/testcharts/compressedchart-0.3.0.tgz", filepath.Join(dir, "compressedchart-0.3.0.tgz")); err != nil { - t.Fatal(err) - } + require.NoError(t, linkOrCopy("testdata/testcharts/reqtest-0.1.0.tgz", filepath.Join(dir, "reqtest-0.1.0.tgz"))) + require.NoError(t, linkOrCopy("testdata/testcharts/compressedchart-0.3.0.tgz", filepath.Join(dir, "compressedchart-0.3.0.tgz"))) c.ParseFlags([]string{"--merge", destIndex}) - if err := c.RunE(c, []string{dir}); err != nil { - t.Error(err) - } + require.NoError(t, c.RunE(c, []string{dir})) index, err = repo.LoadIndexFile(destIndex) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(index.Entries) != 2 { - t.Errorf("expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) - } + assert.Len(t, index.Entries, 2, "expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) vs = index.Entries["compressedchart"] - if len(vs) != 3 { - t.Errorf("expected 3 versions, got %d: %#v", len(vs), vs) - } + assert.Len(t, vs, 3, "expected 3 versions, got %d: %#v", len(vs), vs) expectedVersion = "0.3.0" - if vs[0].Version != expectedVersion { - t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) - } + assert.Equal(t, expectedVersion, vs[0].Version, "expected %q, got %q", expectedVersion, vs[0].Version) // test that index.yaml gets generated on merge even when it doesn't exist - if err := os.Remove(destIndex); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Remove(destIndex)) c.ParseFlags([]string{"--merge", destIndex}) - if err := c.RunE(c, []string{dir}); err != nil { - t.Error(err) - } + require.NoError(t, c.RunE(c, []string{dir})) index, err = repo.LoadIndexFile(destIndex) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // verify it didn't create an empty index.yaml and the merged happened - if len(index.Entries) != 2 { - t.Errorf("expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) - } + assert.Len(t, index.Entries, 2, "expected 2 entries, got %d: %#v", len(index.Entries), index.Entries) vs = index.Entries["compressedchart"] - if len(vs) != 1 { - t.Errorf("expected 1 versions, got %d: %#v", len(vs), vs) - } + assert.Len(t, vs, 1, "expected 1 versions, got %d: %#v", len(vs), vs) expectedVersion = "0.3.0" - if vs[0].Version != expectedVersion { - t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) - } + assert.Equal(t, expectedVersion, vs[0].Version, "expected %q, got %q", expectedVersion, vs[0].Version) } func linkOrCopy(source, target string) error { diff --git a/pkg/cmd/repo_remove_test.go b/pkg/cmd/repo_remove_test.go index 3b0072a68..7d252c35d 100644 --- a/pkg/cmd/repo_remove_test.go +++ b/pkg/cmd/repo_remove_test.go @@ -21,9 +21,11 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/helmpath" "helm.sh/helm/v4/pkg/repo/v1" "helm.sh/helm/v4/pkg/repo/v1/repotest" @@ -49,41 +51,29 @@ func TestRepoRemove(t *testing.T) { repoCache: rootDir, } - if err := rmOpts.run(os.Stderr); err == nil { - t.Errorf("Expected error removing %s, but did not get one.", testRepoName) - } + require.Errorf(t, rmOpts.run(os.Stderr), "Expected error removing %s, but did not get one.", testRepoName) o := &repoAddOptions{ name: testRepoName, url: ts.URL(), repoFile: repoFile, } - if err := o.run(os.Stderr); err != nil { - t.Error(err) - } + require.NoError(t, o.run(os.Stderr)) cacheIndexFile, cacheChartsFile := createCacheFiles(rootDir, testRepoName) // Reset the buffer before running repo remove b.Reset() - if err := rmOpts.run(b); err != nil { - t.Errorf("Error removing %s from repositories", testRepoName) - } - if !strings.Contains(b.String(), "has been removed") { - t.Errorf("Unexpected output: %s", b.String()) - } + require.NoErrorf(t, rmOpts.run(b), "Error removing %s from repositories", testRepoName) + assert.Contains(t, b.String(), "has been removed", "Unexpected output: %s", b.String()) testCacheFiles(t, cacheIndexFile, cacheChartsFile, testRepoName) f, err := repo.LoadFile(repoFile) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if f.Has(testRepoName) { - t.Errorf("%s was not successfully removed from repositories list", testRepoName) - } + assert.Falsef(t, f.Has(testRepoName), "%s was not successfully removed from repositories list", testRepoName) // Test removal of multiple repos in one go var testRepoNames = []string{"foo", "bar", "baz"} @@ -97,9 +87,7 @@ func TestRepoRemove(t *testing.T) { repoFile: repoFile, } - if err := o.run(os.Stderr); err != nil { - t.Error(err) - } + require.NoError(t, o.run(os.Stderr)) cacheIndex, cacheChart := createCacheFiles(rootDir, repoName) cacheFiles[repoName] = []string{cacheIndex, cacheChart} @@ -116,23 +104,15 @@ func TestRepoRemove(t *testing.T) { b.Reset() // Run repo remove command - if err := multiRmOpts.run(b); err != nil { - t.Errorf("Error removing list of repos from repositories: %q", testRepoNames) - } + require.NoErrorf(t, multiRmOpts.run(b), "Error removing list of repos from repositories: %q", testRepoNames) // Check that stuff were removed - if !strings.Contains(b.String(), "has been removed") { - t.Errorf("Unexpected output: %s", b.String()) - } + assert.Contains(t, b.String(), "has been removed", "Unexpected output: %s", b.String()) for _, repoName := range testRepoNames { f, err := repo.LoadFile(repoFile) - if err != nil { - t.Error(err) - } - if f.Has(repoName) { - t.Errorf("%s was not successfully removed from repositories list", repoName) - } + require.NoError(t, err) + assert.Falsef(t, f.Has(repoName), "%s was not successfully removed from repositories list", repoName) cacheIndex := cacheFiles[repoName][0] cacheChart := cacheFiles[repoName][1] testCacheFiles(t, cacheIndex, cacheChart, repoName) @@ -153,12 +133,10 @@ func createCacheFiles(rootDir string, repoName string) (cacheIndexFile string, c func testCacheFiles(t *testing.T, cacheIndexFile string, cacheChartsFile string, repoName string) { t.Helper() - if _, err := os.Stat(cacheIndexFile); err == nil { - t.Errorf("Error cache index file was not removed for repository %s", repoName) - } - if _, err := os.Stat(cacheChartsFile); err == nil { - t.Errorf("Error cache chart file was not removed for repository %s", repoName) - } + _, err := os.Stat(cacheIndexFile) + require.Errorf(t, err, "Error cache index file was not removed for repository %s", repoName) + _, err = os.Stat(cacheChartsFile) + assert.Errorf(t, err, "Error cache chart file was not removed for repository %s", repoName) } func TestRepoRemoveCompletion(t *testing.T) { @@ -183,9 +161,7 @@ func TestRepoRemoveCompletion(t *testing.T) { repoFile: repoFile, } - if err := o.run(os.Stderr); err != nil { - t.Error(err) - } + require.NoError(t, o.run(os.Stderr)) } repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache) diff --git a/pkg/cmd/repo_update_test.go b/pkg/cmd/repo_update_test.go index 7aa4d414f..70b6dfbef 100644 --- a/pkg/cmd/repo_update_test.go +++ b/pkg/cmd/repo_update_test.go @@ -24,6 +24,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/repo/v1" @@ -44,9 +47,7 @@ func TestUpdateCmd(t *testing.T) { update: updater, repoFile: "testdata/repositories.yaml", } - if err := o.run(&out); err != nil { - t.Fatal(err) - } + require.NoError(t, o.run(&out)) if got := out.String(); !strings.Contains(got, "charts") || !strings.Contains(got, "firstexample") || @@ -70,9 +71,7 @@ func TestUpdateCmdMultiple(t *testing.T) { repoFile: "testdata/repositories.yaml", names: []string{"firstexample", "charts"}, } - if err := o.run(&out); err != nil { - t.Fatal(err) - } + require.NoError(t, o.run(&out)) if got := out.String(); !strings.Contains(got, "charts") || !strings.Contains(got, "firstexample") || @@ -96,9 +95,7 @@ func TestUpdateCmdInvalid(t *testing.T) { repoFile: "testdata/repositories.yaml", names: []string{"firstexample", "invalid"}, } - if err := o.run(&out); err == nil { - t.Fatal("expected error but did not get one") - } + require.Error(t, o.run(&out), "expected error but did not get one") } func TestUpdateCustomCacheCmd(t *testing.T) { @@ -119,12 +116,9 @@ func TestUpdateCustomCacheCmd(t *testing.T) { repoCache: cachePath, } b := io.Discard - if err := o.run(b); err != nil { - t.Fatal(err) - } - if _, err := os.Stat(filepath.Join(cachePath, "test-index.yaml")); err != nil { - t.Fatalf("error finding created index file in custom cache: %v", err) - } + require.NoError(t, o.run(b)) + _, err := os.Stat(filepath.Join(cachePath, "test-index.yaml")) + require.NoErrorf(t, err, "error finding created index file in custom cache") } func TestUpdateCharts(t *testing.T) { @@ -140,20 +134,14 @@ func TestUpdateCharts(t *testing.T) { Name: "charts", URL: ts.URL(), }, getter.All(settings)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b := bytes.NewBuffer(nil) updateCharts([]*repo.ChartRepository{r}, b) got := b.String() - if strings.Contains(got, "Unable to get an update") { - t.Errorf("Failed to get a repo: %q", got) - } - if !strings.Contains(got, "Update Complete.") { - t.Error("Update was not successful") - } + assert.NotContains(t, got, "Unable to get an update", "Failed to get a repo: %q", got) + assert.Contains(t, got, "Update Complete.", "Update was not successful") } func TestRepoUpdateFileCompletion(t *testing.T) { @@ -176,37 +164,20 @@ func TestUpdateChartsFailWithError(t *testing.T) { Name: "charts", URL: invalidURL, }, getter.All(settings)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) r2, err := repo.NewChartRepository(&repo.Entry{ Name: "charts", URL: invalidURL, }, getter.All(settings)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b := bytes.NewBuffer(nil) err = updateCharts([]*repo.ChartRepository{r1, r2}, b) - if err == nil { - t.Error("Repo update should return error because update of repository fails and 'fail-on-repo-update-fail' flag set") - return - } - var expectedErr = "failed to update the following repositories" - var receivedErr = err.Error() - if !strings.Contains(receivedErr, expectedErr) { - t.Errorf("Expected error (%s) but got (%s) instead", expectedErr, receivedErr) - } - if !strings.Contains(receivedErr, invalidURL) { - t.Errorf("Expected invalid URL (%s) in error message but got (%s) instead", invalidURL, receivedErr) - } + require.Error(t, err, "Repo update should return error because update of repository fails and 'fail-on-repo-update-fail' flag set") + require.ErrorContains(t, err, "failed to update the following repositories") + require.ErrorContains(t, err, invalidURL) got := b.String() - if !strings.Contains(got, "Unable to get an update") { - t.Errorf("Repo should have failed update but instead got: %q", got) - } - if strings.Contains(got, "Update Complete.") { - t.Error("Update was not successful and should return error message because 'fail-on-repo-update-fail' flag set") - } + assert.Contains(t, got, "Unable to get an update", "Repo should have failed update but instead got: %q", got) + assert.NotContains(t, got, "Update Complete.", "Update was not successful and should return error message because 'fail-on-repo-update-fail' flag set") } diff --git a/pkg/cmd/require/args_test.go b/pkg/cmd/require/args_test.go index 89403140e..5d3a9f003 100644 --- a/pkg/cmd/require/args_test.go +++ b/pkg/cmd/require/args_test.go @@ -18,10 +18,10 @@ package require import ( "io" "strconv" - "strings" "testing" "github.com/spf13/cobra" + "github.com/stretchr/testify/require" ) func TestArgs(t *testing.T) { @@ -77,16 +77,10 @@ func runTestCases(t *testing.T, testCases []testCase) { err := cmd.Execute() if tc.wantError == "" { - if err != nil { - t.Fatalf("unexpected error, got '%v'", err) - } - return - } - if !strings.Contains(err.Error(), tc.wantError) { - t.Fatalf("unexpected error \n\nWANT:\n%q\n\nGOT:\n%q\n", tc.wantError, err) - } - if !strings.Contains(err.Error(), "Usage:") { - t.Fatalf("unexpected error: want Usage string\n\nGOT:\n%q\n", err) + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.wantError) + require.ErrorContains(t, err, "Usage:") } }) } diff --git a/pkg/cmd/rollback.go b/pkg/cmd/rollback.go index 01d8b1866..b716dae10 100644 --- a/pkg/cmd/rollback.go +++ b/pkg/cmd/rollback.go @@ -40,6 +40,7 @@ To see revision numbers, run 'helm history RELEASE'. func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewRollback(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) cmd := &cobra.Command{ Use: "rollback [REVISION]", diff --git a/pkg/cmd/rollback_test.go b/pkg/cmd/rollback_test.go index 116e158fd..21d6a65af 100644 --- a/pkg/cmd/rollback_test.go +++ b/pkg/cmd/rollback_test.go @@ -18,9 +18,11 @@ package cmd import ( "fmt" - "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/release/common" release "helm.sh/helm/v4/pkg/release/v1" @@ -148,24 +150,15 @@ func TestRollbackWithLabels(t *testing.T) { } storage := storageFixture() for _, rel := range rels { - if err := storage.Create(rel); err != nil { - t.Fatal(err) - } + require.NoError(t, storage.Create(rel)) } _, _, err := executeActionCommandC(storage, fmt.Sprintf("rollback %s 1", releaseName)) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) + updatedReli, err := storage.Get(releaseName, 3) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !reflect.DeepEqual(updatedRel.Labels, labels1) { - t.Errorf("Expected {%v}, got {%v}", labels1, updatedRel.Labels) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Equalf(t, labels1, updatedRel.Labels, "Expected {%v}, got {%v}", labels1, updatedRel.Labels) } diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 28798de5c..410a9162c 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package cmd // import "helm.sh/helm/v4/pkg/cmd" +package cmd import ( "context" diff --git a/pkg/cmd/root_test.go b/pkg/cmd/root_test.go index 316e6bd2e..b07bdbbf6 100644 --- a/pkg/cmd/root_test.go +++ b/pkg/cmd/root_test.go @@ -23,6 +23,9 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/test/ensure" "helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/helmpath" @@ -86,9 +89,8 @@ func TestRootCmd(t *testing.T) { t.Setenv(k, v) } - if _, _, err := executeActionCommand(tt.args); err != nil { - t.Fatalf("unexpected error: %s", err) - } + _, _, err := executeActionCommand(tt.args) + require.NoError(t, err) // NOTE(bacongobbler): we need to check here after calling ensure.HelmHome so we // load the proper paths after XDG_*_HOME is set @@ -104,15 +106,9 @@ func TestRootCmd(t *testing.T) { tt.dataPath = filepath.Join(os.Getenv(xdg.DataHomeEnvVar), "helm") } - if helmpath.CachePath() != tt.cachePath { - t.Errorf("expected cache path %q, got %q", tt.cachePath, helmpath.CachePath()) - } - if helmpath.ConfigPath() != tt.configPath { - t.Errorf("expected config path %q, got %q", tt.configPath, helmpath.ConfigPath()) - } - if helmpath.DataPath() != tt.dataPath { - t.Errorf("expected data path %q, got %q", tt.dataPath, helmpath.DataPath()) - } + assert.Equal(t, tt.cachePath, helmpath.CachePath(), "expected cache path %q, got %q", tt.cachePath, helmpath.CachePath()) + assert.Equal(t, tt.configPath, helmpath.ConfigPath(), "expected config path %q, got %q", tt.configPath, helmpath.ConfigPath()) + assert.Equal(t, tt.dataPath, helmpath.DataPath(), "expected data path %q, got %q", tt.dataPath, helmpath.DataPath()) }) } } @@ -120,9 +116,7 @@ func TestRootCmd(t *testing.T) { func TestUnknownSubCmd(t *testing.T) { _, _, err := executeActionCommand("foobar") - if err == nil || err.Error() != `unknown command "foobar" for "helm"` { - t.Errorf("Expect unknown command error, got %q", err) - } + assert.EqualErrorf(t, err, `unknown command "foobar" for "helm"`, "Expect unknown command error") } // Need the release of Cobra following 1.0 to be able to disable @@ -138,14 +132,10 @@ func TestRootCmdLogger(t *testing.T) { buf := new(bytes.Buffer) actionConfig := action.NewConfiguration() _, err := newRootCmdWithConfig(actionConfig, buf, args, SetupLogging) - if err != nil { - t.Errorf("expected no error, got: '%v'", err) - } + require.NoError(t, err) l1 := actionConfig.Logger() l2 := slog.Default() - if l1.Handler() != l2.Handler() { - t.Error("expected actionConfig logger to be the slog default logger") - } + assert.Equal(t, l2.Handler(), l1.Handler(), "expected actionConfig logger to be the slog default logger") } diff --git a/pkg/cmd/search/search_test.go b/pkg/cmd/search/search_test.go index 46394e77f..e45386947 100644 --- a/pkg/cmd/search/search_test.go +++ b/pkg/cmd/search/search_test.go @@ -20,6 +20,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/repo/v1" ) @@ -40,24 +43,16 @@ func TestSortScore(t *testing.T) { // Test Score for i := range expectScore { - if expectScore[i] != in[i].Score { - t.Errorf("Sort error on index %d: expected %d, got %d", i, expectScore[i], in[i].Score) - } + assert.Equalf(t, expectScore[i], in[i].Score, "Sort error on index %d: expected %d, got %d", i, expectScore[i], in[i].Score) } // Test Name for i := range expect { - if expect[i] != in[i].Name { - t.Errorf("Sort error: expected %s, got %s", expect[i], in[i].Name) - } + assert.Equalf(t, expect[i], in[i].Name, "Sort error: expected %s, got %s", expect[i], in[i].Name) } // Test version of last two items - if in[5].Chart.Version != "1.2.4" { - t.Errorf("Expected 1.2.4, got %s", in[5].Chart.Version) - } - if in[6].Chart.Version != "1.2.3" { - t.Error("Expected 1.2.3 to be last") - } + assert.Equalf(t, "1.2.4", in[5].Chart.Version, "Expected 1.2.4, got %s", in[5].Chart.Version) + assert.Equal(t, "1.2.3", in[6].Chart.Version, "Expected 1.2.3 to be last") } var indexfileEntries = map[string]repo.ChartVersions{ @@ -122,30 +117,22 @@ func loadTestIndex(_ *testing.T, all bool) *Index { func TestAll(t *testing.T) { i := loadTestIndex(t, false) all := i.All() - if len(all) != 4 { - t.Errorf("Expected 4 entries, got %d", len(all)) - } + assert.Lenf(t, all, 4, "Expected 4 entries, got %d", len(all)) i = loadTestIndex(t, true) all = i.All() - if len(all) != 5 { - t.Errorf("Expected 5 entries, got %d", len(all)) - } + assert.Lenf(t, all, 5, "Expected 5 entries, got %d", len(all)) } func TestAddRepo_Sort(t *testing.T) { i := loadTestIndex(t, true) sr, err := i.Search("TESTING/SANTA-MARIA", 100, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) SortScore(sr) ch := sr[0] expect := "1.2.3" - if ch.Chart.Version != expect { - t.Errorf("Expected %q, got %q", expect, ch.Chart.Version) - } + assert.Equalf(t, ch.Chart.Version, expect, "Expected %q, got %q", expect, ch.Chart.Version) } func TestSearchByName(t *testing.T) { @@ -245,31 +232,20 @@ func TestSearchByName(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { charts, err := i.Search(tt.query, 100, tt.regexp) - if err != nil { - if tt.fail { - if !strings.Contains(err.Error(), tt.failMsg) { - t.Fatalf("Unexpected error message: %s", err) - } - return - } - t.Fatalf("%s: %s", tt.name, err) - } - // Give us predictably ordered results. - SortScore(charts) + if tt.fail { + require.ErrorContains(t, err, tt.failMsg) + } else { + require.NoError(t, err) // Give us predictably ordered results. + SortScore(charts) - l := len(charts) - if l != len(tt.expect) { - t.Fatalf("Expected %d result, got %d", len(tt.expect), l) - } - // For empty result sets, just keep going. - if l == 0 { - return - } - - for i, got := range charts { - ex := tt.expect[i] - if got.Name != ex.Name { - t.Errorf("[%d]: Expected name %q, got %q", i, ex.Name, got.Name) + l := len(tt.expect) + require.Len(t, charts, len(tt.expect)) + // For empty result sets, just keep going. + if l != 0 { + for i, got := range charts { + ex := tt.expect[i] + assert.Equalf(t, got.Name, ex.Name, "[%d]: Expected name %q, got %q", i, ex.Name, got.Name) + } } } }) @@ -280,12 +256,8 @@ func TestSearchByNameAll(t *testing.T) { // Test with the All bit turned on. i := loadTestIndex(t, true) cs, err := i.Search("santa-maria", 100, false) - if err != nil { - t.Fatal(err) - } - if len(cs) != 2 { - t.Errorf("expected 2 charts, got %d", len(cs)) - } + require.NoError(t, err) + assert.Lenf(t, cs, 2, "expected 2 charts, got %d", len(cs)) } func TestCalcScore(t *testing.T) { @@ -293,16 +265,12 @@ func TestCalcScore(t *testing.T) { fields := []string{"aaa", "bbb", "ccc", "ddd"} matchline := strings.Join(fields, sep) - if r := i.calcScore(2, matchline); r != 0 { - t.Errorf("Expected 0, got %d", r) - } - if r := i.calcScore(5, matchline); r != 1 { - t.Errorf("Expected 1, got %d", r) - } - if r := i.calcScore(10, matchline); r != 2 { - t.Errorf("Expected 2, got %d", r) - } - if r := i.calcScore(14, matchline); r != 3 { - t.Errorf("Expected 3, got %d", r) - } + r := i.calcScore(2, matchline) + assert.Equalf(t, 0, r, "Expected 0, got %d", r) + r = i.calcScore(5, matchline) + assert.Equalf(t, 1, r, "Expected 1, got %d", r) + r = i.calcScore(10, matchline) + assert.Equalf(t, 2, r, "Expected 2, got %d", r) + r = i.calcScore(14, matchline) + assert.Equalf(t, 3, r, "Expected 3, got %d", r) } diff --git a/pkg/cmd/search_hub_test.go b/pkg/cmd/search_hub_test.go index 98bf052f2..a1612443a 100644 --- a/pkg/cmd/search_hub_test.go +++ b/pkg/cmd/search_hub_test.go @@ -21,6 +21,9 @@ import ( "net/http" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSearchHubCmd(t *testing.T) { @@ -42,14 +45,8 @@ func TestSearchHubCmd(t *testing.T) { testcmd := "search hub --endpoint " + ts.URL + " maria" storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) - if err != nil { - t.Errorf("unexpected error, %s", err) - } - if out != expected { - t.Error("expected and actual output did not match") - t.Log(out) - t.Log(expected) - } + require.NoError(t, err) + assert.Equal(t, expected, out, "expected and actual output did not match") } func TestSearchHubListRepoCmd(t *testing.T) { @@ -71,14 +68,8 @@ func TestSearchHubListRepoCmd(t *testing.T) { testcmd := "search hub --list-repo-url --endpoint " + ts.URL + " maria" storage := storageFixture() _, out, err := executeActionCommandC(storage, testcmd) - if err != nil { - t.Errorf("unexpected error, %s", err) - } - if out != expected { - t.Error("expected and actual output did not match") - t.Log(out) - t.Log(expected) - } + require.NoError(t, err) + assert.Equal(t, expected, out, "expected and actual output did not match") } func TestSearchHubOutputCompletion(t *testing.T) { @@ -165,21 +156,14 @@ func TestSearchHubCmd_FailOnNoResponseTests(t *testing.T) { _, out, err := executeActionCommandC(storage, tt.cmd) if tt.wantErr { - if err == nil { - t.Error("expected error due to no record in response, got nil") - } + require.Error(t, err, "expected error due to no record in response, got nil") } else { - if err != nil { - t.Errorf("unexpected error, got %q", err) - } + require.NoError(t, err) } - if out != tt.expected { - t.Errorf("expected and actual output did not match\n"+ - "expected: %q\n"+ - "actual : %q", - tt.expected, out) - } + assert.Equal(t, tt.expected, out, "expected and actual output did not match\n"+ + "expected: %q\n"+ + "actual : %q", tt.expected, out) }) } } diff --git a/pkg/cmd/show_test.go b/pkg/cmd/show_test.go index e24b8c442..61c4f8b10 100644 --- a/pkg/cmd/show_test.go +++ b/pkg/cmd/show_test.go @@ -19,9 +19,11 @@ package cmd import ( "fmt" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/repo/v1/repotest" ) @@ -32,9 +34,7 @@ func TestShowPreReleaseChart(t *testing.T) { ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) tests := []struct { name string @@ -77,14 +77,10 @@ func TestShowPreReleaseChart(t *testing.T) { contentTmp, ) _, _, err := executeActionCommand(cmd) - if err != nil { - if tt.fail { - if !strings.Contains(err.Error(), tt.expectedErr) { - t.Errorf("%q expected error: %s, got: %s", tt.name, tt.expectedErr, err.Error()) - } - return - } - t.Errorf("%q reported error: %s", tt.name, err) + if tt.fail { + assert.ErrorContains(t, err, tt.expectedErr) + } else { + assert.NoError(t, err) } }) } diff --git a/pkg/cmd/source_date_epoch_test.go b/pkg/cmd/source_date_epoch_test.go index 719de7c90..fa64c08b0 100644 --- a/pkg/cmd/source_date_epoch_test.go +++ b/pkg/cmd/source_date_epoch_test.go @@ -19,64 +19,48 @@ package cmd import ( "testing" "time" + + "github.com/stretchr/testify/require" ) func TestSourceDateEpochFromEnv(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "1609459200") got, err := sourceDateEpochFromEnv() - if err != nil { - t.Fatalf("sourceDateEpochFromEnv() error: %v", err) - } - if got == nil { - t.Fatal("expected non-nil epoch") - } + require.NoError(t, err, "sourceDateEpochFromEnv()") + require.NotNil(t, got, "expected non-nil epoch") want := time.Unix(1609459200, 0).UTC() - if !got.Equal(want) { - t.Fatalf("expected %v, got %v", want, *got) - } + require.Truef(t, got.Equal(want), "expected %v, got %v", want, *got) } func TestSourceDateEpochFromEnvUnset(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "") got, err := sourceDateEpochFromEnv() - if err != nil { - t.Fatalf("sourceDateEpochFromEnv() error: %v", err) - } - if got != nil { - t.Fatalf("expected nil epoch, got %v", *got) - } + require.NoError(t, err, "sourceDateEpochFromEnv()") + require.Nil(t, got, "expected nil epoch") } func TestSourceDateEpochFromEnvInvalid(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "not-a-number") - if _, err := sourceDateEpochFromEnv(); err == nil { - t.Fatal("expected error for invalid SOURCE_DATE_EPOCH") - } + _, err := sourceDateEpochFromEnv() + require.Error(t, err, "expected error for invalid SOURCE_DATE_EPOCH") } func TestSourceDateEpochFromEnvNegative(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "-1") - if _, err := sourceDateEpochFromEnv(); err == nil { - t.Fatal("expected error for negative SOURCE_DATE_EPOCH") - } + _, err := sourceDateEpochFromEnv() + require.Error(t, err, "expected error for negative SOURCE_DATE_EPOCH") } func TestSourceDateEpochFromEnvZero(t *testing.T) { t.Setenv("SOURCE_DATE_EPOCH", "0") got, err := sourceDateEpochFromEnv() - if err != nil { - t.Fatalf("sourceDateEpochFromEnv() error: %v", err) - } - if got == nil { - t.Fatal("expected non-nil epoch") - } + require.NoError(t, err, "sourceDateEpochFromEnv() error") + require.NotNil(t, got, "expected non-nil epoch") want := time.Unix(0, 0).UTC() - if !got.Equal(want) { - t.Fatalf("expected %v, got %v", want, *got) - } + require.Truef(t, got.Equal(want), "expected %v, got %v", want, *got) } diff --git a/pkg/cmd/uninstall.go b/pkg/cmd/uninstall.go index bfecd4741..315c29a8d 100644 --- a/pkg/cmd/uninstall.go +++ b/pkg/cmd/uninstall.go @@ -42,6 +42,7 @@ are fully deleted before the command returns. func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewUninstall(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) cmd := &cobra.Command{ Use: "uninstall RELEASE_NAME [...]", diff --git a/pkg/cmd/upgrade.go b/pkg/cmd/upgrade.go index c038a2149..688842141 100644 --- a/pkg/cmd/upgrade.go +++ b/pkg/cmd/upgrade.go @@ -84,6 +84,7 @@ which can contain sensitive values. To hide Kubernetes Secrets use the func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewUpgrade(cfg) + client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...) valueOpts := &values.Options{} var outfmt output.Format var createNamespace bool @@ -139,6 +140,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { instClient.SkipCRDs = client.SkipCRDs instClient.Timeout = client.Timeout instClient.WaitStrategy = client.WaitStrategy + instClient.WaitOptions = client.WaitOptions instClient.WaitForJobs = client.WaitForJobs instClient.Devel = client.Devel instClient.Namespace = client.Namespace @@ -224,6 +226,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { ContentCache: settings.ContentCache, Debug: settings.Debug, SourceDateEpoch: sourceDateEpoch, + RegistryClient: registryClient, } if err := man.Update(); err != nil { return err diff --git a/pkg/cmd/upgrade_test.go b/pkg/cmd/upgrade_test.go index 30188d3d9..5aba7b11b 100644 --- a/pkg/cmd/upgrade_test.go +++ b/pkg/cmd/upgrade_test.go @@ -18,13 +18,16 @@ package cmd import ( "fmt" + "net/http" + "net/http/httptest" "os" "path/filepath" - "reflect" - "strings" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/chart/common" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" @@ -44,13 +47,9 @@ func TestUpgradeCmd(t *testing.T) { }, } chartPath := filepath.Join(tmpChart, cfile.Metadata.Name) - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart for upgrade: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart for upgrade") ch, err := loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading chart: %v", err) - } + require.NoError(t, err, "Error loading chart") _ = release.Mock(&release.MockReleaseOptions{ Name: "funny-bunny", Chart: ch, @@ -59,25 +58,17 @@ func TestUpgradeCmd(t *testing.T) { // update chart version cfile.Metadata.Version = "0.1.2" - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart") ch, err = loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading updated chart: %v", err) - } + require.NoError(t, err, "Error loading updated chart") // update chart version again cfile.Metadata.Version = "0.1.3" - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart") var ch2 *chart.Chart ch2, err = loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading updated chart: %v", err) - } + require.NoError(t, err, "Error loading updated chart") missingDepsPath := "testdata/testcharts/chart-missing-deps" badDepsPath := "testdata/testcharts/chart-bad-requirements" @@ -193,6 +184,58 @@ func TestUpgradeCmd(t *testing.T) { runTestCmd(t, tests) } +// TestUpgradeDependencyUpdateOCINoPanic is a regression test for a nil-pointer +// panic in `helm upgrade --dependency-update` when a chart declares an OCI +// dependency. The upgrade command built its downloader.Manager without a +// RegistryClient (unlike install, dependency update, and dependency build), so +// resolving an OCI dependency dereferenced a nil *registry.Client. The command +// must now return a graceful error instead of panicking. +func TestUpgradeDependencyUpdateOCINoPanic(t *testing.T) { + defer resetEnv()() + + // A stub registry that answers the API-version ping but rejects the tag + // lookup, so OCI dependency resolution fails fast and hermetically instead + // of reaching a real registry. + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Docker-Distribution-API-Version", "registry/2.0") + if r.URL.Path == "/v2/" { + w.WriteHeader(http.StatusOK) + } else { + w.WriteHeader(http.StatusNotFound) + } + })) + defer srv.Close() + + // A chart with an unresolved OCI dependency forces --dependency-update into + // the tag-lookup path that previously panicked: the version is a range (an + // explicit version would skip the lookup) and the dependency is not present + // under charts/. + tmp := t.TempDir() + parent := &chart.Chart{ + Metadata: &chart.Metadata{ + APIVersion: chart.APIVersionV2, + Name: "oci-parent", + Version: "0.1.0", + Dependencies: []*chart.Dependency{{ + Name: "subchart", + Repository: fmt.Sprintf("oci://%s/charts", srv.Listener.Addr()), + Version: "^1.0.0", + }}, + }, + } + require.NoError(t, chartutil.SaveDir(parent, tmp), "Error creating chart") + chartPath := filepath.Join(tmp, parent.Metadata.Name) + // SaveDir writes only resolved subcharts (Chart.Dependencies()), not the + // declared Metadata.Dependencies, so create the empty charts/ directory + // explicitly to make the "dependency missing from charts/" state concrete. + require.NoError(t, os.MkdirAll(filepath.Join(chartPath, "charts"), 0o755), "Error creating charts dir") + + // The command must return an error (registry rejects the lookup), not panic. + _, _, err := executeActionCommandC(storageFixture(), + fmt.Sprintf("upgrade --dependency-update --plain-http oci-parent '%s'", chartPath)) + require.Error(t, err, "expected an error resolving the OCI dependency, got nil") +} + func TestUpgradeWithValue(t *testing.T) { releaseName := "funny-bunny-v2" relMock, ch, chartPath := prepareMockRelease(t, releaseName) @@ -205,22 +248,14 @@ func TestUpgradeWithValue(t *testing.T) { cmd := fmt.Sprintf("upgrade %s --set favoriteDrink=tea '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 4) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: tea") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: tea", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func TestUpgradeWithStringValue(t *testing.T) { @@ -235,22 +270,14 @@ func TestUpgradeWithStringValue(t *testing.T) { cmd := fmt.Sprintf("upgrade %s --set-string favoriteDrink=coffee '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 4) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: coffee") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: coffee", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func TestUpgradeInstallWithSubchartNotes(t *testing.T) { @@ -265,26 +292,15 @@ func TestUpgradeInstallWithSubchartNotes(t *testing.T) { cmd := fmt.Sprintf("upgrade %s -i --render-subchart-notes '%s'", releaseName, "testdata/testcharts/chart-with-subchart-notes") _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) upgradedReli, err := store.Get(releaseName, 2) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - upgradedRel, err := releaserToV1Release(upgradedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(upgradedRel.Info.Notes, "PARENT NOTES") { - t.Errorf("The parent notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes) - } - - if !strings.Contains(upgradedRel.Info.Notes, "SUBCHART NOTES") { - t.Errorf("The subchart notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes) - } + upgradedRel, err := releaserToV1Release(upgradedReli) + require.NoError(t, err) + assert.Contains(t, upgradedRel.Info.Notes, "PARENT NOTES", "The parent notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes) + assert.Contains(t, upgradedRel.Info.Notes, "SUBCHART NOTES", "The subchart notes are not set correctly. NOTES: %s", upgradedRel.Info.Notes) } func TestUpgradeWithValuesFile(t *testing.T) { @@ -299,22 +315,14 @@ func TestUpgradeWithValuesFile(t *testing.T) { cmd := fmt.Sprintf("upgrade %s --values testdata/testcharts/upgradetest/values.yaml '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 4) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: beer") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: beer", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func TestUpgradeWithValuesFromStdin(t *testing.T) { @@ -328,28 +336,18 @@ func TestUpgradeWithValuesFromStdin(t *testing.T) { store.Create(relMock(releaseName, 3, ch)) in, err := os.Open("testdata/testcharts/upgradetest/values.yaml") - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) cmd := fmt.Sprintf("upgrade %s --values - '%s'", releaseName, chartPath) _, _, err = executeActionCommandStdinC(store, in, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 4) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: beer") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: beer", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func TestUpgradeInstallWithValuesFromStdin(t *testing.T) { @@ -361,37 +359,25 @@ func TestUpgradeInstallWithValuesFromStdin(t *testing.T) { store := storageFixture() in, err := os.Open("testdata/testcharts/upgradetest/values.yaml") - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) cmd := fmt.Sprintf("upgrade %s -f - --install '%s'", releaseName, chartPath) _, _, err = executeActionCommandStdinC(store, in, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 1) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !strings.Contains(updatedRel.Manifest, "drink: beer") { - t.Errorf("The value is not set correctly. manifest: %s", updatedRel.Manifest) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Contains(t, updatedRel.Manifest, "drink: beer", "The value is not set correctly. manifest: %s", updatedRel.Manifest) } func prepareMockRelease(t *testing.T, releaseName string) (func(n string, v int, ch *chart.Chart) *release.Release, *chart.Chart, string) { t.Helper() tmpChart := t.TempDir() configmapData, err := os.ReadFile("testdata/testcharts/upgradetest/templates/configmap.yaml") - if err != nil { - t.Fatalf("Error loading template yaml %v", err) - } + require.NoError(t, err, "Error loading template yaml") cfile := &chart.Chart{ Metadata: &chart.Metadata{ APIVersion: chart.APIVersionV1, @@ -402,13 +388,9 @@ func prepareMockRelease(t *testing.T, releaseName string) (func(n string, v int, Templates: []*common.File{{Name: "templates/configmap.yaml", ModTime: time.Now(), Data: configmapData}}, } chartPath := filepath.Join(tmpChart, cfile.Metadata.Name) - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart for upgrade: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart for upgrade") ch, err := loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading chart: %v", err) - } + require.NoError(t, err, "Error loading chart") _ = release.Mock(&release.MockReleaseOptions{ Name: releaseName, Chart: ch, @@ -475,35 +457,23 @@ func TestUpgradeInstallWithLabels(t *testing.T) { } cmd := fmt.Sprintf("upgrade %s --install --labels key1=val1,key2=val2 '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) updatedReli, err := store.Get(releaseName, 1) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } - updatedRel, err := releaserToV1Release(updatedReli) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) - if !reflect.DeepEqual(updatedRel.Labels, expectedLabels) { - t.Errorf("Expected {%v}, got {%v}", expectedLabels, updatedRel.Labels) - } + updatedRel, err := releaserToV1Release(updatedReli) + require.NoError(t, err) + assert.Equal(t, expectedLabels, updatedRel.Labels) } func prepareMockReleaseWithSecret(t *testing.T, releaseName string) (func(n string, v int, ch *chart.Chart) *release.Release, *chart.Chart, string) { t.Helper() tmpChart := t.TempDir() configmapData, err := os.ReadFile("testdata/testcharts/chart-with-secret/templates/configmap.yaml") - if err != nil { - t.Fatalf("Error loading template yaml %v", err) - } + require.NoError(t, err, "Error loading template yaml") secretData, err := os.ReadFile("testdata/testcharts/chart-with-secret/templates/secret.yaml") - if err != nil { - t.Fatalf("Error loading template yaml %v", err) - } + require.NoError(t, err, "Error loading template yaml") modTime := time.Now() cfile := &chart.Chart{ Metadata: &chart.Metadata{ @@ -515,13 +485,9 @@ func prepareMockReleaseWithSecret(t *testing.T, releaseName string) (func(n stri Templates: []*common.File{{Name: "templates/configmap.yaml", ModTime: modTime, Data: configmapData}, {Name: "templates/secret.yaml", ModTime: modTime, Data: secretData}}, } chartPath := filepath.Join(tmpChart, cfile.Metadata.Name) - if err := chartutil.SaveDir(cfile, tmpChart); err != nil { - t.Fatalf("Error creating chart for upgrade: %v", err) - } + require.NoErrorf(t, chartutil.SaveDir(cfile, tmpChart), "Error creating chart for upgrade") ch, err := loader.Load(chartPath) - if err != nil { - t.Fatalf("Error loading chart: %v", err) - } + require.NoError(t, err, "Error loading chart") _ = release.Mock(&release.MockReleaseOptions{ Name: releaseName, Chart: ch, @@ -546,54 +512,34 @@ func TestUpgradeWithDryRun(t *testing.T) { // have it available. cmd := fmt.Sprintf("upgrade %s --install '%s'", releaseName, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) _, err = store.Get(releaseName, 1) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) cmd = fmt.Sprintf("upgrade %s --dry-run '%s'", releaseName, chartPath) _, out, err := executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) // No second release should be stored because this is a dry run. _, err = store.Get(releaseName, 2) - if err == nil { - t.Error("expected error as there should be no new release but got none") - } - - if !strings.Contains(out, "kind: Secret") { - t.Error("expected secret in output from --dry-run but found none") - } + require.Error(t, err, "expected error as there should be no new release but got none") + assert.Contains(t, out, "kind: Secret", "expected secret in output from --dry-run but found none") // Ensure the secret is not in the output cmd = fmt.Sprintf("upgrade %s --dry-run --hide-secret '%s'", releaseName, chartPath) _, out, err = executeActionCommandC(store, cmd) - if err != nil { - t.Errorf("unexpected error, got '%v'", err) - } + require.NoError(t, err) // No second release should be stored because this is a dry run. _, err = store.Get(releaseName, 2) - if err == nil { - t.Error("expected error as there should be no new release but got none") - } - - if strings.Contains(out, "kind: Secret") { - t.Error("expected no secret in output from --dry-run --hide-secret but found one") - } + require.Error(t, err, "expected error as there should be no new release but got none") + assert.NotContains(t, out, "kind: Secret", "expected no secret in output from --dry-run --hide-secret but found one") // Ensure there is an error when --hide-secret used without dry-run cmd = fmt.Sprintf("upgrade %s --hide-secret '%s'", releaseName, chartPath) _, _, err = executeActionCommandC(store, cmd) - if err == nil { - t.Error("expected error when --hide-secret used without --dry-run") - } + assert.Error(t, err, "expected error when --hide-secret used without --dry-run") } func TestUpgradeInstallServerSideApply(t *testing.T) { @@ -630,23 +576,14 @@ func TestUpgradeInstallServerSideApply(t *testing.T) { cmd := fmt.Sprintf("upgrade %s --install %s '%s'", releaseName, tt.serverSideFlag, chartPath) _, _, err := executeActionCommandC(store, cmd) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } + require.NoError(t, err) rel, err := store.Get(releaseName, 1) - if err != nil { - t.Fatalf("unexpected error getting release: %v", err) - } + require.NoError(t, err, "unexpected error getting release") relV1, err := releaserToV1Release(rel) - if err != nil { - t.Fatalf("unexpected error converting release: %v", err) - } - - if relV1.ApplyMethod != tt.expectedApplyMethod { - t.Errorf("expected ApplyMethod %q, got %q", tt.expectedApplyMethod, relV1.ApplyMethod) - } + require.NoError(t, err, "unexpected error converting release") + assert.Equal(t, tt.expectedApplyMethod, relV1.ApplyMethod, "expected ApplyMethod %q, got %q", tt.expectedApplyMethod, relV1.ApplyMethod) }) } } diff --git a/pkg/cmd/verify_test.go b/pkg/cmd/verify_test.go index 050d799c9..0b4078e1e 100644 --- a/pkg/cmd/verify_test.go +++ b/pkg/cmd/verify_test.go @@ -19,6 +19,9 @@ import ( "fmt" "runtime" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestVerifyCmd(t *testing.T) { @@ -73,18 +76,11 @@ func TestVerifyCmd(t *testing.T) { t.Run(tt.name, func(t *testing.T) { _, out, err := executeActionCommand(tt.cmd) if tt.wantError { - if err == nil { - t.Errorf("Expected error, but got none: %q", out) - } - if err.Error() != tt.expect { - t.Errorf("Expected error %q, got %q", tt.expect, err) - } - return - } else if err != nil { - t.Errorf("Unexpected error: %s", err) - } - if out != tt.expect { - t.Errorf("Expected %q, got %q", tt.expect, out) + require.Error(t, err, "Expected error, but got none: %q", out) + assert.EqualError(t, err, tt.expect, "Expected error %q", tt.expect) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expect, out, "Expected %q, got %q", tt.expect, out) } }) } diff --git a/pkg/downloader/cache_test.go b/pkg/downloader/cache_test.go index 49a7adc5d..32f014727 100644 --- a/pkg/downloader/cache_test.go +++ b/pkg/downloader/cache_test.go @@ -105,10 +105,9 @@ func TestDiskCache_PutAndGet(t *testing.T) { t.Run("GetDirectory", func(t *testing.T) { dirKey := sha256.Sum256([]byte("i am a directory")) dirPath := cache.fileName(dirKey, CacheChart) - err := os.MkdirAll(dirPath, 0o755) - require.NoError(t, err) + require.NoError(t, os.MkdirAll(dirPath, 0o755)) - _, err = cache.Get(dirKey, CacheChart) + _, err := cache.Get(dirKey, CacheChart) assert.EqualError(t, err, "is a directory") }) } diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index a4de2f5e3..92d4f024d 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -18,7 +18,6 @@ package downloader import ( "crypto/sha256" "encoding/hex" - "errors" "os" "path/filepath" "testing" @@ -69,9 +68,7 @@ func TestResolveChartRef(t *testing.T) { // Create a mock registry client for OCI references registryClient, err := registry.NewClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) c := ChartDownloader{ Out: os.Stderr, @@ -85,17 +82,15 @@ func TestResolveChartRef(t *testing.T) { } for _, tt := range tests { - _, u, err := c.ResolveChartVersion(tt.ref, tt.version) - if err != nil { - if tt.fail { - continue + t.Run(tt.name, func(t *testing.T) { + _, u, err := c.ResolveChartVersion(tt.ref, tt.version) + if err != nil { + require.True(t, tt.fail) + } else { + got := u.String() + assert.Equalf(t, tt.expect, got, "%s: expected %s, got %s", tt.name, tt.expect, got) } - t.Errorf("%s: failed with error %q", tt.name, err) - continue - } - if got := u.String(); got != tt.expect { - t.Errorf("%s: expected %s, got %s", tt.name, tt.expect, got) - } + }) } } @@ -128,48 +123,34 @@ func TestResolveChartOpts(t *testing.T) { snapshotOpts := c.Options for _, tt := range tests { - // reset chart downloader options for each test case - c.Options = snapshotOpts - - expect, err := getter.NewHTTPGetter(tt.expect...) - if err != nil { - t.Errorf("%s: failed to setup http client: %s", tt.name, err) - continue - } - - _, u, err := c.ResolveChartVersion(tt.ref, tt.version) - if err != nil { - t.Errorf("%s: failed with error %s", tt.name, err) - continue - } - - got, err := getter.NewHTTPGetter( - append( - c.Options, - getter.WithURL(u.String()), - )..., - ) - if err != nil { - t.Errorf("%s: failed to create http client: %s", tt.name, err) - continue - } - - if *(got.(*getter.HTTPGetter)) != *(expect.(*getter.HTTPGetter)) { - t.Errorf("%s: expected %s, got %s", tt.name, expect, got) - } + t.Run(tt.name, func(t *testing.T) { + // reset chart downloader options for each test case + c.Options = snapshotOpts + + expect, err := getter.NewHTTPGetter(tt.expect...) + require.NoError(t, err, "failed to setup http client") + + _, u, err := c.ResolveChartVersion(tt.ref, tt.version) + require.NoError(t, err, "failed with error") + + got, err := getter.NewHTTPGetter( + append( + c.Options, + getter.WithURL(u.String()), + )..., + ) + require.NoError(t, err, "failed to create http client") + assert.Equal(t, expect, got) + }) } } func TestVerifyChart(t *testing.T) { v, err := VerifyChart("testdata/signtest-0.1.0.tgz", "testdata/signtest-0.1.0.tgz.prov", "testdata/helm-test-key.pub") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // The verification is tested at length in the provenance package. Here, // we just want a quick sanity check that the v is not empty. - if v.FileHash == "" { - t.Error("Digest missing") - } + assert.NotEmpty(t, v.FileHash, "Digest missing") } func TestIsTar(t *testing.T) { @@ -183,9 +164,7 @@ func TestIsTar(t *testing.T) { } for src, expect := range tests { - if isTar(src) != expect { - t.Errorf("%q should be %t", src, expect) - } + assert.Equal(t, expect, isTar(src), "%q should be %t", src, expect) } } @@ -196,13 +175,8 @@ func TestDownloadTo(t *testing.T) { repotest.WithMiddleware(repotest.BasicAuthMiddleware(t)), ) defer srv.Stop() - if err := srv.CreateIndex(); err != nil { - t.Fatal(err) - } - - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.CreateIndex()) + require.NoError(t, srv.LinkIndices()) contentCache := t.TempDir() @@ -226,21 +200,14 @@ func TestDownloadTo(t *testing.T) { cname := "/signtest-0.1.0.tgz" dest := srv.Root() where, v, err := c.DownloadTo(srv.URL()+cname, "", dest) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if expect := filepath.Join(dest, cname); where != expect { - t.Errorf("Expected download to %s, got %s", expect, where) - } - - if v.FileHash == "" { - t.Error("File hash was empty, but verification is required.") - } + expect := filepath.Join(dest, cname) + assert.Equalf(t, expect, where, "Expected download to %s, got %s", expect, where) + assert.NotEmpty(t, v.FileHash, "File hash was empty, but verification is required.") - if _, err := os.Stat(filepath.Join(dest, cname)); err != nil { - t.Error(err) - } + _, err = os.Stat(filepath.Join(dest, cname)) + assert.NoError(t, err) } func TestDownloadTo_TLS(t *testing.T) { @@ -251,12 +218,8 @@ func TestDownloadTo_TLS(t *testing.T) { repotest.WithTLSConfig(repotest.MakeTestTLSConfig(t, "../../testdata")), ) defer srv.Stop() - if err := srv.CreateIndex(); err != nil { - t.Fatal(err) - } - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.CreateIndex()) + require.NoError(t, srv.LinkIndices()) repoConfig := filepath.Join(srv.Root(), "repositories.yaml") repoCache := srv.Root() @@ -285,22 +248,15 @@ func TestDownloadTo_TLS(t *testing.T) { cname := "test/signtest" dest := srv.Root() where, v, err := c.DownloadTo(cname, "", dest) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) target := filepath.Join(dest, "signtest-0.1.0.tgz") - if expect := target; where != expect { - t.Errorf("Expected download to %s, got %s", expect, where) - } + expect := target + assert.Equalf(t, expect, where, "Expected download to %s, got %s", expect, where) + assert.NotEmpty(t, v.FileHash, "File hash was empty, but verification is required.") - if v.FileHash == "" { - t.Error("File hash was empty, but verification is required.") - } - - if _, err := os.Stat(target); err != nil { - t.Error(err) - } + _, err = os.Stat(target) + assert.NoError(t, err) } func TestDownloadTo_VerifyLater(t *testing.T) { @@ -314,9 +270,7 @@ func TestDownloadTo_VerifyLater(t *testing.T) { repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) contentCache := t.TempDir() c := ChartDownloader{ @@ -333,20 +287,16 @@ func TestDownloadTo_VerifyLater(t *testing.T) { } cname := "/signtest-0.1.0.tgz" where, _, err := c.DownloadTo(srv.URL()+cname, "", dest) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if expect := filepath.Join(dest, cname); where != expect { - t.Errorf("Expected download to %s, got %s", expect, where) - } + expect := filepath.Join(dest, cname) + assert.Equalf(t, expect, where, "Expected download to %s, got %s", expect, where) - if _, err := os.Stat(filepath.Join(dest, cname)); err != nil { - t.Fatal(err) - } - if _, err := os.Stat(filepath.Join(dest, cname+".prov")); err != nil { - t.Fatal(err) - } + _, err = os.Stat(filepath.Join(dest, cname)) + require.NoError(t, err) + + _, err = os.Stat(filepath.Join(dest, cname+".prov")) + require.NoError(t, err) } func TestScanReposForURL(t *testing.T) { @@ -363,24 +313,17 @@ func TestScanReposForURL(t *testing.T) { u := "http://example.com/alpine-0.2.0.tgz" rf, err := repo.LoadFile(repoConfig) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) entry, err := c.scanReposForURL(u, rf) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if entry.Name != "testing" { - t.Errorf("Unexpected repo %q for URL %q", entry.Name, u) - } + assert.Equal(t, "testing", entry.Name, "Unexpected repo %q for URL %q", entry.Name, u) // A lookup failure should produce an ErrNoOwnerRepo u = "https://no.such.repo/foo/bar-1.23.4.tgz" - if _, err = c.scanReposForURL(u, rf); !errors.Is(err, ErrNoOwnerRepo) { - t.Fatalf("expected ErrNoOwnerRepo, got %v", err) - } + _, err = c.scanReposForURL(u, rf) + require.ErrorIs(t, err, ErrNoOwnerRepo) } func TestDownloadToCache(t *testing.T) { @@ -388,12 +331,8 @@ func TestDownloadToCache(t *testing.T) { repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.CreateIndex(); err != nil { - t.Fatal(err) - } - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.CreateIndex()) + require.NoError(t, srv.LinkIndices()) // The repo file needs to point to our server. repoFile := filepath.Join(srv.Root(), "repositories.yaml") @@ -431,6 +370,7 @@ func TestDownloadToCache(t *testing.T) { // Check that it's in the cache digest, _, err := c.ResolveChartVersion("test/signtest", "0.1.0") require.NoError(t, err) + digestBytes, err := hex.DecodeString(digest) require.NoError(t, err) var digestArray [sha256.Size]byte @@ -472,6 +412,7 @@ func TestDownloadToCache(t *testing.T) { // Check that both chart and prov are in cache digest, _, err := c.ResolveChartVersion("test/signtest", "0.1.0") require.NoError(t, err) + digestBytes, err := hex.DecodeString(digest) require.NoError(t, err) var digestArray [sha256.Size]byte @@ -479,6 +420,7 @@ func TestDownloadToCache(t *testing.T) { _, err = c.Cache.Get(digestArray, CacheChart) require.NoError(t, err, "chart should be in cache") + _, err = c.Cache.Get(digestArray, CacheProv) require.NoError(t, err, "provenance file should be in cache") diff --git a/pkg/downloader/chart_downloader_windows_test.go b/pkg/downloader/chart_downloader_windows_test.go index 732416701..0c7a23d23 100644 --- a/pkg/downloader/chart_downloader_windows_test.go +++ b/pkg/downloader/chart_downloader_windows_test.go @@ -23,6 +23,9 @@ import ( "sync" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/getter" "helm.sh/helm/v4/pkg/repo/v1/repotest" @@ -36,9 +39,7 @@ func TestParallelDownloadTo(t *testing.T) { srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/*.tgz")) defer srv.Stop() - if err := srv.CreateIndex(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.CreateIndex()) dest := t.TempDir() cacheDir := t.TempDir() @@ -86,46 +87,36 @@ func TestParallelDownloadTo(t *testing.T) { } // With the file locking fix, all parallel downloads should succeed - if failedCount > 0 { - t.Errorf("Parallel downloads failed: %d out of %d downloads failed due to concurrent file access", failedCount, numDownloads) - } + assert.Falsef(t, failedCount > 0, "Parallel downloads failed: %d out of %d downloads failed due to concurrent file access", failedCount, numDownloads) // Verify the file exists and is valid expectedFile := filepath.Join(dest, "local-subchart-0.1.0.tgz") info, err := os.Stat(expectedFile) - if err != nil { - t.Errorf("Expected file %s does not exist: %v", expectedFile, err) - } else { - // Verify the file is not empty - if info.Size() == 0 { - t.Errorf("Downloaded file %s is empty (0 bytes)", expectedFile) - } - - // Verify the file has the expected size (should match the source file) - sourceFile := "testdata/local-subchart-0.1.0.tgz" - sourceInfo, err := os.Stat(sourceFile) - if err == nil && info.Size() != sourceInfo.Size() { - t.Errorf("Downloaded file size (%d bytes) doesn't match source file size (%d bytes)", - info.Size(), sourceInfo.Size()) - } - - // Verify it's a valid tar.gz file by checking the magic bytes - file, err := os.Open(expectedFile) - if err == nil { - defer file.Close() - // gzip magic bytes are 0x1f 0x8b - magic := make([]byte, 2) - if n, err := file.Read(magic); err == nil && n == 2 { - if magic[0] != 0x1f || magic[1] != 0x8b { - t.Errorf("Downloaded file is not a valid gzip file (magic bytes: %x)", magic) - } - } - } - - // Verify no lock file was left behind - lockFile := expectedFile + ".lock" - if _, err := os.Stat(lockFile); err == nil { - t.Errorf("Lock file %s was not cleaned up", lockFile) + require.NoError(t, err, "Expected file %s does not exist: %v", expectedFile) + // Verify the file is not empty + assert.Falsef(t, info.Size() == 0, "Downloaded file %s is empty (0 bytes)", expectedFile) + + // Verify the file has the expected size (should match the source file) + sourceFile := "testdata/local-subchart-0.1.0.tgz" + sourceInfo, err := os.Stat(sourceFile) + require.NoError(t, err) + assert.False(t, info.Size() != sourceInfo.Size(), "Downloaded file size doesn't match source file size") + + // Verify it's a valid tar.gz file by checking the magic bytes + file, err := os.Open(expectedFile) + if err == nil { + defer file.Close() + // gzip magic bytes are 0x1f 0x8b + magic := make([]byte, 2) + n, err := file.Read(magic) + require.NoError(t, err) + if n == 2 { + assert.False(t, magic[0] != 0x1f || magic[1] != 0x8b, "Downloaded file is not a valid gzip file (magic bytes: %x)", magic) } } + + // Verify no lock file was left behind + lockFile := expectedFile + ".lock" + _, err = os.Stat(lockFile) + assert.Falsef(t, err == nil, "Lock file %s was not cleaned up", lockFile) } diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index e0cea0cd2..e40bbbac1 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -17,11 +17,9 @@ package downloader import ( "bytes" - "errors" "io/fs" "os" "path/filepath" - "reflect" "testing" "time" @@ -50,9 +48,7 @@ func TestVersionEquals(t *testing.T) { } for _, tt := range tests { - if versionEquals(tt.v1, tt.v2) != tt.expect { - t.Errorf("%s: failed comparison of %q and %q (expect equal: %t)", tt.name, tt.v1, tt.v2, tt.expect) - } + assert.Equal(t, tt.expect, versionEquals(tt.v1, tt.v2), "%s: failed comparison of %q and %q (expect equal: %t)", tt.name, tt.v1, tt.v2, tt.expect) } } @@ -64,84 +60,46 @@ func TestFindChartURL(t *testing.T) { RepositoryCache: repoCache, } repos, err := m.loadChartRepositories() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) name := "alpine" version := "0.1.0" repoURL := "http://example.com/charts" churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err := m.findChartURL(name, version, repoURL, repos) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if churl != "https://charts.helm.sh/stable/alpine-0.1.0.tgz" { - t.Errorf("Unexpected URL %q", churl) - } - if username != "" { - t.Errorf("Unexpected username %q", username) - } - if password != "" { - t.Errorf("Unexpected password %q", password) - } - if passcredentialsall != false { - t.Errorf("Unexpected passcredentialsall %t", passcredentialsall) - } - if insecureSkipTLSVerify { - t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) - } + assert.Equal(t, "https://charts.helm.sh/stable/alpine-0.1.0.tgz", churl, "Unexpected URL %q", churl) + assert.Empty(t, username, "Unexpected username %q", username) + assert.Empty(t, password, "Unexpected password %q", password) + assert.False(t, passcredentialsall, "Unexpected passcredentialsall %t", passcredentialsall) + assert.False(t, insecureSkipTLSVerify, "Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) name = "tlsfoo" version = "1.2.3" repoURL = "https://example-https-insecureskiptlsverify.com" churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !insecureSkipTLSVerify { - t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) - } - if churl != "https://example.com/tlsfoo-1.2.3.tgz" { - t.Errorf("Unexpected URL %q", churl) - } - if username != "" { - t.Errorf("Unexpected username %q", username) - } - if password != "" { - t.Errorf("Unexpected password %q", password) - } - if passcredentialsall != false { - t.Errorf("Unexpected passcredentialsall %t", passcredentialsall) - } + assert.True(t, insecureSkipTLSVerify, "Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) + assert.Equal(t, "https://example.com/tlsfoo-1.2.3.tgz", churl, "Unexpected URL %q", churl) + assert.Empty(t, username, "Unexpected username %q", username) + assert.Empty(t, password, "Unexpected password %q", password) + assert.False(t, passcredentialsall, "Unexpected passcredentialsall %t", passcredentialsall) name = "foo" version = "1.2.3" repoURL = "http://example.com/helm" churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if churl != "http://example.com/helm/charts/foo-1.2.3.tgz" { - t.Errorf("Unexpected URL %q", churl) - } - if username != "" { - t.Errorf("Unexpected username %q", username) - } - if password != "" { - t.Errorf("Unexpected password %q", password) - } - if passcredentialsall != false { - t.Errorf("Unexpected passcredentialsall %t", passcredentialsall) - } - if insecureSkipTLSVerify { - t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) - } + assert.Equal(t, "http://example.com/helm/charts/foo-1.2.3.tgz", churl, "Unexpected URL %q", churl) + assert.Empty(t, username, "Unexpected username %q", username) + assert.Empty(t, password, "Unexpected password %q", password) + assert.False(t, passcredentialsall, "Unexpected passcredentialsall %t", passcredentialsall) + assert.False(t, insecureSkipTLSVerify, "Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) } func TestGetRepoNames(t *testing.T) { @@ -209,23 +167,16 @@ func TestGetRepoNames(t *testing.T) { } for _, tt := range tests { - l, err := m.resolveRepoNames(tt.req) - if err != nil { + t.Run(tt.name, func(t *testing.T) { + l, err := m.resolveRepoNames(tt.req) if tt.err { - continue + require.Error(t, err) + } else { + require.NoError(t, err) + // m1 and m2 are the maps we want to compare + assert.Equal(t, l, tt.expect, "%s: expected map %v, got %v", tt.name, l, tt.name) } - t.Fatal(err) - } - - if tt.err { - t.Fatalf("Expected error in test %q", tt.name) - } - - // m1 and m2 are the maps we want to compare - eq := reflect.DeepEqual(l, tt.expect) - if !eq { - t.Errorf("%s: expected map %v, got %v", tt.name, l, tt.name) - } + }) } } @@ -238,20 +189,12 @@ func TestDownloadAll(t *testing.T) { ChartPath: chartPath, } signtest, err := loader.LoadDir(filepath.Join("testdata", "signtest")) - if err != nil { - t.Fatal(err) - } - if err := chartutil.SaveDir(signtest, filepath.Join(chartPath, "testdata")); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + require.NoError(t, chartutil.SaveDir(signtest, filepath.Join(chartPath, "testdata"))) local, err := loader.LoadDir(filepath.Join("testdata", "local-subchart")) - if err != nil { - t.Fatal(err) - } - if err := chartutil.SaveDir(local, filepath.Join(chartPath, "charts")); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + require.NoError(t, chartutil.SaveDir(local, filepath.Join(chartPath, "charts"))) signDep := &chart.Dependency{ Name: signtest.Name(), @@ -265,16 +208,11 @@ func TestDownloadAll(t *testing.T) { } // create a 'tmpcharts' directory to test #5567 - if err := os.MkdirAll(filepath.Join(chartPath, "tmpcharts"), 0o755); err != nil { - t.Fatal(err) - } - if err := m.downloadAll([]*chart.Dependency{signDep, localDep}); err != nil { - t.Error(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(chartPath, "tmpcharts"), 0o755)) + require.NoError(t, m.downloadAll([]*chart.Dependency{signDep, localDep})) - if _, err := os.Stat(filepath.Join(chartPath, "charts", "signtest-0.1.0.tgz")); errors.Is(err, fs.ErrNotExist) { - t.Error(err) - } + _, err = os.Stat(filepath.Join(chartPath, "charts", "signtest-0.1.0.tgz")) + require.NotErrorIs(t, err, fs.ErrNotExist) // A chart with a bad name like this cannot be loaded and saved. Handling in // the loading and saving will return an error about the invalid name. In @@ -283,24 +221,15 @@ func TestDownloadAll(t *testing.T) { description: A Helm chart for Kubernetes name: ../bad-local-subchart version: 0.1.0` - if err := os.MkdirAll(filepath.Join(chartPath, "testdata", "bad-local-subchart"), 0o755); err != nil { - t.Fatal(err) - } - err = os.WriteFile(filepath.Join(chartPath, "testdata", "bad-local-subchart", "Chart.yaml"), []byte(badchartyaml), 0o644) - if err != nil { - t.Fatal(err) - } + require.NoError(t, os.MkdirAll(filepath.Join(chartPath, "testdata", "bad-local-subchart"), 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(chartPath, "testdata", "bad-local-subchart", "Chart.yaml"), []byte(badchartyaml), 0o644)) badLocalDep := &chart.Dependency{ Name: "../bad-local-subchart", Repository: "file://./testdata/bad-local-subchart", Version: "0.1.0", } - - err = m.downloadAll([]*chart.Dependency{badLocalDep}) - if err == nil { - t.Fatal("Expected error for bad dependency name") - } + require.Error(t, m.downloadAll([]*chart.Dependency{badLocalDep}), "Expected error for bad dependency name") } func TestUpdateBeforeBuild(t *testing.T) { @@ -310,9 +239,7 @@ func TestUpdateBeforeBuild(t *testing.T) { repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) dir := func(p ...string) string { return filepath.Join(append([]string{srv.Root()}, p...)...) } @@ -325,9 +252,7 @@ func TestUpdateBeforeBuild(t *testing.T) { APIVersion: "v1", }, } - if err := chartutil.SaveDir(d, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(d, dir())) // Save a chart c := &chart.Chart{ Metadata: &chart.Metadata{ @@ -341,9 +266,7 @@ func TestUpdateBeforeBuild(t *testing.T) { }}, }, } - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) // Set-up a manager b := bytes.NewBuffer(nil) @@ -360,13 +283,8 @@ func TestUpdateBeforeBuild(t *testing.T) { } // Update before Build. see issue: https://github.com/helm/helm/issues/7101 - if err := m.Update(); err != nil { - t.Fatal(err) - } - - if err := m.Build(); err != nil { - t.Fatal(err) - } + require.NoError(t, m.Update()) + require.NoError(t, m.Build()) } // TestUpdateWithNoRepo is for the case of a dependency that has no repo listed. @@ -379,9 +297,7 @@ func TestUpdateWithNoRepo(t *testing.T) { repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) dir := func(p ...string) string { return filepath.Join(append([]string{srv.Root()}, p...)...) } @@ -407,16 +323,12 @@ func TestUpdateWithNoRepo(t *testing.T) { }}, }, } - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) // Save dependent chart into the parents charts directory. If the chart is // not in the charts directory Helm will return an error that it is not // found. - if err := chartutil.SaveDir(d, dir(c.Metadata.Name, "charts")); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(d, dir(c.Metadata.Name, "charts"))) // Set-up a manager b := bytes.NewBuffer(nil) @@ -433,9 +345,7 @@ func TestUpdateWithNoRepo(t *testing.T) { } // Test the update - if err := m.Update(); err != nil { - t.Fatal(err) - } + require.NoError(t, m.Update()) } // This function is the skeleton test code of failing tests for #6416 and #6871 and bugs due to #5874. @@ -452,9 +362,7 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe repotest.WithChartSourceGlob("testdata/*.tgz*"), ) defer srv.Stop() - if err := srv.LinkIndices(); err != nil { - t.Fatal(err) - } + require.NoError(t, srv.LinkIndices()) dir := func(p ...string) string { return filepath.Join(append([]string{srv.Root()}, p...)...) } @@ -479,9 +387,7 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe Dependencies: []*chart.Dependency{&dep}, }, } - if err := chartutil.SaveDir(c, dir()); err != nil { - t.Fatal(err) - } + require.NoError(t, chartutil.SaveDir(c, dir())) // Set-up a manager b := bytes.NewBuffer(nil) @@ -500,14 +406,10 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe } // First build will update dependencies and create Chart.lock file. - if err := m.Build(); err != nil { - t.Fatal(err) - } + require.NoError(t, m.Build()) // Second build should be passed. See PR #6655. - if err := m.Build(); err != nil { - t.Fatal(err) - } + require.NoError(t, m.Build()) } func TestBuild_WithoutOptionalFields(t *testing.T) { @@ -573,9 +475,7 @@ func TestErrRepoNotFound_Error(t *testing.T) { e := ErrRepoNotFound{ Repos: tt.fields.Repos, } - if got := e.Error(); got != tt.want { - t.Errorf("Error() = %v, want %v", got, tt.want) - } + assert.EqualError(t, e, tt.want) }) } } @@ -601,12 +501,8 @@ func TestKey(t *testing.T) { for _, tt := range tests { o, err := key(tt.name) - if err != nil { - t.Fatalf("unable to generate key for %q with error: %s", tt.name, err) - } - if o != tt.expect { - t.Errorf("wrong key name generated for %q, expected %q but got %q", tt.name, tt.expect, o) - } + require.NoError(t, err, "unable to generate key for %q", tt.name) + assert.Equal(t, tt.expect, o, "wrong key name generated for %q, expected %q but got %q", tt.name, tt.expect, o) } } @@ -697,8 +593,7 @@ func TestWriteLock(t *testing.T) { t.Run("v2 lock file", func(t *testing.T) { dir := t.TempDir() - err := writeLock(dir, lock, false) - require.NoError(t, err) + require.NoError(t, writeLock(dir, lock, false)) lockfilePath := filepath.Join(dir, "Chart.lock") _, err = os.Stat(lockfilePath) @@ -716,8 +611,7 @@ func TestWriteLock(t *testing.T) { t.Run("v1 lock file", func(t *testing.T) { dir := t.TempDir() - err := writeLock(dir, lock, true) - require.NoError(t, err) + require.NoError(t, writeLock(dir, lock, true)) lockfilePath := filepath.Join(dir, "requirements.lock") _, err = os.Stat(lockfilePath) @@ -737,9 +631,7 @@ func TestWriteLock(t *testing.T) { dir := t.TempDir() lockfilePath := filepath.Join(dir, "Chart.lock") require.NoError(t, os.WriteFile(lockfilePath, []byte("old content"), 0o644)) - - err = writeLock(dir, lock, false) - require.NoError(t, err) + require.NoError(t, writeLock(dir, lock, false)) content, err := os.ReadFile(lockfilePath) require.NoError(t, err) @@ -753,17 +645,13 @@ func TestWriteLock(t *testing.T) { lockfilePath := filepath.Join(dir, "Chart.lock") require.NoError(t, os.Symlink(dummyFile, lockfilePath)) - - err = writeLock(dir, lock, false) - assert.ErrorContains(t, err, "the Chart.lock file is a symlink to") + assert.ErrorContains(t, writeLock(dir, lock, false), "the Chart.lock file is a symlink to") }) t.Run("chart path is not a directory", func(t *testing.T) { dir := t.TempDir() filePath := filepath.Join(dir, "not-a-dir") require.NoError(t, os.WriteFile(filePath, []byte("file"), 0o644)) - - err = writeLock(filePath, lock, false) - assert.Error(t, err) + assert.Error(t, writeLock(filePath, lock, false)) }) } diff --git a/pkg/engine/doc.go b/pkg/engine/doc.go index e764a829a..9bb1059f2 100644 --- a/pkg/engine/doc.go +++ b/pkg/engine/doc.go @@ -21,4 +21,4 @@ When Helm renders templates it does so with additional functions and different modes (e.g., strict, lint mode). This package handles the helm specific implementation. */ -package engine // import "helm.sh/helm/v4/pkg/engine" +package engine diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index f666b63a6..1f3096366 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -51,9 +51,7 @@ func TestSortTemplates(t *testing.T) { "/mychart/templates/charts/bar/templates/foo.tpl": {}, } got := sortTemplates(tpls) - if len(got) != len(tpls) { - t.Fatal("Sorted results are missing templates") - } + require.Len(t, got, len(tpls), "Sorted results are missing templates") expect := []string{ "/mychart/templates/charts/foo/charts/bar/templates/foo.tpl", @@ -65,12 +63,7 @@ func TestSortTemplates(t *testing.T) { "/mychart/templates/_foo.tpl", } for i, e := range expect { - if got[i] != e { - t.Fatalf("\n\tExp:\n%s\n\tGot:\n%s", - strings.Join(expect, "\n"), - strings.Join(got, "\n"), - ) - } + require.Equal(t, e, got[i], "\n\tExp:\n%s\n\tGot:\n%s", strings.Join(expect, "\n"), strings.Join(got, "\n")) } } @@ -78,17 +71,14 @@ func TestFuncMap(t *testing.T) { fns := funcMap() forbidden := []string{"env", "expandenv"} for _, f := range forbidden { - if _, ok := fns[f]; ok { - t.Errorf("Forbidden function %s exists in FuncMap.", f) - } + _, ok := fns[f] + assert.Falsef(t, ok, "Forbidden function %s exists in FuncMap.", f) } // Test for Engine-specific template functions. expect := []string{"include", "required", "tpl", "toYaml", "fromYaml", "toToml", "fromToml", "toJson", "fromJson", "lookup"} for _, f := range expect { - if _, ok := fns[f]; !ok { - t.Errorf("Expected add-on function %q", f) - } + assert.Containsf(t, fns, f, "Expected add-on function %q", f) } } @@ -120,13 +110,9 @@ func TestRender(t *testing.T) { } v, err := util.CoalesceValues(c, vals) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") out, err := Render(c, v) - if err != nil { - t.Errorf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") expect := map[string]string{ "moby/templates/test1": "Spouter Inn", @@ -137,9 +123,7 @@ func TestRender(t *testing.T) { } for name, data := range expect { - if out[name] != data { - t.Errorf("Expected %q, got %q", data, out[name]) - } + assert.Equal(t, data, out[name], "Expected %q, got %q", data, out[name]) } } @@ -173,14 +157,10 @@ func TestRenderRefsOrdering(t *testing.T) { for i := range 100 { out, err := Render(parentChart, common.Values{}) - if err != nil { - t.Fatalf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") for name, data := range expect { - if out[name] != data { - t.Fatalf("Expected %q, got %q (iteration %d)", data, out[name], i+1) - } + require.Equal(t, data, out[name], "Expected %q, got %q (iteration %d)", data, out[name], i+1) } } } @@ -198,25 +178,12 @@ func TestRenderInternals(t *testing.T) { } out, err := new(Engine).render(t.Context(), tpls) - if err != nil { - t.Fatalf("Failed template rendering: %s", err) - } - - if len(out) != 3 { - t.Fatalf("Expected 3 templates, got %d", len(out)) - } - - if out["one"] != "Hello One" { - t.Errorf("Expected 'Hello One', got %q", out["one"]) - } - if out["two"] != "Goodbye TWO" { - t.Errorf("Expected 'Goodbye TWO'. got %q", out["two"]) - } - - if out["three"] != "Goodbye THREE" { - t.Errorf("Expected 'Goodbye THREE'. got %q", out["two"]) - } + require.NoError(t, err, "Failed template rendering") + require.Len(t, out, 3, "Expected 3 templates, got %d", len(out)) + assert.Equal(t, "Hello One", out["one"]) + assert.Equal(t, "Goodbye TWO", out["two"]) + assert.Equal(t, "Goodbye THREE", out["three"]) } func TestRenderWithDNS(t *testing.T) { @@ -236,22 +203,16 @@ func TestRenderWithDNS(t *testing.T) { } v, err := util.CoalesceValues(c, vals) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") var e Engine e.EnableDNS = true out, err := e.Render(c, v) - if err != nil { - t.Errorf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") for _, val := range c.Templates { fp := path.Join("moby", val.Name) - if out[fp] == "" { - t.Errorf("Expected IP address, got %q", out[fp]) - } + assert.NotEmpty(t, out[fp], "Expected IP address, got %q", out[fp]) } } @@ -375,21 +336,15 @@ func TestRenderWithClientProvider(t *testing.T) { } v, err := util.CoalesceValues(c, vals) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") out, err := RenderWithClientProvider(c, v, provider) - if err != nil { - t.Errorf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") for name, want := range cases { t.Run(name, func(t *testing.T) { key := path.Join("moby/templates", name) - if out[key] != want.output { - t.Errorf("Expected %q, got %q", want, out[key]) - } + assert.Equal(t, want.output, out[key], "Expected %q, got %q", want, out[key]) }) } } @@ -411,9 +366,7 @@ func TestRenderWithClientProvider_error(t *testing.T) { } v, err := util.CoalesceValues(c, vals) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") provider := &testClientProvider{ t: t, @@ -424,9 +377,7 @@ func TestRenderWithClientProvider_error(t *testing.T) { }, } _, err = RenderWithClientProvider(c, v, provider) - if err == nil || !strings.Contains(err.Error(), "kaboom") { - t.Errorf("Expected error from client provider when rendering, got %q", err) - } + assert.ErrorContainsf(t, err, "kaboom", "Expected error from client provider when rendering") } func TestParallelRenderInternals(t *testing.T) { @@ -444,12 +395,8 @@ func TestParallelRenderInternals(t *testing.T) { }, } out, err := e.render(t.Context(), tpls) - if err != nil { - t.Errorf("Failed to render %s: %s", tt, err) - } - if out["t"] != tt { - t.Errorf("Expected %q, got %q", tt, out["t"]) - } + assert.NoError(t, err, "Failed to render %s", tt) + assert.Equal(t, tt, out["t"], "Expected %q, got %q", tt, out["t"]) wg.Done() }(i) } @@ -463,13 +410,8 @@ func TestParseErrors(t *testing.T) { "undefined_function": {tpl: `{{foo}}`, vals: vals}, } _, err := new(Engine).render(t.Context(), tplsUndefinedFunction) - if err == nil { - t.Fatalf("Expected failures while rendering: %s", err) - } - expected := `parse error at (undefined_function:1): function "foo" not defined` - if err.Error() != expected { - t.Errorf("Expected '%s', got %q", expected, err.Error()) - } + require.Error(t, err, "Expected failures while rendering") + assert.EqualError(t, err, `parse error at (undefined_function:1): function "foo" not defined`) } func TestExecErrors(t *testing.T) { @@ -526,12 +468,8 @@ linebreak`, for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { _, err := new(Engine).render(t.Context(), tt.tpls) - if err == nil { - t.Fatalf("Expected failures while rendering: %s", err) - } - if err.Error() != tt.expected { - t.Errorf("Expected %q, got %q", tt.expected, err.Error()) - } + require.Error(t, err, "Expected failures while rendering") + assert.EqualError(t, err, tt.expected) }) } } @@ -544,25 +482,15 @@ func TestFailErrors(t *testing.T) { "failtpl": {tpl: failtpl, vals: vals}, } _, err := new(Engine).render(t.Context(), tplsFailed) - if err == nil { - t.Fatalf("Expected failures while rendering: %s", err) - } + require.Error(t, err, "Expected failures while rendering") expected := `execution error at (failtpl:1:33): This is an error` - if err.Error() != expected { - t.Errorf("Expected '%s', got %q", expected, err.Error()) - } + require.EqualError(t, err, expected) var e Engine e.LintMode = true out, err := e.render(t.Context(), tplsFailed) - if err != nil { - t.Fatal(err) - } - - expectStr := "All your base are belong to us" - if gotStr := out["failtpl"]; gotStr != expectStr { - t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out) - } + require.NoError(t, err) + assert.Equal(t, "All your base are belong to us", out["failtpl"]) } func TestAllTemplates(t *testing.T) { @@ -592,9 +520,7 @@ func TestAllTemplates(t *testing.T) { dep1.AddDependency(dep2) tpls := allTemplates(ch1, common.Values{}) - if len(tpls) != 5 { - t.Errorf("Expected 5 charts, got %d", len(tpls)) - } + assert.Len(t, tpls, 5, "Expected 5 charts, got %d", len(tpls)) } func TestChartValuesContainsIsRoot(t *testing.T) { @@ -614,17 +540,13 @@ func TestChartValuesContainsIsRoot(t *testing.T) { ch1.AddDependency(dep1) out, err := Render(ch1, common.Values{}) - if err != nil { - t.Fatalf("failed to render templates: %s", err) - } + require.NoError(t, err, "failed to render templates") expects := map[string]string{ "parent/charts/child/templates/isroot": "false", "parent/templates/isroot": "true", } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -646,18 +568,10 @@ func TestRenderDependency(t *testing.T) { }) out, err := Render(ch, map[string]any{}) - if err != nil { - t.Fatalf("failed to render chart: %s", err) - } - - if len(out) != 2 { - t.Errorf("Expected 2, got %d", len(out)) - } + require.NoError(t, err, "failed to render chart") - expect := "Hello World" - if out["outerchart/templates/outer"] != expect { - t.Errorf("Expected %q, got %q", expect, out["outer"]) - } + assert.Len(t, out, 2, "Expected 2, got %d", len(out)) + assert.Equal(t, "Hello World", out["outerchart/templates/outer"]) } func TestRenderNestedValues(t *testing.T) { @@ -719,9 +633,7 @@ func TestRenderNestedValues(t *testing.T) { } tmp, err := util.CoalesceValues(outer, injValues) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") inject := common.Values{ "Values": tmp, @@ -734,34 +646,22 @@ func TestRenderNestedValues(t *testing.T) { t.Logf("Calculated values: %v", inject) out, err := Render(outer, inject) - if err != nil { - t.Fatalf("failed to render templates: %s", err) - } + require.NoError(t, err, "failed to render templates") fullouterpath := "top/" + outerpath - if out[fullouterpath] != "Gather ye rosebuds while ye may" { - t.Errorf("Unexpected outer: %q", out[fullouterpath]) - } + assert.Equal(t, "Gather ye rosebuds while ye may", out[fullouterpath], "Unexpected outer: %q", out[fullouterpath]) fullinnerpath := "top/charts/herrick/" + innerpath - if out[fullinnerpath] != "Old time is still a-flyin'" { - t.Errorf("Unexpected inner: %q", out[fullinnerpath]) - } + assert.Equal(t, "Old time is still a-flyin'", out[fullinnerpath], "Unexpected inner: %q", out[fullinnerpath]) fulldeepestpath := "top/charts/herrick/charts/deepest/" + deepestpath - if out[fulldeepestpath] != "And this same flower that smiles to-day" { - t.Errorf("Unexpected deepest: %q", out[fulldeepestpath]) - } + assert.Equal(t, "And this same flower that smiles to-day", out[fulldeepestpath], "Unexpected deepest: %q", out[fulldeepestpath]) fullcheckrelease := "top/charts/herrick/charts/deepest/" + checkrelease - if out[fullcheckrelease] != "Tomorrow will be dyin" { - t.Errorf("Unexpected release: %q", out[fullcheckrelease]) - } + assert.Equal(t, "Tomorrow will be dyin", out[fullcheckrelease], "Unexpected release: %q", out[fullcheckrelease]) fullchecksubcharts := "top/" + subchartspath - if out[fullchecksubcharts] != "The glorious Lamp of Heaven, the Sun" { - t.Errorf("Unexpected subcharts: %q", out[fullchecksubcharts]) - } + assert.Equal(t, "The glorious Lamp of Heaven, the Sun", out[fullchecksubcharts], "Unexpected subcharts: %q", out[fullchecksubcharts]) } func TestRenderBuiltinValues(t *testing.T) { @@ -798,9 +698,7 @@ func TestRenderBuiltinValues(t *testing.T) { t.Logf("Calculated values: %v", outer) out, err := Render(outer, inject) - if err != nil { - t.Fatalf("failed to render templates: %s", err) - } + require.NoError(t, err, "failed to render templates") expects := map[string]string{ "Troy/charts/Latium/templates/Lavinia": "Troy/charts/Latium/templates/LaviniaLatiumAeneid", @@ -809,9 +707,7 @@ func TestRenderBuiltinValues(t *testing.T) { "Troy/charts/Latium/templates/From": "Virgil Aeneid", } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -843,20 +739,12 @@ func TestAlterFuncMap_include(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := " Mistah Kurtz - he dead." - if got := out["conrad/templates/quote"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + require.NoError(t, err) + assert.Equal(t, " Mistah Kurtz - he dead.", out["conrad/templates/quote"]) _, err = Render(d, v) expectErrName := "nested/templates/quote" - if err == nil { - t.Errorf("Expected err of nested reference name: %v", expectErrName) - } + assert.Error(t, err, "Expected err of nested reference name: %v", expectErrName) } func TestAlterFuncMap_require(t *testing.T) { @@ -881,18 +769,10 @@ func TestAlterFuncMap_require(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - expectStr := "All your base are belong to us" - if gotStr := out["conan/templates/quote"]; gotStr != expectStr { - t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out) - } - expectNum := "All 2 of them!" - if gotNum := out["conan/templates/bases"]; gotNum != expectNum { - t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out) - } + assert.Equal(t, "All your base are belong to us", out["conan/templates/quote"]) + assert.Equal(t, "All 2 of them!", out["conan/templates/bases"]) // test required without passing in needed values with lint mode on // verifies lint replaces required with an empty string (should not fail) @@ -907,19 +787,11 @@ func TestAlterFuncMap_require(t *testing.T) { } var e Engine e.LintMode = true - out, err = e.Render(c, lintValues) - if err != nil { - t.Fatal(err) - } - expectStr = "All your base are belong to us" - if gotStr := out["conan/templates/quote"]; gotStr != expectStr { - t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out) - } - expectNum = "All of them!" - if gotNum := out["conan/templates/bases"]; gotNum != expectNum { - t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out) - } + out, err = e.Render(c, lintValues) + require.NoError(t, err) + assert.Equal(t, "All your base are belong to us", out["conan/templates/quote"]) + assert.Equal(t, "All of them!", out["conan/templates/bases"]) } func TestAlterFuncMap_tpl(t *testing.T) { @@ -941,14 +813,8 @@ func TestAlterFuncMap_tpl(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := "Evaluate tpl Value: myvalue" - if got := out["TplFunction/templates/base"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + require.NoError(t, err) + assert.Equal(t, "Evaluate tpl Value: myvalue", out["TplFunction/templates/base"]) } func TestAlterFuncMap_tplfunc(t *testing.T) { @@ -970,14 +836,8 @@ func TestAlterFuncMap_tplfunc(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := "Evaluate tpl Value: \"myvalue\"" - if got := out["TplFunction/templates/base"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + require.NoError(t, err) + assert.Equal(t, "Evaluate tpl Value: \"myvalue\"", out["TplFunction/templates/base"]) } func TestAlterFuncMap_tplinclude(t *testing.T) { @@ -1000,14 +860,8 @@ func TestAlterFuncMap_tplinclude(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := "\"TplFunction/templates/base\"" - if got := out["TplFunction/templates/base"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + require.NoError(t, err) + assert.Equal(t, "\"TplFunction/templates/base\"", out["TplFunction/templates/base"]) } func TestRenderRecursionLimit(t *testing.T) { @@ -1031,9 +885,8 @@ func TestRenderRecursionLimit(t *testing.T) { expectErr := "rendering template has a nested reference name: recursion: unable to execute template" _, err := Render(c, v) - if err == nil || !strings.HasSuffix(err.Error(), expectErr) { - t.Errorf("Expected err with suffix: %s", expectErr) - } + require.Error(t, err) + assert.True(t, strings.HasSuffix(err.Error(), expectErr), "Expected err with suffix: %s", expectErr) // calling the same function many times is ok times := 4000 @@ -1053,9 +906,7 @@ func TestRenderRecursionLimit(t *testing.T) { } out, err := Render(d, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var expect string var expectSb1062 strings.Builder @@ -1063,9 +914,7 @@ func TestRenderRecursionLimit(t *testing.T) { expectSb1062.WriteString(phrase + "\n") } expect += expectSb1062.String() - if got := out["overlook/templates/quote"]; got != expect { - t.Errorf("Expected %q, got %q (%v)", expect, got, out) - } + assert.Equal(t, expect, out["overlook/templates/quote"]) } func TestRenderLoadTemplateForTplFromFile(t *testing.T) { @@ -1094,14 +943,8 @@ func TestRenderLoadTemplateForTplFromFile(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } - - expect := "test-function nested-define-content" - if got := out["TplLoadFromFile/templates/base"]; got != expect { - t.Fatalf("Expected %q, got %q", expect, got) - } + require.NoError(t, err) + require.Equal(t, "test-function nested-define-content", out["TplLoadFromFile/templates/base"]) } func TestRenderTplEmpty(t *testing.T) { @@ -1122,9 +965,7 @@ func TestRenderTplEmpty(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expects := map[string]string{ "TplEmpty/templates/empty-string": "", @@ -1132,9 +973,7 @@ func TestRenderTplEmpty(t *testing.T) { "TplEmpty/templates/only-defines": "", } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -1168,9 +1007,7 @@ func TestRenderTplTemplateNames(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expects := map[string]string{ "TplTemplateNames/templates/default-basepath": "TplTemplateNames/templates", @@ -1180,9 +1017,7 @@ func TestRenderTplTemplateNames(t *testing.T) { "TplTemplateNames/templates/modified-field": "extra-field", } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -1232,9 +1067,7 @@ func TestRenderTplRedefines(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expects := map[string]string{ "TplRedefines/templates/partial": `before: original-in-partial\ntpl: redefined-in-tpl\nafter: original-in-partial`, @@ -1247,9 +1080,7 @@ func TestRenderTplRedefines(t *testing.T) { `after: original-in-manifest original-outer-in-manifest`, } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -1272,17 +1103,13 @@ func TestRenderTplMissingKey(t *testing.T) { } out, err := Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expects := map[string]string{ "TplMissingKey/templates/manifest": `missingValue: `, } for file, expect := range expects { - if out[file] != expect { - t.Errorf("Expected %q, got %q", expect, out[file]) - } + assert.Equal(t, expect, out[file], "Expected %q, got %q", expect, out[file]) } } @@ -1307,15 +1134,9 @@ func TestRenderTplMissingKeyString(t *testing.T) { e := new(Engine) e.Strict = true - out, err := e.Render(c, v) - if err == nil { - t.Errorf("Expected error, got %v", out) - return - } - errTxt := fmt.Sprint(err) - if !strings.Contains(errTxt, "noSuchKey") { - t.Errorf("Expected error to contain 'noSuchKey', got %s", errTxt) - } + _, err := e.Render(c, v) + require.Error(t, err) + assert.ErrorContains(t, err, "noSuchKey") } func TestNestedHelpersProducesMultilineStacktrace(t *testing.T) { @@ -1354,7 +1175,7 @@ NestedHelperFunctions/charts/common/templates/_helpers_2.tpl:1:49 _, err := Render(c, vals) require.Error(t, err) - assert.Equal(t, expectedErrorMessage, err.Error()) + assert.EqualError(t, err, expectedErrorMessage) } func TestMultilineNoTemplateAssociatedError(t *testing.T) { @@ -1374,11 +1195,6 @@ func TestMultilineNoTemplateAssociatedError(t *testing.T) { }, } - expectedErrorMessage := `multiline/templates/svc.yaml:1:9 - executing "multiline/templates/svc.yaml" at : - error calling include: -template: no template "nested_helper.name" associated with template "gotpl"` - v := common.Values{} val, _ := util.CoalesceValues(c, v) @@ -1388,7 +1204,10 @@ template: no template "nested_helper.name" associated with template "gotpl"` _, err := Render(c, vals) require.Error(t, err) - assert.Equal(t, expectedErrorMessage, err.Error()) + assert.EqualError(t, err, `multiline/templates/svc.yaml:1:9 + executing "multiline/templates/svc.yaml" at : + error calling include: +template: no template "nested_helper.name" associated with template "gotpl"`) } func TestRenderCustomTemplateFuncs(t *testing.T) { @@ -1436,23 +1255,17 @@ func TestRenderCustomTemplateFuncs(t *testing.T) { // Render the chart. out, err := e.Render(c, v) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Expected output should be "hello!!!". - expected := "hello!!!" - key := "CustomFunc/templates/manifest" - if rendered, ok := out[key]; !ok || rendered != expected { - t.Errorf("Expected %q, got %q", expected, rendered) - } + rendered, ok := out["CustomFunc/templates/manifest"] + require.True(t, ok) + assert.Equal(t, "hello!!!", rendered) // Verify that the rendered template used the custom "upper" function. - expected = "custom:hello" - key = "CustomFunc/templates/override" - if rendered, ok := out[key]; !ok || rendered != expected { - t.Errorf("Expected %q, got %q", expected, rendered) - } + rendered, ok = out["CustomFunc/templates/override"] + require.True(t, ok) + assert.Equal(t, "custom:hello", rendered) } func TestTraceableError_SimpleForm(t *testing.T) { @@ -1461,12 +1274,8 @@ func TestTraceableError_SimpleForm(t *testing.T) { } for _, errString := range testStrings { trace, done := parseTemplateSimpleErrorString(errString) - if !done { - t.Error("Expected parse to pass but did not") - } - if trace.message != "error calling include" { - t.Errorf("Expected %q, got %q", errString, trace.message) - } + assert.True(t, done, "Expected parse to pass but did not") + assert.Equal(t, "error calling include", trace.message, "Expected %q, got %q", errString, trace.message) } } func TestTraceableError_ExecutingForm(t *testing.T) { @@ -1478,12 +1287,8 @@ func TestTraceableError_ExecutingForm(t *testing.T) { errString := errTuple[0] expectedLocation := errTuple[1] trace, done := parseTemplateExecutingAtErrorType(errString) - if !done { - t.Error("Expected parse to pass but did not") - } - if trace.location != expectedLocation { - t.Errorf("Expected %q, got %q", expectedLocation, trace.location) - } + assert.True(t, done, "Expected parse to pass but did not") + assert.Equal(t, expectedLocation, trace.location, "Expected %q, got %q", expectedLocation, trace.location) } } @@ -1493,12 +1298,8 @@ func TestTraceableError_NoTemplateForm(t *testing.T) { } for _, errString := range testStrings { trace, done := parseTemplateNoTemplateError(errString, errString) - if !done { - t.Error("Expected parse to pass but did not") - } - if trace.message != errString { - t.Errorf("Expected %q, got %q", errString, trace.message) - } + assert.True(t, done, "Expected parse to pass but did not") + assert.Equal(t, errString, trace.message, "Expected %q, got %q", errString, trace.message) } } @@ -1535,9 +1336,7 @@ func TestRenderSubchartDefaultNilNoStringify(t *testing.T) { injValues := map[string]any{} tmp, err := util.CoalesceValues(parent, injValues) - if err != nil { - t.Fatalf("Failed to coalesce values: %s", err) - } + require.NoError(t, err, "Failed to coalesce values") inject := common.Values{ "Values": tmp, @@ -1548,18 +1347,9 @@ func TestRenderSubchartDefaultNilNoStringify(t *testing.T) { } out, err := Render(parent, inject) - if err != nil { - t.Fatalf("Failed to render templates: %s", err) - } + require.NoError(t, err, "Failed to render templates") rendered := out["parent/charts/child/templates/test.yaml"] - - if strings.Contains(rendered, "%!s()") { - t.Errorf("Rendered output contains %%!s(), got: %q", rendered) - } - - expected := "subPath: fallback" - if rendered != expected { - t.Errorf("Expected %q, got %q", expected, rendered) - } + assert.NotContains(t, rendered, "%!s()", "Rendered output contains %%!s(), got: %q", rendered) + assert.Equal(t, "subPath: fallback", rendered) } diff --git a/pkg/engine/files_test.go b/pkg/engine/files_test.go index b4318a597..9fec2e132 100644 --- a/pkg/engine/files_test.go +++ b/pkg/engine/files_test.go @@ -16,6 +16,7 @@ limitations under the License. package engine import ( + "strconv" "testing" "github.com/stretchr/testify/assert" @@ -44,17 +45,13 @@ func getTestFiles() files { func TestNewFiles(t *testing.T) { files := getTestFiles() - if len(files) != len(cases) { - t.Errorf("Expected len() = %d, got %d", len(cases), len(files)) - } + assert.Len(t, files, len(cases), "Expected len() = %d, got %d", len(cases), len(files)) for i, f := range cases { - if got := string(files.GetBytes(f.path)); got != f.data { - t.Errorf("%d: expected %q, got %q", i, f.data, got) - } - if got := files.Get(f.path); got != f.data { - t.Errorf("%d: expected %q, got %q", i, f.data, got) - } + t.Run(strconv.Itoa(i), func(t *testing.T) { + assert.Equal(t, f.data, string(files.GetBytes(f.path))) + assert.Equal(t, f.data, files.Get(f.path)) + }) } } diff --git a/pkg/engine/funcs_test.go b/pkg/engine/funcs_test.go index bc541339b..beb87b429 100644 --- a/pkg/engine/funcs_test.go +++ b/pkg/engine/funcs_test.go @@ -134,8 +134,7 @@ keyInElement1 = "valueInElement1"`, for _, tt := range tests { var b strings.Builder - err := template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars) - require.NoError(t, err) + require.NoError(t, template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars)) assert.Equal(t, tt.expect, b.String(), tt.tpl) } @@ -360,8 +359,7 @@ func TestDurationHelpers(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var b strings.Builder - err := template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars) - require.NoError(t, err, tt.tpl) + require.NoError(t, template.Must(template.New("test").Funcs(funcMap()).Parse(tt.tpl)).Execute(&b, tt.vars), tt.tpl) assert.Equal(t, tt.expect, b.String(), tt.tpl) }) } @@ -422,8 +420,7 @@ func TestDurationHelpers(t *testing.T) { Funcs(funcMap()). Parse(tt.tpl), ) - err := tmpl.Execute(&b, tt.vars) - require.Error(t, err, tt.tpl) + require.Error(t, tmpl.Execute(&b, tt.vars), tt.tpl) }) } } @@ -474,8 +471,7 @@ func TestMerge(t *testing.T) { } tpl := `{{merge .dst .src1 .src2}}` var b strings.Builder - err := template.Must(template.New("test").Funcs(funcMap()).Parse(tpl)).Execute(&b, dict) - require.NoError(t, err) + require.NoError(t, template.Must(template.New("test").Funcs(funcMap()).Parse(tpl)).Execute(&b, dict)) expected := map[string]any{ "a": "one", // key overridden diff --git a/pkg/gates/gates_test.go b/pkg/gates/gates_test.go index 217ee1bbe..e57f1aa8f 100644 --- a/pkg/gates/gates_test.go +++ b/pkg/gates/gates_test.go @@ -38,7 +38,7 @@ func TestError(t *testing.T) { os.Unsetenv(name) g := Gate(name) - assert.Equal(t, "this feature has been marked as experimental and is not enabled by default. Please set HELM_EXPERIMENTAL_FEATURE=1 in your environment to use this feature", g.Error().Error()) + assert.EqualError(t, g.Error(), "this feature has been marked as experimental and is not enabled by default. Please set HELM_EXPERIMENTAL_FEATURE=1 in your environment to use this feature") } func TestString(t *testing.T) { diff --git a/pkg/getter/getter_test.go b/pkg/getter/getter_test.go index 3a09b4d82..67cfc2ef0 100644 --- a/pkg/getter/getter_test.go +++ b/pkg/getter/getter_test.go @@ -19,6 +19,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/cli" ) @@ -30,9 +33,7 @@ func TestProvider(t *testing.T) { func(_ ...Option) (Getter, error) { return nil, nil }, } - if !p.Provides("three") { - t.Error("Expected provider to provide three") - } + assert.True(t, p.Provides("three"), "Expected provider to provide three") } func TestProviders(t *testing.T) { @@ -41,34 +42,25 @@ func TestProviders(t *testing.T) { {[]string{"two", "four"}, func(_ ...Option) (Getter, error) { return nil, nil }}, } - if _, err := ps.ByScheme("one"); err != nil { - t.Error(err) - } - if _, err := ps.ByScheme("four"); err != nil { - t.Error(err) - } + _, err := ps.ByScheme("one") + require.NoError(t, err) + _, err = ps.ByScheme("four") + require.NoError(t, err) - if _, err := ps.ByScheme("five"); err == nil { - t.Error("Did not expect handler for five") - } + _, err = ps.ByScheme("five") + assert.Error(t, err, "Did not expect handler for five") } func TestProvidersWithTimeout(t *testing.T) { want := time.Hour getters := Getters(WithTimeout(want)) getter, err := getters.ByScheme("http") - if err != nil { - t.Error(err) - } + require.NoError(t, err) httpGetter := getter.(*HTTPGetter) client, err := httpGetter.httpClient(httpGetter.opts) - if err != nil { - t.Error(err) - } + require.NoError(t, err) got := client.Timeout - if got != want { - t.Errorf("Expected %q, got %q", want, got) - } + assert.Equal(t, want, got, "Expected %q, got %q", want, got) } func TestAll(t *testing.T) { @@ -76,13 +68,10 @@ func TestAll(t *testing.T) { env.PluginsDirectory = pluginDir all := All(env) - if len(all) != 4 { - t.Errorf("expected 4 providers (default plus three plugins), got %d", len(all)) - } + assert.Len(t, all, 4, "expected 4 providers (default plus three plugins), got %d", len(all)) - if _, err := all.ByScheme("test2"); err != nil { - t.Error(err) - } + _, err := all.ByScheme("test2") + assert.NoError(t, err) } func TestByScheme(t *testing.T) { @@ -90,10 +79,8 @@ func TestByScheme(t *testing.T) { env.PluginsDirectory = pluginDir g := All(env) - if _, err := g.ByScheme("test"); err != nil { - t.Error(err) - } - if _, err := g.ByScheme("https"); err != nil { - t.Error(err) - } + _, err := g.ByScheme("test") + require.NoError(t, err) + _, err = g.ByScheme("https") + assert.NoError(t, err) } diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index d7ba770b3..aebb6f11c 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -28,6 +28,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/internal/tlsutil" "helm.sh/helm/v4/internal/version" "helm.sh/helm/v4/pkg/cli" @@ -35,13 +38,10 @@ import ( func TestHTTPGetter(t *testing.T) { g, err := NewHTTPGetter(WithURL("http://example.com")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := g.(*HTTPGetter); !ok { - t.Fatal("Expected NewHTTPGetter to produce an *HTTPGetter") - } + _, ok := g.(*HTTPGetter) + require.True(t, ok, "Expected NewHTTPGetter to produce an *HTTPGetter") cd := "../../testdata" join := filepath.Join @@ -60,54 +60,20 @@ func TestHTTPGetter(t *testing.T) { WithTimeout(timeout), WithTransport(transport), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) hg, ok := g.(*HTTPGetter) - if !ok { - t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter") - } - - if hg.opts.username != "I" { - t.Errorf("Expected NewHTTPGetter to contain %q as the username, got %q", "I", hg.opts.username) - } - - if hg.opts.password != "Am" { - t.Errorf("Expected NewHTTPGetter to contain %q as the password, got %q", "Am", hg.opts.password) - } - - if hg.opts.passCredentialsAll != false { - t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll) - } - - if hg.opts.userAgent != "Groot" { - t.Errorf("Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent) - } - - if hg.opts.certFile != pub { - t.Errorf("Expected NewHTTPGetter to contain %q as the public key file, got %q", pub, hg.opts.certFile) - } - - if hg.opts.keyFile != priv { - t.Errorf("Expected NewHTTPGetter to contain %q as the private key file, got %q", priv, hg.opts.keyFile) - } - - if hg.opts.caFile != ca { - t.Errorf("Expected NewHTTPGetter to contain %q as the CA file, got %q", ca, hg.opts.caFile) - } - - if hg.opts.insecureSkipVerifyTLS != insecure { - t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", false, hg.opts.insecureSkipVerifyTLS) - } - - if hg.opts.timeout != timeout { - t.Errorf("Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout) - } - - if hg.opts.transport != transport { - t.Errorf("Expected NewHTTPGetter to contain %p as Transport, got %p", transport, hg.opts.transport) - } + require.True(t, ok, "expected NewHTTPGetter to produce an *HTTPGetter") + assert.Equal(t, "I", hg.opts.username, "Expected NewHTTPGetter to contain %q as the username, got %q", "I", hg.opts.username) + assert.Equal(t, "Am", hg.opts.password, "Expected NewHTTPGetter to contain %q as the password, got %q", "Am", hg.opts.password) + assert.False(t, hg.opts.passCredentialsAll, "Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll) + assert.Equal(t, "Groot", hg.opts.userAgent, "Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent) + assert.Equal(t, pub, hg.opts.certFile, "Expected NewHTTPGetter to contain %q as the public key file, got %q", pub, hg.opts.certFile) + assert.Equal(t, priv, hg.opts.keyFile, "Expected NewHTTPGetter to contain %q as the private key file, got %q", priv, hg.opts.keyFile) + assert.Equal(t, ca, hg.opts.caFile, "Expected NewHTTPGetter to contain %q as the CA file, got %q", ca, hg.opts.caFile) + assert.Equal(t, insecure, hg.opts.insecureSkipVerifyTLS, "Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", false, hg.opts.insecureSkipVerifyTLS) + assert.Equal(t, timeout, hg.opts.timeout, "Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout) + assert.Same(t, transport, hg.opts.transport, "Expected NewHTTPGetter to contain %p as Transport, got %p", transport, hg.opts.transport) // Test if setting insecureSkipVerifyTLS is being passed to the ops insecure = true @@ -115,76 +81,51 @@ func TestHTTPGetter(t *testing.T) { g, err = NewHTTPGetter( WithInsecureSkipVerifyTLS(insecure), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) hg, ok = g.(*HTTPGetter) - if !ok { - t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter") - } - - if hg.opts.insecureSkipVerifyTLS != insecure { - t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", insecure, hg.opts.insecureSkipVerifyTLS) - } + require.True(t, ok, "expected NewHTTPGetter to produce an *HTTPGetter") + assert.Equal(t, insecure, hg.opts.insecureSkipVerifyTLS, "Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", insecure, hg.opts.insecureSkipVerifyTLS) // Checking false by default - if hg.opts.passCredentialsAll != false { - t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll) - } + assert.False(t, hg.opts.passCredentialsAll, "Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll) // Test setting PassCredentialsAll g, err = NewHTTPGetter( WithBasicAuth("I", "Am"), WithPassCredentialsAll(true), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) hg, ok = g.(*HTTPGetter) - if !ok { - t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter") - } - if hg.opts.passCredentialsAll != true { - t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", true, hg.opts.passCredentialsAll) - } + require.True(t, ok, "expected NewHTTPGetter to produce an *HTTPGetter") + assert.True(t, hg.opts.passCredentialsAll, "Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", true, hg.opts.passCredentialsAll) } func TestDownload(t *testing.T) { expect := "Call me Ishmael" srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defaultUserAgent := version.GetUserAgent() - if r.UserAgent() != defaultUserAgent { - t.Errorf("Expected '%s', got '%s'", defaultUserAgent, r.UserAgent()) - } + assert.Equal(t, defaultUserAgent, r.UserAgent(), "Expected '%s', got '%s'", defaultUserAgent, r.UserAgent()) fmt.Fprint(w, expect) })) defer srv.Close() g, err := All(cli.New()).ByScheme("http") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got, err := g.Get(srv.URL, WithURL(srv.URL)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if got.String() != expect { - t.Errorf("Expected %q, got %q", expect, got.String()) - } + assert.Equal(t, expect, got.String(), "Expected %q, got %q", expect, got.String()) // test with http server const expectedUserAgent = "I am Groot" basicAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() - if !ok || username != "username" || password != "password" { - t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password) - } - if r.UserAgent() != expectedUserAgent { - t.Errorf("Expected '%s', got '%s'", expectedUserAgent, r.UserAgent()) - } + assert.True(t, ok, "Expected request to use basic auth") + assert.Equal(t, "username", username) + assert.Equal(t, "password", password) + assert.Equal(t, expectedUserAgent, r.UserAgent(), "Expected '%s', got '%s'", expectedUserAgent, r.UserAgent()) fmt.Fprint(w, expect) })) @@ -197,24 +138,18 @@ func TestDownload(t *testing.T) { WithPassCredentialsAll(false), WithUserAgent(expectedUserAgent), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got, err = httpgetter.Get(u.String()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if got.String() != expect { - t.Errorf("Expected %q, got %q", expect, got.String()) - } + assert.Equal(t, expect, got.String(), "Expected %q, got %q", expect, got.String()) // test with Get URL differing from withURL crossAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() - if ok || username == "username" || password == "password" { - t.Errorf("Expected request to not include but got '%v', '%s', '%s'", ok, username, password) - } + assert.False(t, ok) + assert.NotEqual(t, "username", username) + assert.NotEqual(t, "password", password) fmt.Fprint(w, expect) })) @@ -232,24 +167,18 @@ func TestDownload(t *testing.T) { WithBasicAuth("username", "password"), WithPassCredentialsAll(false), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got, err = httpgetter.Get(u.String()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if got.String() != expect { - t.Errorf("Expected %q, got %q", expect, got.String()) - } + assert.Equal(t, expect, got.String(), "Expected %q, got %q", expect, got.String()) // test with Get URL differing from withURL and should pass creds crossAuthSrv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() - if !ok || username != "username" || password != "password" { - t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password) - } + assert.True(t, ok, "Expected request to use basic auth") + assert.Equal(t, "username", username) + assert.Equal(t, "password", password) fmt.Fprint(w, expect) })) @@ -267,24 +196,16 @@ func TestDownload(t *testing.T) { WithBasicAuth("username", "password"), WithPassCredentialsAll(true), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got, err = httpgetter.Get(u.String()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if got.String() != expect { - t.Errorf("Expected %q, got %q", expect, got.String()) - } + assert.Equal(t, expect, got.String(), "Expected %q, got %q", expect, got.String()) // test server with varied Accept Header const expectedAcceptHeader = "application/gzip,application/octet-stream" acceptHeaderSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Accept") != expectedAcceptHeader { - t.Errorf("Expected '%s', got '%s'", expectedAcceptHeader, r.Header.Get("Accept")) - } + assert.Equal(t, expectedAcceptHeader, r.Header.Get("Accept"), "Expected '%s', got '%s'", expectedAcceptHeader, r.Header.Get("Accept")) fmt.Fprint(w, expect) })) @@ -294,13 +215,9 @@ func TestDownload(t *testing.T) { httpgetter, err = NewHTTPGetter( WithAcceptHeader(expectedAcceptHeader), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = httpgetter.Get(u.String()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } func TestDownloadTLS(t *testing.T) { @@ -314,9 +231,7 @@ func TestDownloadTLS(t *testing.T) { tlsutil.WithCertKeyPairFiles(pub, priv), tlsutil.WithCAFile(ca), ) - if err != nil { - t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err)) - } + require.NoError(t, err, "can't create TLS config for client") tlsConf.ServerName = "helm.sh" tlsSrv.TLS = tlsConf tlsSrv.StartTLS() @@ -327,33 +242,24 @@ func TestDownloadTLS(t *testing.T) { WithURL(u.String()), WithTLSClientConfig(pub, priv, ca), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := g.Get(u.String()); err != nil { - t.Error(err) - } + _, err = g.Get(u.String()) + require.NoError(t, err) // now test with TLS config being passed along in .Get (see #6635) g, err = NewHTTPGetter() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)); err != nil { - t.Error(err) - } + _, err = g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)) + require.NoError(t, err) // test with only the CA file (see also #6635) g, err = NewHTTPGetter() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)); err != nil { - t.Error(err) - } + _, err = g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)) + assert.NoError(t, err) } func TestDownloadTLSWithRedirect(t *testing.T) { @@ -369,9 +275,7 @@ func TestDownloadTLSWithRedirect(t *testing.T) { tlsutil.WithInsecureSkipVerify(insecureSkipTLSVerify), ) - if err != nil { - t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err)) - } + require.NoError(t, err, "can't create TLS config for client") tlsSrv2 := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Header().Set("Content-Type", "text/plain") @@ -390,9 +294,7 @@ func TestDownloadTLSWithRedirect(t *testing.T) { tlsutil.WithInsecureSkipVerify(insecureSkipTLSVerify), ) - if err != nil { - t.Fatal(fmt.Errorf("can't create TLS config for client: %w", err)) - } + require.NoError(t, err, "can't create TLS config for client") tlsSrv1 := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { u, _ := url.ParseRequestURI(tlsSrv2.URL) @@ -419,65 +321,41 @@ func TestDownloadTLSWithRedirect(t *testing.T) { WithURL(u.String()), WithTLSClientConfig(pub, priv, ca), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) buf, err := g.Get(u.String()) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b, err := io.ReadAll(buf) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if string(b) != srv2Resp { - t.Errorf("expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) - } + assert.Equal(t, srv2Resp, string(b), "expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) }) t.Run("Test with TLS config being passed along in .Get (see #6635)", func(t *testing.T) { g, err := NewHTTPGetter() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) buf, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig(pub, priv, ca)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b, err := io.ReadAll(buf) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if string(b) != srv2Resp { - t.Errorf("expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) - } + assert.Equal(t, srv2Resp, string(b), "expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) }) t.Run("Test with only the CA file (see also #6635)", func(t *testing.T) { g, err := NewHTTPGetter() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) buf, err := g.Get(u.String(), WithURL(u.String()), WithTLSClientConfig("", "", ca)) - if err != nil { - t.Error(err) - } + require.NoError(t, err) b, err := io.ReadAll(buf) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if string(b) != srv2Resp { - t.Errorf("expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) - } + assert.Equal(t, srv2Resp, string(b), "expected response from Server2 to be '%s', instead got: %s", srv2Resp, string(b)) }) } @@ -491,25 +369,19 @@ func TestDownloadInsecureSkipTLSVerify(t *testing.T) { g, err := NewHTTPGetter( WithURL(u.String()), ) - if err != nil { - t.Error(err) - } + require.NoError(t, err) - if _, err := g.Get(u.String()); err == nil { - t.Errorf("Expected Getter to throw an error, got %s", err) - } + _, err = g.Get(u.String()) + require.Errorf(t, err, "Expected Getter to throw an error") // Test certificate check skip g, err = NewHTTPGetter( WithURL(u.String()), WithInsecureSkipVerifyTLS(true), ) - if err != nil { - t.Error(err) - } - if _, err = g.Get(u.String()); err != nil { - t.Error(err) - } + require.NoError(t, err) + _, err = g.Get(u.String()) + assert.NoError(t, err) } func TestHTTPGetterTarDownload(t *testing.T) { @@ -535,17 +407,13 @@ func TestHTTPGetterTarDownload(t *testing.T) { defer srv.Close() g, err := NewHTTPGetter(WithURL(srv.URL)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) data, _ := g.Get(srv.URL) mimeType := http.DetectContentType(data.Bytes()) expectedMimeType := "application/x-gzip" - if mimeType != expectedMimeType { - t.Fatalf("Expected response with MIME type %s, but got %s", expectedMimeType, mimeType) - } + require.Equal(t, expectedMimeType, mimeType, "Expected response with MIME type %s, but got %s", expectedMimeType, mimeType) } func TestHttpClientInsecureSkipVerify(t *testing.T) { @@ -569,31 +437,22 @@ func TestHttpClientInsecureSkipVerify(t *testing.T) { g.opts.keyFile = "testdata/client.key" g.opts.insecureSkipVerifyTLS = true transport := verifyInsecureSkipVerify(t, &g, "HTTPGetter with 2 way ssl", true) - if len(transport.TLSClientConfig.Certificates) == 0 { - t.Fatal("transport.TLSClientConfig.Certificates is not present") - } + require.NotEmpty(t, transport.TLSClientConfig.Certificates, "transport.TLSClientConfig.Certificates is not present") } func verifyInsecureSkipVerify(t *testing.T, g *HTTPGetter, caseName string, expectedValue bool) *http.Transport { t.Helper() returnVal, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if returnVal == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, returnVal, "Expected non nil value for http client") transport := (returnVal.Transport).(*http.Transport) gotValue := false if transport.TLSClientConfig != nil { gotValue = transport.TLSClientConfig.InsecureSkipVerify } - if gotValue != expectedValue { - t.Fatalf("Case Name = %s\nInsecureSkipVerify did not come as expected. Expected = %t; Got = %v", - caseName, expectedValue, gotValue) - } + require.Equal(t, expectedValue, gotValue, "Case Name = %s\nInsecureSkipVerify did not come as expected. Expected = %t; Got = %v", caseName, expectedValue, gotValue) return transport } @@ -602,31 +461,21 @@ func TestDefaultHTTPTransportReuse(t *testing.T) { httpClient1, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if httpClient1 == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, httpClient1, "Expected non nil value for http client") transport1 := (httpClient1.Transport).(*http.Transport) httpClient2, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if httpClient2 == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, httpClient2, "Expected non nil value for http client") transport2 := (httpClient2.Transport).(*http.Transport) - if transport1 != transport2 { - t.Fatal("Expected default transport to be reused") - } + require.Equal(t, transport2, transport1, "Expected default transport to be reused") } func TestHTTPTransportOption(t *testing.T) { @@ -636,35 +485,23 @@ func TestHTTPTransportOption(t *testing.T) { g.opts.transport = transport httpClient1, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if httpClient1 == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, httpClient1, "Expected non nil value for http client") transport1 := (httpClient1.Transport).(*http.Transport) - if transport1 != transport { - t.Fatal("Expected transport option to be applied") - } + require.Equal(t, transport, transport1, "Expected transport option to be applied") httpClient2, err := g.httpClient(g.opts) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if httpClient2 == nil { - t.Fatal("Expected non nil value for http client") - } + require.NotNil(t, httpClient2, "Expected non nil value for http client") transport2 := (httpClient2.Transport).(*http.Transport) - if transport1 != transport2 { - t.Fatal("Expected applied transport to be reused") - } + require.Equal(t, transport2, transport1, "Expected applied transport to be reused") g = HTTPGetter{} g.opts.url = "https://localhost" @@ -673,7 +510,5 @@ func TestHTTPTransportOption(t *testing.T) { g.opts.insecureSkipVerifyTLS = true g.opts.transport = transport usedTransport := verifyInsecureSkipVerify(t, &g, "HTTPGetter with 2 way ssl", false) - if usedTransport.TLSClientConfig != nil { - t.Fatal("transport.TLSClientConfig should not be set") - } + require.Nil(t, usedTransport.TLSClientConfig, "transport.TLSClientConfig should not be set") } diff --git a/pkg/getter/ocigetter_test.go b/pkg/getter/ocigetter_test.go index 5a7c99ebe..5e7f01420 100644 --- a/pkg/getter/ocigetter_test.go +++ b/pkg/getter/ocigetter_test.go @@ -21,18 +21,18 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/registry" ) func TestOCIGetter(t *testing.T) { g, err := NewOCIGetter(WithURL("oci://example.com")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := g.(*OCIGetter); !ok { - t.Fatal("Expected NewOCIGetter to produce an *OCIGetter") - } + _, ok := g.(*OCIGetter) + require.True(t, ok, "Expected NewOCIGetter to produce an *OCIGetter") cd := "../../testdata" join := filepath.Join @@ -51,71 +51,31 @@ func TestOCIGetter(t *testing.T) { WithInsecureSkipVerifyTLS(insecureSkipVerifyTLS), WithPlainHTTP(plainHTTP), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) og, ok := g.(*OCIGetter) - if !ok { - t.Fatal("expected NewOCIGetter to produce an *OCIGetter") - } - - if og.opts.username != "I" { - t.Errorf("Expected NewOCIGetter to contain %q as the username, got %q", "I", og.opts.username) - } - - if og.opts.password != "Am" { - t.Errorf("Expected NewOCIGetter to contain %q as the password, got %q", "Am", og.opts.password) - } - - if og.opts.certFile != pub { - t.Errorf("Expected NewOCIGetter to contain %q as the public key file, got %q", pub, og.opts.certFile) - } - - if og.opts.keyFile != priv { - t.Errorf("Expected NewOCIGetter to contain %q as the private key file, got %q", priv, og.opts.keyFile) - } - - if og.opts.caFile != ca { - t.Errorf("Expected NewOCIGetter to contain %q as the CA file, got %q", ca, og.opts.caFile) - } - - if og.opts.timeout != timeout { - t.Errorf("Expected NewOCIGetter to contain %s as Timeout flag, got %s", timeout, og.opts.timeout) - } - - if og.opts.transport != transport { - t.Errorf("Expected NewOCIGetter to contain %p as Transport, got %p", transport, og.opts.transport) - } - - if og.opts.plainHTTP != plainHTTP { - t.Errorf("Expected NewOCIGetter to have plainHTTP as %t, got %t", plainHTTP, og.opts.plainHTTP) - } - - if og.opts.insecureSkipVerifyTLS != insecureSkipVerifyTLS { - t.Errorf("Expected NewOCIGetter to have insecureSkipVerifyTLS as %t, got %t", insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS) - } + require.True(t, ok, "expected NewOCIGetter to produce an *OCIGetter") + assert.Equal(t, "I", og.opts.username, "Expected NewOCIGetter to contain %q as the username, got %q", "I", og.opts.username) + assert.Equal(t, "Am", og.opts.password, "Expected NewOCIGetter to contain %q as the password, got %q", "Am", og.opts.password) + assert.Equal(t, pub, og.opts.certFile, "Expected NewOCIGetter to contain %q as the public key file, got %q", pub, og.opts.certFile) + assert.Equal(t, priv, og.opts.keyFile, "Expected NewOCIGetter to contain %q as the private key file, got %q", priv, og.opts.keyFile) + assert.Equal(t, ca, og.opts.caFile, "Expected NewOCIGetter to contain %q as the CA file, got %q", ca, og.opts.caFile) + assert.Equal(t, timeout, og.opts.timeout, "Expected NewOCIGetter to contain %s as Timeout flag, got %s", timeout, og.opts.timeout) + assert.Equal(t, transport, og.opts.transport, "Expected NewOCIGetter to contain %p as Transport, got %p", transport, og.opts.transport) + assert.Equal(t, plainHTTP, og.opts.plainHTTP, "Expected NewOCIGetter to have plainHTTP as %t, got %t", plainHTTP, og.opts.plainHTTP) + assert.Equal(t, insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS, "Expected NewOCIGetter to have insecureSkipVerifyTLS as %t, got %t", insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS) // Test if setting registryClient is being passed to the ops registryClient, err := registry.NewClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) g, err = NewOCIGetter( WithRegistryClient(registryClient), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) og, ok = g.(*OCIGetter) - if !ok { - t.Fatal("expected NewOCIGetter to produce an *OCIGetter") - } - - if og.opts.registryClient != registryClient { - t.Errorf("Expected NewOCIGetter to contain %p as RegistryClient, got %p", registryClient, og.opts.registryClient) - } + require.True(t, ok, "expected NewOCIGetter to produce an *OCIGetter") + assert.Equal(t, registryClient, og.opts.registryClient, "Expected NewOCIGetter to contain %p as RegistryClient, got %p", registryClient, og.opts.registryClient) } func TestOCIHTTPTransportReuse(t *testing.T) { @@ -123,29 +83,19 @@ func TestOCIHTTPTransportReuse(t *testing.T) { _, err := g.newRegistryClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if g.transport == nil { - t.Fatal("Expected non nil value for transport") - } + require.NotNil(t, g.transport, "Expected non nil value for transport") transport1 := g.transport _, err = g.newRegistryClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if g.transport == nil { - t.Fatal("Expected non nil value for transport") - } + require.NotNil(t, g.transport, "Expected non nil value for transport") transport2 := g.transport - if transport1 != transport2 { - t.Fatal("Expected default transport to be reused") - } + require.Equal(t, transport2, transport1, "Expected default transport to be reused") } diff --git a/pkg/getter/plugingetter_test.go b/pkg/getter/plugingetter_test.go index 16af9eb31..c9ed9f779 100644 --- a/pkg/getter/plugingetter_test.go +++ b/pkg/getter/plugingetter_test.go @@ -35,25 +35,18 @@ func TestCollectPlugins(t *testing.T) { env.PluginsDirectory = pluginDir p, err := collectGetterPlugins(env) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(p) != 2 { - t.Errorf("Expected 2 plugins, got %d: %v", len(p), p) - } + assert.Len(t, p, 2, "Expected 2 plugins, got %d: %v", len(p), p) - if _, err := p.ByScheme("test2"); err != nil { - t.Error(err) - } + _, err = p.ByScheme("test2") + require.NoError(t, err) - if _, err := p.ByScheme("test"); err != nil { - t.Error(err) - } + _, err = p.ByScheme("test") + require.NoError(t, err) - if _, err := p.ByScheme("nosuchthing"); err == nil { - t.Fatal("did not expect protocol handler for nosuchthing") - } + _, err = p.ByScheme("nosuchthing") + require.Error(t, err, "did not expect protocol handler for nosuchthing") } func TestConvertOptions(t *testing.T) { diff --git a/pkg/ignore/doc.go b/pkg/ignore/doc.go index a66066eb2..bba658d41 100644 --- a/pkg/ignore/doc.go +++ b/pkg/ignore/doc.go @@ -65,4 +65,4 @@ Notable differences from .gitignore: - The evaluation of escape sequences has not been tested for compatibility - There is no support for '\!' as a special leading sequence. */ -package ignore // import "helm.sh/helm/v4/pkg/ignore" +package ignore diff --git a/pkg/kube/client.go b/pkg/kube/client.go index e363fad61..bb26fbcc9 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -167,14 +167,15 @@ func (c *Client) newStatusWatcher(opts ...WaitOption) (*statusWaiter, error) { waitContext = c.WaitContext } sw := &statusWaiter{ - restMapper: restMapper, - client: dynamicClient, - ctx: waitContext, - watchUntilReadyCtx: o.watchUntilReadyCtx, - waitCtx: o.waitCtx, - waitWithJobsCtx: o.waitWithJobsCtx, - waitForDeleteCtx: o.waitForDeleteCtx, - readers: o.statusReaders, + restMapper: restMapper, + client: dynamicClient, + ctx: waitContext, + watchUntilReadyCtx: o.watchUntilReadyCtx, + waitCtx: o.waitCtx, + waitWithJobsCtx: o.waitWithJobsCtx, + waitForDeleteCtx: o.waitForDeleteCtx, + readers: o.statusReaders, + statusComputeWorkers: o.statusComputeWorkers, } sw.SetLogger(c.Logger().Handler()) return sw, nil @@ -249,7 +250,7 @@ func (c *Client) getKubeClient() (kubernetes.Interface, error) { // IsReachable tests connectivity to the cluster. func (c *Client) IsReachable() error { client, err := c.getKubeClient() - if err == genericclioptions.ErrEmptyConfig { + if errors.Is(err, genericclioptions.ErrEmptyConfig) { // re-replace kubernetes ErrEmptyConfig error with a friendly error // moar workarounds for Kubernetes API breaking. return errors.New("kubernetes cluster unreachable") @@ -949,11 +950,12 @@ func (c *Client) Delete(resources ResourceList, policy metav1.DeletionPropagatio func isIncompatibleServerError(err error) bool { // 415: Unsupported media type means we're talking to a server which doesn't // support server-side apply. - if _, ok := err.(*apierrors.StatusError); !ok { + var sErr *apierrors.StatusError + if !errors.As(err, &sErr) { // Non-StatusError means the error isn't because the server is incompatible. return false } - return err.(*apierrors.StatusError).Status().Code == http.StatusUnsupportedMediaType + return sErr.Status().Code == http.StatusUnsupportedMediaType } // isServerSideRetryable checks if an error encountered during server-side apply diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 6421a2c2d..405925a30 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -316,9 +316,7 @@ func TestCreate(t *testing.T) { list, err := c.Build(objBody(&tc.Pods), false) require.NoError(t, err) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result, err := c.Create( list, @@ -487,7 +485,7 @@ func TestUpdate(t *testing.T) { data, err := io.ReadAll(req.Body) require.NoError(t, err) - assert.Equal(t, `{}`, string(data)) + assert.JSONEq(t, `{}`, string(data)) } return newResponse(http.StatusOK, &listTarget.Items[0]) @@ -569,17 +567,16 @@ func TestUpdate(t *testing.T) { // Special handling for the rollback test case if name == "rollback after failed upgrade with removed resource" { - assert.Empty(t, result.Created, "expected 0 resource created, got %d", len(result.Created)) - assert.Len(t, result.Updated, 1, "expected 1 resource updated, got %d", len(result.Updated)) - assert.Empty(t, result.Deleted, "expected 0 resource deleted, got %d", len(result.Deleted)) + assert.Empty(t, result.Created, "expected 0 resource created") + assert.Len(t, result.Updated, 1, "expected 1 resource updated") + assert.Empty(t, result.Deleted, "expected 0 resource deleted") } else { - assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - assert.Len(t, result.Updated, 2, "expected 2 resource updated, got %d", len(result.Updated)) - assert.Len(t, result.Deleted, 1, "expected 1 resource deleted, got %d", len(result.Deleted)) + assert.Len(t, result.Created, 1, "expected 1 resource created") + assert.Len(t, result.Updated, 2, "expected 2 resource updated") + assert.Len(t, result.Deleted, 1, "expected 1 resource deleted") } if tc.ExpectedError != "" { - require.Error(t, err) require.ErrorContains(t, err, tc.ExpectedError) } else { require.NoError(t, err) @@ -622,15 +619,12 @@ func TestBuild(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Test for an invalid manifest infos, err := c.Build(tt.reader, false) - if err != nil && !tt.err { - t.Errorf("Got error message when no error should have occurred: %v", err) - } else if err != nil && strings.Contains(err.Error(), "--validate=false") { - t.Error("error message was not scrubbed") - } - - if len(infos) != tt.count { - t.Errorf("expected %d result objects, got %d", tt.count, len(infos)) + if tt.err { + require.ErrorContains(t, err, "--validate=false", "error message was not scrubbed") + } else { + require.NoError(t, err, "Got error message when no error should have occurred") } + assert.Len(t, infos, tt.count, "expected %d result objects, got %d", tt.count, len(infos)) }) } } @@ -661,15 +655,12 @@ func TestBuildTable(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Test for an invalid manifest infos, err := c.BuildTable(tt.reader, false) - if err != nil && !tt.err { - t.Errorf("Got error message when no error should have occurred: %v", err) - } else if err != nil && strings.Contains(err.Error(), "--validate=false") { - t.Error("error message was not scrubbed") - } - - if len(infos) != tt.count { - t.Errorf("expected %d result objects, got %d", tt.count, len(infos)) + if tt.err { + require.ErrorContains(t, err, "--validate=false", "error message was not scrubbed") + } else { + require.NoError(t, err, "Got error message when no error should have occurred") } + assert.Len(t, infos, tt.count, "expected %d result objects, got %d", tt.count, len(infos)) }) } } @@ -705,21 +696,17 @@ func TestPerform(t *testing.T) { c := newTestClient(t) infos, err := c.Build(tt.reader, false) - if err != nil && err.Error() != tt.errMessage { - t.Errorf("Error while building manifests: %v", err) + if err != nil { + require.EqualErrorf(t, err, tt.errMessage, "Error while building manifests") } err = perform(infos, fn) - if (err != nil) != tt.err { - t.Errorf("expected error: %v, got %v", tt.err, err) - } - if err != nil && err.Error() != tt.errMessage { - t.Errorf("expected error message: %v, got %v", tt.errMessage, err) - } - - if len(results) != tt.count { - t.Errorf("expected %d result objects, got %d", tt.count, len(results)) + if tt.err { + require.EqualError(t, err, tt.errMessage) + } else { + require.NoError(t, err) } + assert.Len(t, results, tt.count, "expected %d result objects, got %d", tt.count, len(results)) }) } } @@ -771,9 +758,7 @@ func TestWait(t *testing.T) { return newResponse(http.StatusOK, pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) now := time.Now() created = &now return newResponse(http.StatusOK, resources[0].Object) @@ -785,32 +770,18 @@ func TestWait(t *testing.T) { } var err error c.Waiter, err = c.GetWaiterWithOptions(LegacyStrategy) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resources, err := c.Build(objBody(&podList), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result, err := c.Create( resources, ClientCreateOptionServerSideApply(false, false)) - if err != nil { - t.Fatal(err) - } - if len(result.Created) != 3 { - t.Errorf("expected 3 resource created, got %d", len(result.Created)) - } - - if err := c.Wait(resources, time.Second*30); err != nil { - t.Errorf("expected wait without error, got %s", err) - } - - if time.Since(*created) < time.Second*5 { - t.Errorf("expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) - } + require.NoError(t, err) + assert.Len(t, result.Created, 3, "expected 3 resource created, got %d", len(result.Created)) + require.NoErrorf(t, c.Wait(resources, time.Second*30), "expected wait without error") + assert.GreaterOrEqualf(t, time.Since(*created), time.Second*5, "expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) } func TestWaitJob(t *testing.T) { @@ -832,9 +803,7 @@ func TestWaitJob(t *testing.T) { return newResponse(http.StatusOK, job) case p == "/namespaces/default/jobs" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) now := time.Now() created = &now return newResponse(http.StatusOK, resources[0].Object) @@ -846,31 +815,17 @@ func TestWaitJob(t *testing.T) { } var err error c.Waiter, err = c.GetWaiterWithOptions(LegacyStrategy) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resources, err := c.Build(objBody(job), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result, err := c.Create( resources, ClientCreateOptionServerSideApply(false, false)) - if err != nil { - t.Fatal(err) - } - if len(result.Created) != 1 { - t.Errorf("expected 1 resource created, got %d", len(result.Created)) - } - - if err := c.WaitWithJobs(resources, time.Second*30); err != nil { - t.Errorf("expected wait without error, got %s", err) - } - - if time.Since(*created) < time.Second*5 { - t.Errorf("expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) - } + require.NoError(t, err) + assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) + require.NoErrorf(t, c.WaitWithJobs(resources, time.Second*30), "expected wait without error") + assert.GreaterOrEqualf(t, time.Since(*created), time.Second*5, "expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*created)) } func TestWaitDelete(t *testing.T) { @@ -896,9 +851,7 @@ func TestWaitDelete(t *testing.T) { return newResponse(http.StatusOK, &pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -908,73 +861,46 @@ func TestWaitDelete(t *testing.T) { } var err error c.Waiter, err = c.GetWaiterWithOptions(LegacyStrategy) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resources, err := c.Build(objBody(&pod), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) result, err := c.Create( resources, ClientCreateOptionServerSideApply(false, false)) - if err != nil { - t.Fatal(err) - } - if len(result.Created) != 1 { - t.Errorf("expected 1 resource created, got %d", len(result.Created)) - } - if _, err := c.Delete(resources, metav1.DeletePropagationBackground); err != nil { - t.Fatal(err) - } - - if err := c.WaitForDelete(resources, time.Second*30); err != nil { - t.Errorf("expected wait without error, got %s", err) - } - - if time.Since(*deleted) < time.Second*5 { - t.Errorf("expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*deleted)) - } + require.NoError(t, err) + assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) + _, errs := c.Delete(resources, metav1.DeletePropagationBackground) + require.Nil(t, errs) + require.NoErrorf(t, c.WaitForDelete(resources, time.Second*30), "expected wait without error") + assert.GreaterOrEqualf(t, time.Since(*deleted), time.Second*5, "expected to wait at least 5 seconds before ready status was detected, but got %s", time.Since(*deleted)) } func TestReal(t *testing.T) { t.Skip("This is a live test, comment this line to run") c := New(nil) resources, err := c.Build(strings.NewReader(guestbookManifest), false) - if err != nil { - t.Fatal(err) - } - if _, err := c.Create(resources); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + _, err = c.Create(resources) + require.NoError(t, err) testSvcEndpointManifest := testServiceManifest + "\n---\n" + testEndpointManifest c = New(nil) resources, err = c.Build(strings.NewReader(testSvcEndpointManifest), false) - if err != nil { - t.Fatal(err) - } - if _, err := c.Create(resources); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + _, err = c.Create(resources) + require.NoError(t, err) resources, err = c.Build(strings.NewReader(testEndpointManifest), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, errs := c.Delete(resources, metav1.DeletePropagationBackground); errs != nil { - t.Fatal(errs) - } + _, errs := c.Delete(resources, metav1.DeletePropagationBackground) + require.Nil(t, errs) resources, err = c.Build(strings.NewReader(testSvcEndpointManifest), false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // ensures that delete does not fail if a resource is not found - if _, errs := c.Delete(resources, metav1.DeletePropagationBackground); errs != nil { - t.Fatal(errs) - } + _, errs = c.Delete(resources, metav1.DeletePropagationBackground) + require.Nil(t, errs) } func TestGetPodList(t *testing.T) { @@ -1004,10 +930,9 @@ func TestOutputContainerLogsForPodList(t *testing.T) { c := Client{Namespace: namespace, kubeClient: kubeClient} outBuffer := &bytes.Buffer{} outBufferFunc := func(_, _, _ string) io.Writer { return outBuffer } - err := c.OutputContainerLogsForPodList(&somePodList, namespace, outBufferFunc) clientAssertions := assert.New(t) req := require.New(t) - req.NoError(err) + req.NoError(c.OutputContainerLogsForPodList(&somePodList, namespace, outBufferFunc)) clientAssertions.Equal("fake logsfake logsfake logs", outBuffer.String()) } @@ -1247,23 +1172,11 @@ func (c createPatchTestCase) run(t *testing.T) { } patch, patchType, err := createPatch(c.original, targetInfo, c.threeWayMergeForUnstructured) - if err != nil { - t.Fatalf("Failed to create patch: %v", err) - } + require.NoError(t, err, "Failed to create patch") - if c.expectedPatch != string(patch) { - t.Errorf("Unexpected patch.\nTarget:\n%s\nOriginal:\n%s\nActual:\n%s\n\nExpected:\n%s\nGot:\n%s", - c.target, - c.original, - c.actual, - c.expectedPatch, - string(patch), - ) - } + assert.Equal(t, c.expectedPatch, string(patch), "Unexpected patch.\nTarget:\n%s\nOriginal:\n%s\nActual:\n%s\n\nExpected:\n%s\nGot:\n%s", c.target, c.original, c.actual, c.expectedPatch, string(patch)) - if patchType != types.MergePatchType { - t.Errorf("Expected patch type %s, got %s", types.MergePatchType, patchType) - } + assert.Equal(t, types.MergePatchType, patchType, "Expected patch type %s, got %s", types.MergePatchType, patchType) } func newTestCustomResourceData(metadata map[string]string, spec map[string]any) *unstructured.Unstructured { @@ -1438,12 +1351,8 @@ func TestIsReachableTwiceAfterClientCreationFailure(t *testing.T) { assertReachableErr := func(label string, err error) { t.Helper() - if err == nil { - t.Fatalf("%s: expected error, got nil", label) - } - if !errors.Is(err, refusedErr) { - t.Fatalf("%s: expected error wrapping %v, got %v", label, refusedErr, err) - } + require.Error(t, err, "%s: expected error, got nil", label) + require.ErrorIs(t, err, refusedErr) } assertReachableErr("first call", client.IsReachable()) @@ -1472,9 +1381,7 @@ func TestIsIncompatibleServerError(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - if got := isIncompatibleServerError(tc.Err); got != tc.Want { - t.Errorf("isIncompatibleServerError() = %v, want %v", got, tc.Want) - } + assert.Equalf(t, tc.Want, isIncompatibleServerError(tc.Err), "isIncompatibleServerError()") }) } } @@ -1926,9 +1833,7 @@ func TestClientWaitContextCancellationLegacy(t *testing.T) { return newResponse(http.StatusOK, pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Logf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -1949,10 +1854,7 @@ func TestClientWaitContextCancellationLegacy(t *testing.T) { ClientCreateOptionServerSideApply(false, false)) require.NoError(t, err) assert.Len(t, result.Created, 2, "expected 2 resources created, got %d", len(result.Created)) - - err = c.Wait(resources, time.Second*30) - require.Error(t, err) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.Wait(resources, time.Second*30), "context canceled") } func TestClientWaitWithJobsContextCancellationLegacy(t *testing.T) { @@ -1981,9 +1883,7 @@ func TestClientWaitWithJobsContextCancellationLegacy(t *testing.T) { return newResponse(http.StatusOK, job) case p == "/namespaces/default/jobs" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Logf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -2004,9 +1904,7 @@ func TestClientWaitWithJobsContextCancellationLegacy(t *testing.T) { ClientCreateOptionServerSideApply(false, false)) require.NoError(t, err) assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - - err = c.WaitWithJobs(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.WaitWithJobs(resources, time.Second*30), "context canceled", "expected context canceled error") } func TestClientWaitForDeleteContextCancellationLegacy(t *testing.T) { @@ -2041,9 +1939,7 @@ func TestClientWaitForDeleteContextCancellationLegacy(t *testing.T) { return newResponse(http.StatusOK, &pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Logf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -2065,12 +1961,9 @@ func TestClientWaitForDeleteContextCancellationLegacy(t *testing.T) { require.NoError(t, err) assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - if _, err := c.Delete(resources, metav1.DeletePropagationBackground); err != nil { - t.Fatal(err) - } - - err = c.WaitForDelete(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + _, errs := c.Delete(resources, metav1.DeletePropagationBackground) + require.Nil(t, errs) + assert.ErrorContains(t, c.WaitForDelete(resources, time.Second*30), "context canceled", "expected context canceled error") } func TestClientWaitContextNilDoesNotPanic(t *testing.T) { @@ -2100,9 +1993,7 @@ func TestClientWaitContextNilDoesNotPanic(t *testing.T) { return newResponse(http.StatusOK, pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) now := time.Now() created = &now return newResponse(http.StatusOK, resources[0].Object) @@ -2125,10 +2016,7 @@ func TestClientWaitContextNilDoesNotPanic(t *testing.T) { ClientCreateOptionServerSideApply(false, false)) require.NoError(t, err) assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - - err = c.Wait(resources, time.Second*30) - require.NoError(t, err) - + require.NoError(t, c.Wait(resources, time.Second*30)) assert.GreaterOrEqual(t, time.Since(*created), time.Second*2, "expected to wait at least 2 seconds") } @@ -2152,9 +2040,7 @@ func TestClientWaitContextPreCancelledLegacy(t *testing.T) { return newResponse(http.StatusOK, pod) case p == "/namespaces/default/pods" && m == http.MethodPost: resources, err := c.Build(req.Body, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return newResponse(http.StatusOK, resources[0].Object) default: t.Fatalf("unexpected request: %s %s", req.Method, req.URL.Path) @@ -2175,9 +2061,7 @@ func TestClientWaitContextPreCancelledLegacy(t *testing.T) { ClientCreateOptionServerSideApply(false, false)) require.NoError(t, err) assert.Len(t, result.Created, 1, "expected 1 resource created, got %d", len(result.Created)) - - err = c.Wait(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.Wait(resources, time.Second*30), "context canceled") } func TestClientWaitContextCancellationStatusWatcher(t *testing.T) { @@ -2202,8 +2086,7 @@ metadata: cancel() - err = c.Wait(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.Wait(resources, time.Second*30), "context canceled", "expected context canceled error") } func TestClientWaitWithJobsContextCancellationStatusWatcher(t *testing.T) { @@ -2228,8 +2111,7 @@ metadata: cancel() - err = c.WaitWithJobs(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.WaitWithJobs(resources, time.Second*30), "context canceled") } func TestClientWaitForDeleteContextCancellationStatusWatcher(t *testing.T) { @@ -2259,8 +2141,7 @@ status: cancel() - err = c.WaitForDelete(resources, time.Second*30) - assert.ErrorContains(t, err, "context canceled", "expected context canceled error, got: %v", err) + assert.ErrorContains(t, c.WaitForDelete(resources, time.Second*30), "context canceled") } // testStatusReader is a custom status reader for testing that returns a configurable status. @@ -2334,8 +2215,7 @@ metadata: // The pod has no Ready condition, but our custom reader returns CurrentStatus, // so the wait should succeed immediately without timeout. - err = c.Wait(resources, time.Second*3) - require.NoError(t, err) + require.NoError(t, c.Wait(resources, time.Second*3)) } func TestClientStatusReadersWithWaitWithJobs(t *testing.T) { @@ -2376,8 +2256,7 @@ metadata: // The job has no Complete condition, but our custom reader returns CurrentStatus, // so the wait should succeed immediately without timeout. - err = c.WaitWithJobs(resources, time.Second*3) - require.NoError(t, err) + require.NoError(t, c.WaitWithJobs(resources, time.Second*3)) } func createManifest(t *testing.T, manifest string, @@ -2385,12 +2264,10 @@ func createManifest(t *testing.T, manifest string, t.Helper() m := make(map[string]any) - err := yaml.Unmarshal([]byte(manifest), &m) - require.NoError(t, err) + require.NoError(t, yaml.Unmarshal([]byte(manifest), &m)) obj := &unstructured.Unstructured{Object: m} gvk := obj.GroupVersionKind() mapping, err := fakeMapper.RESTMapping(gvk.GroupKind(), gvk.Version) require.NoError(t, err) - err = fakeClient.Tracker().Create(mapping.Resource, obj, obj.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(mapping.Resource, obj, obj.GetNamespace())) } diff --git a/pkg/kube/options.go b/pkg/kube/options.go index 3326c284b..7853cb63a 100644 --- a/pkg/kube/options.go +++ b/pkg/kube/options.go @@ -72,11 +72,34 @@ func WithKStatusReaders(readers ...engine.StatusReader) WaitOption { } } +// WithStatusComputeWorkers sets the number of concurrent goroutines used to +// compute object status per informer. This prevents the informer notification +// pipeline from being blocked by slow API calls (e.g., LIST ReplicaSets/Pods +// for Deployments) when many resources are updated simultaneously. +// +// A value of 0 (the default) keeps the underlying cli-utils behavior, where +// status is computed synchronously on the informer goroutine. Negative values +// are clamped to 0 so callers cannot propagate invalid counts to the +// underlying watcher. SDK consumers (for example helm-controller) inherit +// this conservative default and can opt in explicitly. The Helm CLI passes +// a non-zero value so that `helm install/upgrade/rollback` users get the +// fix for multi-minute waits out of the box. +// See https://github.com/fluxcd/cli-utils/pull/20. +func WithStatusComputeWorkers(n int) WaitOption { + return func(wo *waitOptions) { + if n < 0 { + n = 0 + } + wo.statusComputeWorkers = n + } +} + type waitOptions struct { - ctx context.Context - watchUntilReadyCtx context.Context - waitCtx context.Context - waitWithJobsCtx context.Context - waitForDeleteCtx context.Context - statusReaders []engine.StatusReader + ctx context.Context + watchUntilReadyCtx context.Context + waitCtx context.Context + waitWithJobsCtx context.Context + waitForDeleteCtx context.Context + statusReaders []engine.StatusReader + statusComputeWorkers int } diff --git a/pkg/kube/ready_test.go b/pkg/kube/ready_test.go index fc3ac9409..c40ad1d4d 100644 --- a/pkg/kube/ready_test.go +++ b/pkg/kube/ready_test.go @@ -19,6 +19,8 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" @@ -90,18 +92,15 @@ func Test_ReadyChecker_IsReady_Pod(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.CoreV1().Pods(defaultNamespace).Create(t.Context(), tt.pod, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Pod error: %v", err) - return - } + _, err := c.client.CoreV1().Pods(defaultNamespace).Create(t.Context(), tt.pod, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create Pod error") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -162,17 +161,16 @@ func Test_ReadyChecker_IsReady_Job(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.BatchV1().Jobs(defaultNamespace).Create(t.Context(), tt.job, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Job error: %v", err) - return - } + _, err := c.client.BatchV1().Jobs(defaultNamespace).Create(t.Context(), tt.job, metav1.CreateOptions{}) + + require.NoError(t, err, "Failed to create Job") got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -236,21 +234,19 @@ func Test_ReadyChecker_IsReady_Deployment(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.AppsV1().Deployments(defaultNamespace).Create(t.Context(), tt.deployment, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Deployment error: %v", err) - return - } - if _, err := c.client.AppsV1().ReplicaSets(defaultNamespace).Create(t.Context(), tt.replicaSet, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create ReplicaSet error: %v", err) - return - } + _, err := c.client.AppsV1().Deployments(defaultNamespace).Create(t.Context(), tt.deployment, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create Deployment") + + _, err = c.client.AppsV1().ReplicaSets(defaultNamespace).Create(t.Context(), tt.replicaSet, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create ReplicaSet") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -311,17 +307,16 @@ func Test_ReadyChecker_IsReady_PersistentVolumeClaim(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.CoreV1().PersistentVolumeClaims(defaultNamespace).Create(t.Context(), tt.pvc, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create PersistentVolumeClaim error: %v", err) - return - } + _, err := c.client.CoreV1().PersistentVolumeClaims(defaultNamespace).Create(t.Context(), tt.pvc, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create PersistentVolumeClaim") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -382,17 +377,16 @@ func Test_ReadyChecker_IsReady_Service(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.CoreV1().Services(defaultNamespace).Create(t.Context(), tt.svc, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Service error: %v", err) - return - } + _, err := c.client.CoreV1().Services(defaultNamespace).Create(t.Context(), tt.svc, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create Service") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -453,17 +447,16 @@ func Test_ReadyChecker_IsReady_DaemonSet(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.AppsV1().DaemonSets(defaultNamespace).Create(t.Context(), tt.ds, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create DaemonSet error: %v", err) - return - } + _, err := c.client.AppsV1().DaemonSets(defaultNamespace).Create(t.Context(), tt.ds, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create DaemonSet") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -524,17 +517,16 @@ func Test_ReadyChecker_IsReady_StatefulSet(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.AppsV1().StatefulSets(defaultNamespace).Create(t.Context(), tt.ss, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create StatefulSet error: %v", err) - return - } + _, err := c.client.AppsV1().StatefulSets(defaultNamespace).Create(t.Context(), tt.ss, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create StatefulSet") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -610,17 +602,16 @@ func Test_ReadyChecker_IsReady_ReplicationController(t *testing.T) { checkJobs: tt.fields.checkJobs, pausedAsReady: tt.fields.pausedAsReady, } - if _, err := c.client.CoreV1().ReplicationControllers(defaultNamespace).Create(t.Context(), tt.rc, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create ReplicationController error: %v", err) - return - } + _, err := c.client.CoreV1().ReplicationControllers(defaultNamespace).Create(t.Context(), tt.rc, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create ReplicationController") + got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -683,12 +674,12 @@ func Test_ReadyChecker_IsReady_ReplicaSet(t *testing.T) { } // got, err := c.IsReady(tt.args.ctx, tt.args.resource) - if (err != nil) != tt.wantErr { - t.Errorf("IsReady() error = %v, wantErr %v", err, tt.wantErr) - } - if got != tt.want { - t.Errorf("IsReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "IsReady()") + } else { + require.NoError(t, err, "IsReady()") } + assert.Equal(t, tt.want, got, "IsReady() = %v, want %v", got, tt.want) }) } } @@ -755,9 +746,8 @@ func Test_ReadyChecker_deploymentReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.deploymentReady(tt.args.rs, tt.args.dep); got != tt.want { - t.Errorf("deploymentReady() = %v, want %v", got, tt.want) - } + got := c.deploymentReady(tt.args.rs, tt.args.dep) + assert.Equalf(t, tt.want, got, "deploymentReady() = %v, want %v", got, tt.want) }) } } @@ -789,9 +779,8 @@ func Test_ReadyChecker_replicaSetReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.replicaSetReady(tt.args.rs); got != tt.want { - t.Errorf("replicaSetReady() = %v, want %v", got, tt.want) - } + got := c.replicaSetReady(tt.args.rs) + assert.Equalf(t, tt.want, got, "replicaSetReady() = %v, want %v", got, tt.want) }) } } @@ -823,9 +812,8 @@ func Test_ReadyChecker_replicationControllerReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.replicationControllerReady(tt.args.rc); got != tt.want { - t.Errorf("replicationControllerReady() = %v, want %v", got, tt.want) - } + got := c.replicationControllerReady(tt.args.rc) + assert.Equalf(t, tt.want, got, "replicationControllerReady() = %v, want %v", got, tt.want) }) } } @@ -878,9 +866,8 @@ func Test_ReadyChecker_daemonSetReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.daemonSetReady(tt.args.ds); got != tt.want { - t.Errorf("daemonSetReady() = %v, want %v", got, tt.want) - } + got := c.daemonSetReady(tt.args.ds) + assert.Equalf(t, tt.want, got, "daemonSetReady() = %v, want %v", got, tt.want) }) } } @@ -954,9 +941,8 @@ func Test_ReadyChecker_statefulSetReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.statefulSetReady(tt.args.sts); got != tt.want { - t.Errorf("statefulSetReady() = %v, want %v", got, tt.want) - } + got := c.statefulSetReady(tt.args.sts) + assert.Equalf(t, tt.want, got, "statefulSetReady() = %v, want %v", got, tt.want) }) } } @@ -1014,19 +1000,16 @@ func Test_ReadyChecker_podsReadyForObject(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) for _, pod := range tt.existPods { - if _, err := c.client.CoreV1().Pods(defaultNamespace).Create(t.Context(), &pod, metav1.CreateOptions{}); err != nil { - t.Errorf("Failed to create Pod error: %v", err) - return - } + _, err := c.client.CoreV1().Pods(defaultNamespace).Create(t.Context(), &pod, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create Pod error") } got, err := c.podsReadyForObject(t.Context(), tt.args.namespace, tt.args.obj) - if (err != nil) != tt.wantErr { - t.Errorf("podsReadyForObject() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("podsReadyForObject() got = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "podsReadyForObject()") + } else { + require.NoError(t, err, "podsReadyForObject()") } + assert.Equal(t, tt.want, got, "podsReadyForObject() got = %v, want %v", got, tt.want) }) } } @@ -1093,13 +1076,12 @@ func Test_ReadyChecker_jobReady(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) got, err := c.jobReady(tt.args.job) - if (err != nil) != tt.wantErr { - t.Errorf("jobReady() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("jobReady() = %v, want %v", got, tt.want) + if tt.wantErr { + require.Error(t, err, "jobReady()") + } else { + require.NoError(t, err, "jobReady()") } + assert.Equal(t, tt.want, got, "jobReady() = %v, want %v", got, tt.want) }) } } @@ -1131,9 +1113,8 @@ func Test_ReadyChecker_volumeReady(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) - if got := c.volumeReady(tt.args.v); got != tt.want { - t.Errorf("volumeReady() = %v, want %v", got, tt.want) - } + got := c.volumeReady(tt.args.v) + assert.Equalf(t, tt.want, got, "volumeReady() = %v, want %v", got, tt.want) }) } } @@ -1177,9 +1158,7 @@ func Test_ReadyChecker_serviceReady(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) got := c.serviceReady(tt.args.service) - if got != tt.want { - t.Errorf("serviceReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, got, "serviceReady() = %v, want %v", got, tt.want) }) } } @@ -1246,9 +1225,7 @@ func Test_ReadyChecker_crdBetaReady(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) got := c.crdBetaReady(tt.args.crdBeta) - if got != tt.want { - t.Errorf("crdBetaReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, got, "crdBetaReady() = %v, want %v", got, tt.want) }) } } @@ -1315,9 +1292,7 @@ func Test_ReadyChecker_crdReady(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := NewReadyChecker(fake.NewClientset()) got := c.crdReady(tt.args.crdBeta) - if got != tt.want { - t.Errorf("crdBetaReady() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.want, got, "crdBetaReady() = %v, want %v", got, tt.want) }) } } diff --git a/pkg/kube/resource_test.go b/pkg/kube/resource_test.go index 283b44945..8bc644833 100644 --- a/pkg/kube/resource_test.go +++ b/pkg/kube/resource_test.go @@ -19,6 +19,8 @@ package kube import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/resource" @@ -37,27 +39,15 @@ func TestResourceList(t *testing.T) { r1 = []*resource.Info{info("foo"), info("bar")} r2 = []*resource.Info{info("bar")} - if r1.Get(info("bar")).Mapping.Resource.Resource != "pod" { - t.Error("expected get pod") - } + assert.Equal(t, "pod", r1.Get(info("bar")).Mapping.Resource.Resource, "expected get pod") diff := r1.Difference(r2) - if len(diff) != 1 { - t.Error("expected 1 result") - } - - if !diff.Contains(info("foo")) { - t.Error("expected diff to return foo") - } + require.Len(t, diff, 1, "expected 1 result") + assert.Contains(t, diff, info("foo"), "expected diff to return foo") inter := r1.Intersect(r2) - if len(inter) != 1 { - t.Error("expected 1 result") - } - - if !inter.Contains(info("bar")) { - t.Error("expected intersect to return bar") - } + require.Len(t, inter, 1, "expected 1 result") + assert.Contains(t, inter, info("bar"), "expected intersect to return bar") } func TestIsMatchingInfo(t *testing.T) { @@ -66,35 +56,23 @@ func TestIsMatchingInfo(t *testing.T) { gvkDiffGroup := schema.GroupVersionKind{Group: "diff", Version: "version1", Kind: "pod"} resourceInfoDiffGroup := resource.Info{Name: "name1", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvkDiffGroup}} - if isMatchingInfo(&resourceInfo, &resourceInfoDiffGroup) { - t.Error("expected resources not equal") - } + assert.False(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffGroup), "expected resources not equal") gvkDiffVersion := schema.GroupVersionKind{Group: "group1", Version: "diff", Kind: "pod"} resourceInfoDiffVersion := resource.Info{Name: "name1", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvkDiffVersion}} - if !isMatchingInfo(&resourceInfo, &resourceInfoDiffVersion) { - t.Error("expected resources with different versions but same group and kind to be equal") - } + assert.True(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffVersion), "expected resources with different versions but same group and kind to be equal") gvkDiffKind := schema.GroupVersionKind{Group: "group1", Version: "version1", Kind: "deployment"} resourceInfoDiffKind := resource.Info{Name: "name1", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvkDiffKind}} - if isMatchingInfo(&resourceInfo, &resourceInfoDiffKind) { - t.Error("expected resources not equal") - } + assert.False(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffKind), "expected resources not equal") resourceInfoDiffName := resource.Info{Name: "diff", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvk}} - if isMatchingInfo(&resourceInfo, &resourceInfoDiffName) { - t.Error("expected resources not equal") - } + assert.False(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffName), "expected resources not equal") resourceInfoDiffNamespace := resource.Info{Name: "name1", Namespace: "diff", Mapping: &meta.RESTMapping{GroupVersionKind: gvk}} - if isMatchingInfo(&resourceInfo, &resourceInfoDiffNamespace) { - t.Error("expected resources not equal") - } + assert.False(t, isMatchingInfo(&resourceInfo, &resourceInfoDiffNamespace), "expected resources not equal") gvkEqual := schema.GroupVersionKind{Group: "group1", Version: "version1", Kind: "pod"} resourceInfoEqual := resource.Info{Name: "name1", Namespace: "namespace1", Mapping: &meta.RESTMapping{GroupVersionKind: gvkEqual}} - if !isMatchingInfo(&resourceInfo, &resourceInfoEqual) { - t.Error("expected resources to be equal") - } + assert.True(t, isMatchingInfo(&resourceInfo, &resourceInfoEqual), "expected resources to be equal") } diff --git a/pkg/kube/statuswait.go b/pkg/kube/statuswait.go index 12c3e95a6..91eec30ef 100644 --- a/pkg/kube/statuswait.go +++ b/pkg/kube/statuswait.go @@ -43,14 +43,15 @@ import ( ) type statusWaiter struct { - client dynamic.Interface - restMapper meta.RESTMapper - ctx context.Context - watchUntilReadyCtx context.Context - waitCtx context.Context - waitWithJobsCtx context.Context - waitForDeleteCtx context.Context - readers []engine.StatusReader + client dynamic.Interface + restMapper meta.RESTMapper + ctx context.Context + watchUntilReadyCtx context.Context + waitCtx context.Context + waitWithJobsCtx context.Context + waitForDeleteCtx context.Context + readers []engine.StatusReader + statusComputeWorkers int logging.LogHolder } @@ -82,6 +83,7 @@ func (w *statusWaiter) WatchUntilReady(resourceList ResourceList, timeout time.D defer cancel() w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := getStatusWatcher(w.client, w.restMapper) + sw.StatusComputeWorkers = w.statusComputeWorkers jobSR := helmStatusReaders.NewCustomJobStatusReader(w.restMapper) podSR := helmStatusReaders.NewCustomPodStatusReader(w.restMapper) // We don't want to wait on any other resources as watchUntilReady is only for Helm hooks. @@ -104,6 +106,7 @@ func (w *statusWaiter) Wait(resourceList ResourceList, timeout time.Duration) er defer cancel() w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := getStatusWatcher(w.client, w.restMapper) + sw.StatusComputeWorkers = w.statusComputeWorkers sw.StatusReader = statusreaders.NewStatusReader(w.restMapper, w.readers...) return w.wait(ctx, resourceList, sw) } @@ -116,6 +119,7 @@ func (w *statusWaiter) WaitWithJobs(resourceList ResourceList, timeout time.Dura defer cancel() w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := getStatusWatcher(w.client, w.restMapper) + sw.StatusComputeWorkers = w.statusComputeWorkers newCustomJobStatusReader := helmStatusReaders.NewCustomJobStatusReader(w.restMapper) readers := append([]engine.StatusReader(nil), w.readers...) readers = append(readers, newCustomJobStatusReader) diff --git a/pkg/kube/statuswait_test.go b/pkg/kube/statuswait_test.go index 14f10124c..5f5f5d051 100644 --- a/pkg/kube/statuswait_test.go +++ b/pkg/kube/statuswait_test.go @@ -272,8 +272,7 @@ func getRuntimeObjFromManifests(t *testing.T, manifests []string) []runtime.Obje objects := []runtime.Object{} for _, manifest := range manifests { m := make(map[string]any) - err := yaml.Unmarshal([]byte(manifest), &m) - require.NoError(t, err) + require.NoError(t, yaml.Unmarshal([]byte(manifest), &m)) resource := &unstructured.Unstructured{Object: m} objects = append(objects, resource) } @@ -332,8 +331,7 @@ func TestStatusWaitForDelete(t *testing.T) { for _, objToCreate := range objsToCreate { u := objToCreate.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } objsToDelete := getRuntimeObjFromManifests(t, tt.manifestsToDelete) for _, objToDelete := range objsToDelete { @@ -341,8 +339,7 @@ func TestStatusWaitForDelete(t *testing.T) { gvr := getGVR(t, fakeMapper, u) go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { time.Sleep(timeUntilPodDelete) - err := fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) + assert.NoError(t, fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName())) }(gvr, u) } resourceList := getResourceListFromRuntimeObjs(t, c, objsToCreate) @@ -352,9 +349,9 @@ func TestStatusWaitForDelete(t *testing.T) { for _, expectedErrStr := range tt.expectErrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -375,8 +372,7 @@ func TestStatusWaitForDeleteNonExistentObject(t *testing.T) { // Don't create the object to test that the wait for delete works when the object doesn't exist objManifest := getRuntimeObjFromManifests(t, []string{podCurrentManifest}) resourceList := getResourceListFromRuntimeObjs(t, c, objManifest) - err := statusWaiter.WaitForDelete(resourceList, timeout) - assert.NoError(t, err) + assert.NoError(t, statusWaiter.WaitForDelete(resourceList, timeout)) } func TestStatusWait(t *testing.T) { @@ -433,8 +429,7 @@ func TestStatusWait(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.Wait(resourceList, time.Second*3) @@ -443,9 +438,9 @@ func TestStatusWait(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -490,8 +485,7 @@ func TestWaitForJobComplete(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WaitWithJobs(resourceList, time.Second*3) @@ -500,9 +494,9 @@ func TestWaitForJobComplete(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -553,8 +547,7 @@ func TestWatchForReady(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WatchUntilReady(resourceList, time.Second*3) @@ -563,9 +556,9 @@ func TestWatchForReady(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -657,8 +650,7 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } if strings.Contains(tt.name, "delete") { @@ -668,8 +660,7 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { gvr := getGVR(t, fakeMapper, u) go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { time.Sleep(timeUntilDelete) - err := fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) + assert.NoError(t, fakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName())) }(gvr, u) } } @@ -681,9 +672,9 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -839,8 +830,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } if strings.Contains(tt.name, "delet") { @@ -850,8 +840,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { gvr := getGVR(t, fakeMapper, u) go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { time.Sleep(timeUntilDelete) - err := baseFakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) + assert.NoError(t, baseFakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName())) }(gvr, u) } } @@ -863,10 +852,10 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { for _, expectedErr := range tt.expectErrs { require.ErrorContains(t, err, expectedErr.Error()) } - return + } else { + require.NoError(t, err) + assert.False(t, restrictedConfig.clusterScopedListAttempted) } - require.NoError(t, err) - assert.False(t, restrictedConfig.clusterScopedListAttempted) }) } } @@ -947,8 +936,7 @@ func TestStatusWaitMixedResources(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, baseFakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } if strings.Contains(tt.name, "delet") { @@ -958,8 +946,7 @@ func TestStatusWaitMixedResources(t *testing.T) { gvr := getGVR(t, fakeMapper, u) go func(gvr schema.GroupVersionResource, u *unstructured.Unstructured) { time.Sleep(timeUntilDelete) - err := baseFakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName()) - assert.NoError(t, err) + assert.NoError(t, baseFakeClient.Tracker().Delete(gvr, u.GetNamespace(), u.GetName())) }(gvr, u) } } @@ -971,10 +958,10 @@ func TestStatusWaitMixedResources(t *testing.T) { for _, expectedErr := range tt.expectErrs { require.ErrorContains(t, err, expectedErr.Error()) } - return + } else { + require.NoError(t, err) + assert.False(t, restrictedConfig.clusterScopedListAttempted) } - require.NoError(t, err) - assert.False(t, restrictedConfig.clusterScopedListAttempted) }) } } @@ -1067,8 +1054,7 @@ func TestStatusWaitWithCustomReaders(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.Wait(resourceList, time.Second*3) @@ -1077,9 +1063,9 @@ func TestStatusWaitWithCustomReaders(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -1139,16 +1125,15 @@ func TestStatusWaitWithJobsAndCustomReaders(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WaitWithJobs(resourceList, time.Second*3) if tt.expectErrs != nil { assert.EqualError(t, err, errors.Join(tt.expectErrs...).Error()) - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -1238,8 +1223,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := tt.testFunc(&sw, resourceList, time.Second*3) @@ -1248,9 +1232,9 @@ func TestStatusWaitWithFailedResources(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } @@ -1293,6 +1277,28 @@ func TestWaitOptionFunctions(t *testing.T) { WithWaitForDeleteMethodContext(ctx)(opts) assert.Equal(t, ctx, opts.waitForDeleteCtx) }) + + t.Run("WithStatusComputeWorkers sets statusComputeWorkers", func(t *testing.T) { + t.Parallel() + opts := &waitOptions{} + WithStatusComputeWorkers(8)(opts) + assert.Equal(t, 8, opts.statusComputeWorkers) + }) + + t.Run("WithStatusComputeWorkers clamps negative values to zero", func(t *testing.T) { + t.Parallel() + opts := &waitOptions{} + WithStatusComputeWorkers(-1)(opts) + assert.Equal(t, 0, opts.statusComputeWorkers, + "negative worker counts must not propagate to the underlying watcher") + }) + + t.Run("waitOptions.statusComputeWorkers defaults to zero", func(t *testing.T) { + t.Parallel() + opts := &waitOptions{} + assert.Equal(t, 0, opts.statusComputeWorkers, + "SDK consumers must opt in to concurrent status computation") + }) } func TestMethodSpecificContextCancellation(t *testing.T) { @@ -1321,14 +1327,12 @@ func TestMethodSpecificContextCancellation(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WatchUntilReady(resourceList, time.Second*3) // Should fail due to cancelled method context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WatchUntilReady(resourceList, time.Second*3), "context canceled") }) t.Run("Wait uses method-specific context", func(t *testing.T) { @@ -1354,14 +1358,12 @@ func TestMethodSpecificContextCancellation(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.Wait(resourceList, time.Second*3) // Should fail due to cancelled method context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.Wait(resourceList, time.Second*3), "context canceled") }) t.Run("WaitWithJobs uses method-specific context", func(t *testing.T) { @@ -1387,14 +1389,12 @@ func TestMethodSpecificContextCancellation(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitWithJobs(resourceList, time.Second*3) // Should fail due to cancelled method context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WaitWithJobs(resourceList, time.Second*3), "context canceled") }) t.Run("WaitForDelete uses method-specific context", func(t *testing.T) { @@ -1420,14 +1420,12 @@ func TestMethodSpecificContextCancellation(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitForDelete(resourceList, time.Second*3) // Should fail due to cancelled method context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WaitForDelete(resourceList, time.Second*3), "context canceled") }) } @@ -1457,14 +1455,12 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WatchUntilReady(resourceList, time.Second*3) // Should fail due to cancelled general context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WatchUntilReady(resourceList, time.Second*3), "context canceled") }) t.Run("Wait falls back to general context when method context is nil", func(t *testing.T) { @@ -1490,14 +1486,12 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.Wait(resourceList, time.Second*3) // Should fail due to cancelled general context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.Wait(resourceList, time.Second*3), "context canceled") }) t.Run("WaitWithJobs falls back to general context when method context is nil", func(t *testing.T) { @@ -1523,14 +1517,12 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitWithJobs(resourceList, time.Second*3) // Should fail due to cancelled general context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WaitWithJobs(resourceList, time.Second*3), "context canceled") }) t.Run("WaitForDelete falls back to general context when method context is nil", func(t *testing.T) { @@ -1556,14 +1548,12 @@ func TestMethodContextFallbackToGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitForDelete(resourceList, time.Second*3) // Should fail due to cancelled general context - assert.ErrorContains(t, err, "context canceled") + assert.ErrorContains(t, sw.WaitForDelete(resourceList, time.Second*3), "context canceled") }) } @@ -1593,14 +1583,12 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WatchUntilReady(resourceList, time.Second*3) // Should succeed because method context is used and it's not cancelled - assert.NoError(t, err) + assert.NoError(t, sw.WatchUntilReady(resourceList, time.Second*3)) }) t.Run("method-specific context overrides general context for Wait", func(t *testing.T) { @@ -1626,14 +1614,12 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.Wait(resourceList, time.Second*3) // Should succeed because method context is used and it's not cancelled - assert.NoError(t, err) + assert.NoError(t, sw.Wait(resourceList, time.Second*3)) }) t.Run("method-specific context overrides general context for WaitWithJobs", func(t *testing.T) { @@ -1659,14 +1645,12 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitWithJobs(resourceList, time.Second*3) // Should succeed because method context is used and it's not cancelled - assert.NoError(t, err) + assert.NoError(t, sw.WaitWithJobs(resourceList, time.Second*3)) }) t.Run("method-specific context overrides general context for WaitForDelete", func(t *testing.T) { @@ -1695,9 +1679,8 @@ func TestMethodContextOverridesGeneralContext(t *testing.T) { // immediately cancelled and the call would return a context error. objs := getRuntimeObjFromManifests(t, []string{podCurrentManifest}) resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := sw.WaitForDelete(resourceList, time.Second) // Should succeed because method context is used and it's not cancelled - assert.NoError(t, err) + assert.NoError(t, sw.WaitForDelete(resourceList, time.Second)) }) } @@ -1779,8 +1762,7 @@ func TestWatchUntilReadyWithCustomReaders(t *testing.T) { for _, obj := range objs { u := obj.(*unstructured.Unstructured) gvr := getGVR(t, fakeMapper, u) - err := fakeClient.Tracker().Create(gvr, u, u.GetNamespace()) - require.NoError(t, err) + require.NoError(t, fakeClient.Tracker().Create(gvr, u, u.GetNamespace())) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) err := statusWaiter.WatchUntilReady(resourceList, time.Second*3) @@ -1789,9 +1771,9 @@ func TestWatchUntilReadyWithCustomReaders(t *testing.T) { for _, expectedErrStr := range tt.expectErrStrs { require.ErrorContains(t, err, expectedErrStr) } - return + } else { + assert.NoError(t, err) } - assert.NoError(t, err) }) } } diff --git a/pkg/kube/wait_test.go b/pkg/kube/wait_test.go index acdfffa23..d33a12c87 100644 --- a/pkg/kube/wait_test.go +++ b/pkg/kube/wait_test.go @@ -19,7 +19,6 @@ package kube import ( "errors" "net/http" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -298,17 +297,11 @@ func TestLegacyWaiter_waitForPodSuccess(t *testing.T) { t.Run(tt.name, func(t *testing.T) { done, err := lw.waitForPodSuccess(tt.obj, "foo") if tt.wantErr { - if err == nil { - t.Error("expected error, got none") - } else if !strings.Contains(err.Error(), tt.errMessage) { - t.Errorf("expected error to contain %q, got %q", tt.errMessage, err.Error()) - } - } else if err != nil { - t.Errorf("unexpected error: %v", err) - } - if done != tt.wantDone { - t.Errorf("got done=%v, want %v", done, tt.wantDone) + require.ErrorContains(t, err, tt.errMessage) + } else { + require.NoError(t, err) } + assert.Equal(t, tt.wantDone, done, "got done=%v, want %v", done, tt.wantDone) }) } } @@ -390,17 +383,10 @@ func TestLegacyWaiter_waitForJob(t *testing.T) { t.Run(tt.name, func(t *testing.T) { done, err := lw.waitForJob(tt.obj, "test-job") if tt.wantErr { - if err == nil { - t.Error("expected error, got none") - } else if !strings.Contains(err.Error(), tt.errMessage) { - t.Errorf("expected error to contain %q, got %q", tt.errMessage, err.Error()) - } - } else if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if done != tt.wantDone { - t.Errorf("got done=%v, want %v", done, tt.wantDone) + require.ErrorContains(t, err, tt.errMessage) + } else { + require.NoError(t, err) + assert.Equal(t, tt.wantDone, done, "got done=%v, want %v", done, tt.wantDone) } }) } @@ -459,9 +445,7 @@ func TestLegacyWaiter_isRetryableError(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := lw.isRetryableError(tt.err, info) - if got != tt.wantRetry { - t.Errorf("isRetryableError() = %v, want %v", got, tt.wantRetry) - } + assert.Equal(t, tt.wantRetry, got, "isRetryableError() = %v, want %v", got, tt.wantRetry) }) } } diff --git a/pkg/kubeenv/roundtripper_test.go b/pkg/kubeenv/roundtripper_test.go index 6f0caf6f8..8d5b80e39 100644 --- a/pkg/kubeenv/roundtripper_test.go +++ b/pkg/kubeenv/roundtripper_test.go @@ -141,12 +141,11 @@ func TestRetryingRoundTripper_RoundTrip(t *testing.T) { if tt.expectedErr != "" { require.ErrorContains(t, err, tt.expectedErr) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expectedCode, resp.StatusCode) + assert.Equal(t, tt.expectedCalls, fakeRT.calls) } - require.NoError(t, err) - - assert.Equal(t, tt.expectedCode, resp.StatusCode) - assert.Equal(t, tt.expectedCalls, fakeRT.calls) }) } } diff --git a/pkg/provenance/doc.go b/pkg/provenance/doc.go index dd14568d9..bd60bc593 100644 --- a/pkg/provenance/doc.go +++ b/pkg/provenance/doc.go @@ -35,4 +35,4 @@ and using `gpg --verify`, `keybase pgp verify`, or similar: gpg: Signature made Mon Jul 25 17:23:44 2016 MDT using RSA key ID 1FC18762 gpg: Good signature from "Helm Testing (This key should only be used for testing. DO NOT TRUST.) " [ultimate] */ -package provenance // import "helm.sh/helm/v4/pkg/provenance" +package provenance diff --git a/pkg/provenance/sign_test.go b/pkg/provenance/sign_test.go index 3f8e654f9..ec6e6194b 100644 --- a/pkg/provenance/sign_test.go +++ b/pkg/provenance/sign_test.go @@ -89,14 +89,10 @@ func loadChartMetadataForSigning(t *testing.T, chartPath string) []byte { t.Helper() chart, err := loader.LoadFile(chartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) metadataBytes, err := yaml.Marshal(chart.Metadata) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return metadataBytes } @@ -106,170 +102,113 @@ func TestMessageBlock(t *testing.T) { // Read the chart file data archiveData, err := os.ReadFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) out, err := messageBlock(archiveData, filepath.Base(testChartfile), metadataBytes) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) got := out.String() - if got != testMessageBlock { - t.Errorf("Expected:\n%q\nGot\n%q\n", testMessageBlock, got) - } + assert.Equal(t, testMessageBlock, got, "Expected:\n%q\nGot\n%q\n", testMessageBlock, got) } func TestParseMessageBlock(t *testing.T) { sc, err := parseMessageBlock([]byte(testMessageBlock)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // parseMessageBlock only returns checksums, not metadata (like upstream) - if lsc := len(sc.Files); lsc != 1 { - t.Errorf("Expected 1 file, got %d", lsc) - } + lsc := len(sc.Files) + assert.Equalf(t, 1, lsc, "Expected 1 file, got %d", lsc) - if hash, ok := sc.Files["hashtest-1.2.3.tgz"]; !ok { - t.Error("hashtest file not found in Files") - } else if hash != "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888" { - t.Errorf("Unexpected hash: %q", hash) - } + hash, ok := sc.Files["hashtest-1.2.3.tgz"] + assert.True(t, ok, "hashtest file not found in Files") + assert.Equalf(t, "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888", hash, "Unexpected hash: %q", hash) } func TestLoadKey(t *testing.T) { k, err := loadKey(testKeyfile) - if err != nil { - t.Fatal(err) - } - - if _, ok := k.Identities[testKeyName]; !ok { - t.Errorf("Expected to load a key for user %q", testKeyName) - } + require.NoError(t, err) + assert.Containsf(t, k.Identities, testKeyName, "Expected to load a key for user %q", testKeyName) } func TestLoadKeyRing(t *testing.T) { k, err := loadKeyRing(testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if len(k) > 1 { - t.Errorf("Expected 1, got %d", len(k)) - } + assert.LessOrEqualf(t, len(k), 1, "Expected 1, got %d", len(k)) for _, e := range k { - if ii, ok := e.Identities[testKeyName]; !ok { - t.Errorf("Expected %s in %v", testKeyName, ii) - } + ii, ok := e.Identities[testKeyName] + assert.Truef(t, ok, "Expected %s in %v", testKeyName, ii) } } func TestDigest(t *testing.T) { f, err := os.Open(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer f.Close() hash, err := Digest(f) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := readSumFile(testSumfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !strings.Contains(sig, hash) { - t.Errorf("Expected %s to be in %s", hash, sig) - } + assert.Contains(t, sig, hash, "Expected %s to be in %s", hash, sig) } func TestNewFromFiles(t *testing.T) { s, err := NewFromFiles(testKeyfile, testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := s.Entity.Identities[testKeyName]; !ok { - t.Errorf("Expected to load a key for user %q", testKeyName) - } + assert.Containsf(t, s.Entity.Identities, testKeyName, "Expected to load a key for user %q", testKeyName) } func TestDigestFile(t *testing.T) { hash, err := DigestFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := readSumFile(testSumfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !strings.Contains(sig, hash) { - t.Errorf("Expected %s to be in %s", hash, sig) - } + assert.Contains(t, sig, hash, "Expected %s to be in %s", hash, sig) } func TestDecryptKey(t *testing.T) { k, err := NewFromKeyring(testPasswordKeyfile, testPasswordKeyName) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if !k.Entity.PrivateKey.Encrypted { - t.Fatal("Key is not encrypted") - } + require.True(t, k.Entity.PrivateKey.Encrypted, "Key is not encrypted") // We give this a simple callback that returns the password. - if err := k.DecryptKey(func(_ string) ([]byte, error) { + require.NoError(t, k.DecryptKey(func(_ string) ([]byte, error) { return []byte("secret"), nil - }); err != nil { - t.Fatal(err) - } + })) // Re-read the key (since we already unlocked it) k, err = NewFromKeyring(testPasswordKeyfile, testPasswordKeyName) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Now we give it a bogus password. - if err := k.DecryptKey(func(_ string) ([]byte, error) { + require.Error(t, k.DecryptKey(func(_ string) ([]byte, error) { return []byte("secrets_and_lies"), nil - }); err == nil { - t.Fatal("Expected an error when giving a bogus passphrase") - } + }), "Expected an error when giving a bogus passphrase") } func TestClearSign(t *testing.T) { signer, err := NewFromFiles(testKeyfile, testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) metadataBytes := loadChartMetadataForSigning(t, testChartfile) // Read the chart file data archiveData, err := os.ReadFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := signer.ClearSign(archiveData, filepath.Base(testChartfile), metadataBytes) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) t.Logf("Sig:\n%s", sig) - if !strings.Contains(sig, testMessageBlock) { - t.Errorf("expected message block to be in sig: %s", sig) - } + assert.Contains(t, sig, testMessageBlock, "expected message block to be in sig: %s", sig) } func TestMixedKeyringRSASigningAndVerification(t *testing.T) { @@ -298,7 +237,6 @@ func TestMixedKeyringRSASigningAndVerification(t *testing.T) { } assert.True(t, hasEdDSA, "expected %s to include an Ed25519 public key", testMixedKeyring) - require.NotNil(t, signer.Entity, "expected signer entity to be loaded") require.NotNil(t, signer.Entity.PrivateKey, "expected signer private key to be loaded") assert.Equal(t, packet.PubKeyAlgoRSA, signer.Entity.PrivateKey.PubKeyAlgo, "expected RSA key") @@ -317,9 +255,7 @@ func TestMixedKeyringRSASigningAndVerification(t *testing.T) { require.NotNil(t, verification.SignedBy, "expected verification to include signer") require.NotNil(t, verification.SignedBy.PrimaryKey, "expected verification to include signer primary key") assert.Equal(t, packet.PubKeyAlgoRSA, verification.SignedBy.PrimaryKey.PubKeyAlgo, "expected verification to report RSA key") - - _, ok := verification.SignedBy.Identities[testKeyName] - assert.True(t, ok, "expected verification to be signed by %q", testKeyName) + assert.Contains(t, verification.SignedBy.Identities, testKeyName, "expected verification to be signed by %q", testKeyName) } // failSigner always fails to sign and returns an error @@ -335,9 +271,7 @@ func (s failSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) ([]byte, er func TestClearSignError(t *testing.T) { signer, err := NewFromFiles(testKeyfile, testPubfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // ensure that signing always fails signer.Entity.PrivateKey.PrivateKey = failSigner{} @@ -346,18 +280,11 @@ func TestClearSignError(t *testing.T) { // Read the chart file data archiveData, err := os.ReadFile(testChartfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) sig, err := signer.ClearSign(archiveData, filepath.Base(testChartfile), metadataBytes) - if err == nil { - t.Fatal("didn't get an error from ClearSign but expected one") - } - - if sig != "" { - t.Fatalf("expected an empty signature after failed ClearSign but got %q", sig) - } + require.Error(t, err, "didn't get an error from ClearSign but expected one") + assert.Empty(t, sig, "expected an empty signature after failed ClearSign but got %q", sig) } func TestVerify(t *testing.T) { @@ -385,11 +312,9 @@ func TestVerify(t *testing.T) { _, err = signer.Verify(archiveData, tamperedSigData, filepath.Base(testChartfile)) require.Errorf(t, err, "Expected %s to fail.", testTamperedSigBlock) - switch err.(type) { - case pgperrors.SignatureError: - t.Logf("Tampered sig block error: %s (%T)", err, err) - default: - t.Errorf("Expected invalid signature error, got %q (%T)", err, err) + var sErr pgperrors.SignatureError + if assert.ErrorAs(t, err, &sErr, "Expected invalid signature error") { + t.Logf("Tampered sig block error: %s (%T)", sErr, sErr) } } diff --git a/pkg/pusher/ocipusher_test.go b/pkg/pusher/ocipusher_test.go index a4542500a..b63077293 100644 --- a/pkg/pusher/ocipusher_test.go +++ b/pkg/pusher/ocipusher_test.go @@ -21,9 +21,9 @@ import ( "io" "os" "path/filepath" - "strings" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/registry" @@ -31,13 +31,9 @@ import ( func TestNewOCIPusher(t *testing.T) { p, err := NewOCIPusher() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, ok := p.(*OCIPusher); !ok { - t.Fatal("Expected NewOCIPusher to produce an *OCIPusher") - } + require.IsType(t, &OCIPusher{}, p, "Expected NewOCIPusher to produce an *OCIPusher") cd := "../../testdata" join := filepath.Join @@ -51,55 +47,28 @@ func TestNewOCIPusher(t *testing.T) { WithInsecureSkipTLSVerify(insecureSkipTLSVerify), WithPlainHTTP(plainHTTP), ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) op, ok := p.(*OCIPusher) - if !ok { - t.Fatal("Expected NewOCIPusher to produce an *OCIPusher") - } - - if op.opts.certFile != pub { - t.Errorf("Expected NewOCIPusher to contain %q as the public key file, got %q", pub, op.opts.certFile) - } - - if op.opts.keyFile != priv { - t.Errorf("Expected NewOCIPusher to contain %q as the private key file, got %q", priv, op.opts.keyFile) - } - - if op.opts.caFile != ca { - t.Errorf("Expected NewOCIPusher to contain %q as the CA file, got %q", ca, op.opts.caFile) - } - - if op.opts.plainHTTP != plainHTTP { - t.Errorf("Expected NewOCIPusher to have plainHTTP as %t, got %t", plainHTTP, op.opts.plainHTTP) - } - - if op.opts.insecureSkipTLSVerify != insecureSkipTLSVerify { - t.Errorf("Expected NewOCIPusher to have insecureSkipVerifyTLS as %t, got %t", insecureSkipTLSVerify, op.opts.insecureSkipTLSVerify) - } + require.True(t, ok, "Expected NewOCIPusher to produce an *OCIPusher") + assert.Equal(t, pub, op.opts.certFile, "Expected NewOCIPusher to contain %q as the public key file, got %q", pub, op.opts.certFile) + assert.Equal(t, priv, op.opts.keyFile, "Expected NewOCIPusher to contain %q as the private key file, got %q", priv, op.opts.keyFile) + assert.Equal(t, ca, op.opts.caFile, "Expected NewOCIPusher to contain %q as the CA file, got %q", ca, op.opts.caFile) + assert.Equal(t, plainHTTP, op.opts.plainHTTP, "Expected NewOCIPusher to have plainHTTP as %t, got %t", plainHTTP, op.opts.plainHTTP) + assert.Equal(t, insecureSkipTLSVerify, op.opts.insecureSkipTLSVerify, "Expected NewOCIPusher to have insecureSkipVerifyTLS as %t, got %t", insecureSkipTLSVerify, op.opts.insecureSkipTLSVerify) // Test if setting registryClient is being passed to the ops registryClient, err := registry.NewClient() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) p, err = NewOCIPusher( WithRegistryClient(registryClient), ) - if err != nil { - t.Fatal(err) - } - op, ok = p.(*OCIPusher) - if !ok { - t.Fatal("expected NewOCIPusher to produce an *OCIPusher") - } + require.NoError(t, err) - if op.opts.registryClient != registryClient { - t.Errorf("Expected NewOCIPusher to contain %p as RegistryClient, got %p", registryClient, op.opts.registryClient) - } + op, ok = p.(*OCIPusher) + require.True(t, ok, "expected NewOCIPusher to produce an *OCIPusher") + assert.Equal(t, registryClient, op.opts.registryClient, "Expected NewOCIPusher to contain %p as RegistryClient, got %p", registryClient, op.opts.registryClient) } func TestOCIPusher_Push_ErrorHandling(t *testing.T) { @@ -127,23 +96,13 @@ func TestOCIPusher_Push_ErrorHandling(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pusher, err := NewOCIPusher() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) chartRef := tt.chartRef if tt.setupFunc != nil { chartRef = tt.setupFunc() } - - err = pusher.Push(chartRef, "oci://localhost:5000/test") - if err == nil { - t.Fatal("Expected error but got none") - } - - if !strings.Contains(err.Error(), tt.expectedError) { - t.Errorf("Expected error containing %q, got %q", tt.expectedError, err.Error()) - } + assert.ErrorContains(t, pusher.Push(chartRef, "oci://localhost:5000/test"), tt.expectedError) }) } } @@ -227,30 +186,20 @@ func TestOCIPusher_newRegistryClient(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pusher, err := NewOCIPusher(tt.opts...) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) op, ok := pusher.(*OCIPusher) - if !ok { - t.Fatal("Expected *OCIPusher") - } + require.True(t, ok, "Expected *OCIPusher") client, err := op.newRegistryClient() if tt.expectError { - if err == nil { - t.Fatal("Expected error but got none") - } - if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) { - t.Errorf("Expected error containing %q, got %q", tt.errorContains, err.Error()) + require.Error(t, err, "Expected error but got none") + if tt.errorContains != "" { + require.ErrorContains(t, err, tt.errorContains) } } else { - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if client == nil { - t.Fatal("Expected non-nil registry client") - } + require.NoError(t, err) + require.NotNil(t, client, "Expected non-nil registry client") } }) } @@ -287,25 +236,18 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { // Copy a valid chart src, err := os.Open(chartPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer src.Close() dst, err := os.Create(tempChart) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := io.Copy(dst, src); err != nil { - t.Fatal(err) - } + _, err = io.Copy(dst, src) + require.NoError(t, err) dst.Close() // Make the file unreadable - if err := os.Chmod(tempChart, 0o000); err != nil { - t.Fatal(err) - } + require.NoError(t, os.Chmod(tempChart, 0o000)) return tempChart, func() { os.Chmod(tempChart, 0o644) // Restore permissions for cleanup @@ -328,25 +270,18 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { // Copy chart file src, err := os.Open(chartWithProvPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer src.Close() dst, err := os.Create(tempChart) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if _, err := io.Copy(dst, src); err != nil { - t.Fatal(err) - } + _, err = io.Copy(dst, src) + require.NoError(t, err) dst.Close() // Create provenance file - if err := os.WriteFile(tempProv, []byte("test provenance data"), 0o644); err != nil { - t.Fatal(err) - } + require.NoError(t, os.WriteFile(tempProv, []byte("test provenance data"), 0o644)) return tempChart, func() {} }, @@ -373,9 +308,7 @@ func TestOCIPusher_Push_ChartOperations(t *testing.T) { } pusher, err := NewOCIPusher(tt.options...) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = pusher.Push(chartRef, tt.href) @@ -400,27 +333,17 @@ func TestOCIPusher_Push_MultipleOptions(t *testing.T) { } pusher, err := NewOCIPusher() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Test that multiple options are applied correctly - err = pusher.Push(chartPath, "oci://localhost:5000/test", + // We expect an error since we're not actually pushing to a registry + require.Error(t, pusher.Push(chartPath, "oci://localhost:5000/test", WithPlainHTTP(true), WithInsecureSkipTLSVerify(true), - ) - - // We expect an error since we're not actually pushing to a registry - if err == nil { - t.Fatal("Expected error when pushing without a valid registry") - } + ), "Expected error when pushing without a valid registry") // Verify options were applied op := pusher.(*OCIPusher) - if !op.opts.plainHTTP { - t.Error("Expected plainHTTP option to be applied") - } - if !op.opts.insecureSkipTLSVerify { - t.Error("Expected insecureSkipTLSVerify option to be applied") - } + assert.True(t, op.opts.plainHTTP, "Expected plainHTTP option to be applied") + assert.True(t, op.opts.insecureSkipTLSVerify, "Expected insecureSkipTLSVerify option to be applied") } diff --git a/pkg/pusher/pusher_test.go b/pkg/pusher/pusher_test.go index 71fab8694..078b2fa73 100644 --- a/pkg/pusher/pusher_test.go +++ b/pkg/pusher/pusher_test.go @@ -18,6 +18,9 @@ package pusher import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/registry" ) @@ -28,9 +31,7 @@ func TestProvider(t *testing.T) { func(_ ...Option) (Pusher, error) { return nil, nil }, } - if !p.Provides("three") { - t.Error("Expected provider to provide three") - } + assert.True(t, p.Provides("three"), "Expected provider to provide three") } func TestProviders(t *testing.T) { @@ -39,30 +40,24 @@ func TestProviders(t *testing.T) { {[]string{"two", "four"}, func(_ ...Option) (Pusher, error) { return nil, nil }}, } - if _, err := ps.ByScheme("one"); err != nil { - t.Error(err) - } - if _, err := ps.ByScheme("four"); err != nil { - t.Error(err) - } + _, err := ps.ByScheme("one") + require.NoError(t, err) + _, err = ps.ByScheme("four") + require.NoError(t, err) - if _, err := ps.ByScheme("five"); err == nil { - t.Error("Did not expect handler for five") - } + _, err = ps.ByScheme("five") + assert.Error(t, err, "Did not expect handler for five") } func TestAll(t *testing.T) { env := cli.New() all := All(env) - if len(all) != 1 { - t.Errorf("expected 1 provider (OCI), got %d", len(all)) - } + assert.Len(t, all, 1, "expected 1 provider (OCI), got %d", len(all)) } func TestByScheme(t *testing.T) { env := cli.New() g := All(env) - if _, err := g.ByScheme(registry.OCIScheme); err != nil { - t.Error(err) - } + _, err := g.ByScheme(registry.OCIScheme) + assert.NoError(t, err) } diff --git a/pkg/registry/chart.go b/pkg/registry/chart.go index 7c41785c5..b8b0d88b6 100644 --- a/pkg/registry/chart.go +++ b/pkg/registry/chart.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry import ( "bytes" diff --git a/pkg/registry/chart_test.go b/pkg/registry/chart_test.go index e27c3d619..3edf21e38 100644 --- a/pkg/registry/chart_test.go +++ b/pkg/registry/chart_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry import ( "testing" @@ -232,8 +232,7 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) { result := generateOCIAnnotations(testChart, nowTimeString) // Check that created annotation exists - _, ok := result[ocispec.AnnotationCreated] - assert.True(t, ok, "%s annotation not created", ocispec.AnnotationCreated) + assert.Contains(t, result, ocispec.AnnotationCreated, "%s annotation not created", ocispec.AnnotationCreated) // Verify value of created artifact in RFC3339 format _, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]) @@ -243,12 +242,11 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) { result = generateOCIAnnotations(testChart, "") // Check that created annotation exists - _, ok = result[ocispec.AnnotationCreated] - require.True(t, ok, "%s annotation not created", ocispec.AnnotationCreated) + require.Contains(t, result, ocispec.AnnotationCreated, "%s annotation not created", ocispec.AnnotationCreated) createdTimeAnnotation, err := time.Parse(time.RFC3339, result[ocispec.AnnotationCreated]) require.NoError(t, err, "%s annotation with value '%s' not in RFC3339 format", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated]) // Verify creation annotation after (or equals) time test began - assert.False(t, nowTime.Before(createdTimeAnnotation), "%s annotation with value '%s' not configured properly. Annotation value is not after %s", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated], nowTimeString) + assert.GreaterOrEqual(t, nowTime, createdTimeAnnotation, "%s annotation with value '%s' not configured properly. Annotation value is not after %s", ocispec.AnnotationCreated, result[ocispec.AnnotationCreated], nowTimeString) } diff --git a/pkg/registry/client.go b/pkg/registry/client.go index cba346dea..d1a744f4b 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry import ( "context" diff --git a/pkg/registry/client_http_test.go b/pkg/registry/client_http_test.go index 316a82d3f..0a51b3347 100644 --- a/pkg/registry/client_http_test.go +++ b/pkg/registry/client_http_test.go @@ -39,15 +39,13 @@ func (suite *HTTPRegistryClientTestSuite) TearDownSuite() { } func (suite *HTTPRegistryClientTestSuite) Test_0_Login() { - err := suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().Error(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptPlainText(true)) - suite.Require().Error(err, "error logging into registry with bad credentials") + LoginOptPlainText(true)), "error logging into registry with bad credentials") - err = suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().NoError(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), - LoginOptPlainText(true)) - suite.Require().NoError(err, "no error logging into registry with good credentials") + LoginOptPlainText(true)), "no error logging into registry with good credentials") } func (suite *HTTPRegistryClientTestSuite) Test_1_Push() { diff --git a/pkg/registry/client_insecure_tls_test.go b/pkg/registry/client_insecure_tls_test.go index ae0a44337..f1ece1b1c 100644 --- a/pkg/registry/client_insecure_tls_test.go +++ b/pkg/registry/client_insecure_tls_test.go @@ -38,15 +38,13 @@ func (suite *InsecureTLSRegistryClientTestSuite) TearDownSuite() { } func (suite *InsecureTLSRegistryClientTestSuite) Test_0_Login() { - err := suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().Error(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptInsecure(true)) - suite.Require().Error(err, "error logging into registry with bad credentials") + LoginOptInsecure(true)), "error logging into registry with bad credentials") - err = suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().NoError(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(true)) - suite.Require().NoError(err, "no error logging into registry with good credentials") + LoginOptInsecure(true)), "no error logging into registry with good credentials") } func (suite *InsecureTLSRegistryClientTestSuite) Test_1_Push() { @@ -68,8 +66,7 @@ func (suite *InsecureTLSRegistryClientTestSuite) Test_4_Logout() { suite.Require().Error(err, "failed to delete the credential for this-host-aint-real:5000") } - err = suite.RegistryClient.Logout(suite.DockerRegistryHost) - suite.Require().NoError(err, "no error logging out of registry") + suite.Require().NoError(suite.RegistryClient.Logout(suite.DockerRegistryHost), "no error logging out of registry") } func TestInsecureTLSRegistryClientTestSuite(t *testing.T) { diff --git a/pkg/registry/client_test.go b/pkg/registry/client_test.go index 97b7c7c4c..21604ce7e 100644 --- a/pkg/registry/client_test.go +++ b/pkg/registry/client_test.go @@ -65,9 +65,9 @@ func TestLogin_ResetsForceAttemptOAuth2_OnSuccess(t *testing.T) { if r.URL.Path == "/v2/" { // Accept either HEAD or GET w.WriteHeader(http.StatusOK) - return + } else { + http.NotFound(w, r) } - http.NotFound(w, r) })) defer srv.Close() diff --git a/pkg/registry/client_tls_test.go b/pkg/registry/client_tls_test.go index 45eff232c..0bad5df64 100644 --- a/pkg/registry/client_tls_test.go +++ b/pkg/registry/client_tls_test.go @@ -40,22 +40,19 @@ func (suite *TLSRegistryClientTestSuite) TearDownSuite() { } func (suite *TLSRegistryClientTestSuite) Test_0_Login() { - err := suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().Error(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)) - suite.Require().Error(err, "error logging into registry with bad credentials") + LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)), "error logging into registry with bad credentials") - err = suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().NoError(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), - LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)) - suite.Require().NoError(err, "no error logging into registry with good credentials") + LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)), "no error logging into registry with good credentials") } func (suite *TLSRegistryClientTestSuite) Test_1_Login() { - err := suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().Error(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptTLSClientConfigFromConfig(&tls.Config{})) - suite.Require().Error(err, "error logging into registry with bad credentials") + LoginOptTLSClientConfigFromConfig(&tls.Config{})), "error logging into registry with bad credentials") // Create a *tls.Config from tlsCert, tlsKey, and tlsCA. cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey) @@ -69,10 +66,9 @@ func (suite *TLSRegistryClientTestSuite) Test_1_Login() { RootCAs: rootCAs, } - err = suite.RegistryClient.Login(suite.DockerRegistryHost, + suite.Require().NoError(suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), - LoginOptTLSClientConfigFromConfig(conf)) - suite.Require().NoError(err, "no error logging into registry with good credentials") + LoginOptTLSClientConfigFromConfig(conf)), "no error logging into registry with good credentials") } func (suite *TLSRegistryClientTestSuite) Test_1_Push() { @@ -94,8 +90,7 @@ func (suite *TLSRegistryClientTestSuite) Test_4_Logout() { suite.Require().Error(err, "failed to delete the credential for this-host-aint-real:5000") } - err = suite.RegistryClient.Logout(suite.DockerRegistryHost) - suite.Require().NoError(err, "no error logging out of registry") + suite.Require().NoError(suite.RegistryClient.Logout(suite.DockerRegistryHost), "no error logging out of registry") } func TestTLSRegistryClientTestSuite(t *testing.T) { diff --git a/pkg/registry/constants.go b/pkg/registry/constants.go index c455cf314..df31a18c4 100644 --- a/pkg/registry/constants.go +++ b/pkg/registry/constants.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry const ( // OCIScheme is the URL scheme for OCI-based requests diff --git a/pkg/registry/plugin_test.go b/pkg/registry/plugin_test.go index bb557c5b8..d51cfa0d6 100644 --- a/pkg/registry/plugin_test.go +++ b/pkg/registry/plugin_test.go @@ -78,11 +78,10 @@ func TestGetPluginName(t *testing.T) { if tt.expectErr { assert.Error(t, err, "expected error but got none") - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected, pluginName) } - - require.NoError(t, err) - assert.Equal(t, tt.expected, pluginName) }) } } diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 429b15113..40ebe9687 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -73,10 +73,8 @@ type TestRegistry struct { func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { suite.WorkspaceDir = testWorkspaceDir - err := os.RemoveAll(suite.WorkspaceDir) - suite.Require().NoError(err, "no error removing test workspace dir") - err = os.Mkdir(suite.WorkspaceDir, 0o700) - suite.Require().NoError(err, "no error creating test workspace dir") + suite.Require().NoError(os.RemoveAll(suite.WorkspaceDir), "no error removing test workspace dir") + suite.Require().NoError(os.Mkdir(suite.WorkspaceDir, 0o700), "no error creating test workspace dir") var out bytes.Buffer @@ -92,6 +90,7 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { ClientOptBasicAuth(testUsername, testPassword), } + var err error if tlsEnabled { var tlsConf *tls.Config if insecure { @@ -122,8 +121,7 @@ func setup(suite *TestRegistry, tlsEnabled, insecure bool, auth string) { pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost) suite.Require().NoError(err, "no error generating bcrypt password for test htpasswd file") htpasswdPath := filepath.Join(suite.WorkspaceDir, testHtpasswdFileBasename) - err = os.WriteFile(htpasswdPath, fmt.Appendf(nil, "%s:%s\n", testUsername, string(pwBytes)), 0o644) - suite.Require().NoError(err, "no error creating test htpasswd file") + suite.Require().NoError(os.WriteFile(htpasswdPath, fmt.Appendf(nil, "%s:%s\n", testUsername, string(pwBytes)), 0o644), "no error creating test htpasswd file") // Registry config config := &configuration.Configuration{} @@ -378,23 +376,21 @@ func initFakeRegistryTestServer() string { if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) - return + } else { + w.Header().Set("Content-Type", ProvLayerMediaType) + w.Write(data) } - w.Header().Set("Content-Type", ProvLayerMediaType) - w.Write(data) - case "/v2/testrepo/image-index/blobs/sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55": data, err := os.ReadFile("../downloader/testdata/signtest-0.1.0.tgz") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) - return + } else { + w.Header().Set("Content-Type", ChartLayerMediaType) + w.Write(data) } - w.Header().Set("Content-Type", ChartLayerMediaType) - w.Write(data) - default: w.WriteHeader(http.StatusNotFound) } diff --git a/pkg/registry/tag.go b/pkg/registry/tag.go index bfb4b1ef6..7e15d0dd9 100644 --- a/pkg/registry/tag.go +++ b/pkg/registry/tag.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package registry // import "helm.sh/helm/v4/pkg/registry" +package registry import ( "fmt" diff --git a/pkg/registry/transport.go b/pkg/registry/transport.go index beec43cdd..fa0103ac0 100644 --- a/pkg/registry/transport.go +++ b/pkg/registry/transport.go @@ -18,6 +18,7 @@ package registry import ( "bytes" + "errors" "fmt" "io" "log/slog" @@ -126,7 +127,7 @@ func logResponseBody(resp *http.Response) string { Closer: body, } // read the body up to limit+1 to check if the body exceeds the limit - if _, err := io.CopyN(buf, body, payloadSizeLimit+1); err != nil && err != io.EOF { + if _, err := io.CopyN(buf, body, payloadSizeLimit+1); err != nil && !errors.Is(err, io.EOF) { return fmt.Sprintf(" Error reading response body: %v", err) } diff --git a/pkg/release/v1/hook_test.go b/pkg/release/v1/hook_test.go index f3b8811a6..9e803a0fc 100644 --- a/pkg/release/v1/hook_test.go +++ b/pkg/release/v1/hook_test.go @@ -170,12 +170,12 @@ func TestHookExecutionUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &exec) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.StartedAt.Unix(), exec.StartedAt.Unix()) + assert.Equal(t, tt.expected.CompletedAt.Unix(), exec.CompletedAt.Unix()) + assert.Equal(t, tt.expected.Phase, exec.Phase) } - require.NoError(t, err) - assert.Equal(t, tt.expected.StartedAt.Unix(), exec.StartedAt.Unix()) - assert.Equal(t, tt.expected.CompletedAt.Unix(), exec.CompletedAt.Unix()) - assert.Equal(t, tt.expected.Phase, exec.Phase) }) } } @@ -194,9 +194,7 @@ func TestHookExecutionRoundTrip(t *testing.T) { require.NoError(t, err) var decoded HookExecution - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.StartedAt.Unix(), decoded.StartedAt.Unix()) assert.Equal(t, original.CompletedAt.Unix(), decoded.CompletedAt.Unix()) assert.Equal(t, original.Phase, decoded.Phase) @@ -208,12 +206,11 @@ func TestHookExecutionEmptyStringRoundTrip(t *testing.T) { input := `{"started_at":"","completed_at":"","phase":"Succeeded"}` var exec HookExecution - err := json.Unmarshal([]byte(input), &exec) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &exec)) // Verify time fields are zero values - assert.True(t, exec.StartedAt.IsZero()) - assert.True(t, exec.CompletedAt.IsZero()) + assert.Zero(t, exec.StartedAt) + assert.Zero(t, exec.CompletedAt) assert.Equal(t, HookPhaseSucceeded, exec.Phase) // Marshal back and verify empty time fields are omitted @@ -221,8 +218,7 @@ func TestHookExecutionEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time values should be omitted assert.NotContains(t, result, "started_at") diff --git a/pkg/release/v1/info_test.go b/pkg/release/v1/info_test.go index 12b3014f6..61a888cb8 100644 --- a/pkg/release/v1/info_test.go +++ b/pkg/release/v1/info_test.go @@ -253,17 +253,17 @@ func TestInfoUnmarshalJSON(t *testing.T) { err := json.Unmarshal([]byte(tt.input), &info) if tt.wantErr { assert.Error(t, err) - return + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected.FirstDeployed.Unix(), info.FirstDeployed.Unix()) + assert.Equal(t, tt.expected.LastDeployed.Unix(), info.LastDeployed.Unix()) + assert.Equal(t, tt.expected.Deleted.Unix(), info.Deleted.Unix()) + assert.Equal(t, tt.expected.Description, info.Description) + assert.Equal(t, tt.expected.Status, info.Status) + assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) + assert.Equal(t, tt.expected.Notes, info.Notes) + assert.Equal(t, tt.expected.Resources, info.Resources) } - require.NoError(t, err) - assert.Equal(t, tt.expected.FirstDeployed.Unix(), info.FirstDeployed.Unix()) - assert.Equal(t, tt.expected.LastDeployed.Unix(), info.LastDeployed.Unix()) - assert.Equal(t, tt.expected.Deleted.Unix(), info.Deleted.Unix()) - assert.Equal(t, tt.expected.Description, info.Description) - assert.Equal(t, tt.expected.Status, info.Status) - assert.Equal(t, tt.expected.RollbackRevision, info.RollbackRevision) - assert.Equal(t, tt.expected.Notes, info.Notes) - assert.Equal(t, tt.expected.Resources, info.Resources) }) } } @@ -284,9 +284,7 @@ func TestInfoRoundTrip(t *testing.T) { require.NoError(t, err) var decoded Info - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, original.FirstDeployed.Unix(), decoded.FirstDeployed.Unix()) assert.Equal(t, original.LastDeployed.Unix(), decoded.LastDeployed.Unix()) assert.Equal(t, original.Deleted.Unix(), decoded.Deleted.Unix()) @@ -330,9 +328,7 @@ func TestInfoRollbackRevisionRoundTrip(t *testing.T) { require.NoError(t, err) var decoded Info - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - + require.NoError(t, json.Unmarshal(data, &decoded)) assert.Equal(t, tt.info.RollbackRevision, decoded.RollbackRevision) assert.Equal(t, tt.info.FirstDeployed.Unix(), decoded.FirstDeployed.Unix()) assert.Equal(t, tt.info.LastDeployed.Unix(), decoded.LastDeployed.Unix()) @@ -342,8 +338,7 @@ func TestInfoRollbackRevisionRoundTrip(t *testing.T) { // Verify omitempty behavior: zero rollback_revision should not appear in JSON if tt.info.RollbackRevision == 0 { var raw map[string]any - err = json.Unmarshal(data, &raw) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &raw)) assert.NotContains(t, raw, "rollback_revision") } }) @@ -356,13 +351,12 @@ func TestInfoEmptyStringRoundTrip(t *testing.T) { input := `{"first_deployed":"","last_deployed":"","deleted":"","status":"deployed","description":"test"}` var info Info - err := json.Unmarshal([]byte(input), &info) - require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(input), &info)) // Verify time fields are zero values - assert.True(t, info.FirstDeployed.IsZero()) - assert.True(t, info.LastDeployed.IsZero()) - assert.True(t, info.Deleted.IsZero()) + assert.Zero(t, info.FirstDeployed) + assert.Zero(t, info.LastDeployed) + assert.Zero(t, info.Deleted) assert.Equal(t, common.StatusDeployed, info.Status) assert.Equal(t, "test", info.Description) @@ -371,8 +365,7 @@ func TestInfoEmptyStringRoundTrip(t *testing.T) { require.NoError(t, err) var result map[string]any - err = json.Unmarshal(data, &result) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(data, &result)) // Zero time values should be omitted due to omitzero tag assert.NotContains(t, result, "first_deployed") diff --git a/pkg/release/v1/util/filter.go b/pkg/release/v1/util/filter.go index dc60195cf..88ac995d7 100644 --- a/pkg/release/v1/util/filter.go +++ b/pkg/release/v1/util/filter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "helm.sh/helm/v4/pkg/release/common" diff --git a/pkg/release/v1/util/filter_test.go b/pkg/release/v1/util/filter_test.go index d6bda8f84..57d7e6801 100644 --- a/pkg/release/v1/util/filter_test.go +++ b/pkg/release/v1/util/filter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "testing" diff --git a/pkg/release/v1/util/manifest_sorter_test.go b/pkg/release/v1/util/manifest_sorter_test.go index 35c7a0721..da08ab169 100644 --- a/pkg/release/v1/util/manifest_sorter_test.go +++ b/pkg/release/v1/util/manifest_sorter_test.go @@ -143,7 +143,6 @@ metadata: // This test will fail if 'six' or 'seven' was added. assert.Len(t, generic, 2) - assert.Len(t, hs, 4) for _, out := range hs { diff --git a/pkg/release/v1/util/manifest_test.go b/pkg/release/v1/util/manifest_test.go index 773723c86..e76905a63 100644 --- a/pkg/release/v1/util/manifest_test.go +++ b/pkg/release/v1/util/manifest_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "testing" diff --git a/pkg/release/v1/util/sorter.go b/pkg/release/v1/util/sorter.go index 47506fbf2..e15b87593 100644 --- a/pkg/release/v1/util/sorter.go +++ b/pkg/release/v1/util/sorter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "sort" diff --git a/pkg/release/v1/util/sorter_test.go b/pkg/release/v1/util/sorter_test.go index 0450b09e6..1a3bb3e6a 100644 --- a/pkg/release/v1/util/sorter_test.go +++ b/pkg/release/v1/util/sorter_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util // import "helm.sh/helm/v4/pkg/release/v1/util" +package util import ( "testing" diff --git a/pkg/repo/v1/chartrepo.go b/pkg/repo/v1/chartrepo.go index c7c4a3e7b..42ed52f75 100644 --- a/pkg/repo/v1/chartrepo.go +++ b/pkg/repo/v1/chartrepo.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package repo // import "helm.sh/helm/v4/pkg/repo/v1" +package repo import ( "bytes" diff --git a/pkg/repo/v1/chartrepo_test.go b/pkg/repo/v1/chartrepo_test.go index 9c992474b..f0e5839ac 100644 --- a/pkg/repo/v1/chartrepo_test.go +++ b/pkg/repo/v1/chartrepo_test.go @@ -18,7 +18,6 @@ package repo import ( "bytes" - "errors" "net/http" "net/http/httptest" "os" @@ -29,6 +28,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/yaml" "helm.sh/helm/v4/pkg/cli" @@ -68,37 +69,25 @@ func TestIndexCustomSchemeDownload(t *testing.T) { Name: repoName, URL: repoURL, }, providers) - if err != nil { - t.Fatalf("Problem loading chart repository from %s: %v", repoURL, err) - } + require.NoErrorf(t, err, "Problem loading chart repository from %s", repoURL) repo.CachePath = t.TempDir() tempIndexFile, err := os.CreateTemp(t.TempDir(), "test-repo") - if err != nil { - t.Fatalf("Failed to create temp index file: %v", err) - } + require.NoErrorf(t, err, "Failed to create temp index file") defer os.Remove(tempIndexFile.Name()) idx, err := repo.DownloadIndexFile() - if err != nil { - t.Fatalf("Failed to download index file to %s: %v", idx, err) - } + require.NoErrorf(t, err, "Failed to download index file to %s", idx) - if len(myCustomGetter.repoUrls) != 1 { - t.Fatal("Custom Getter.Get should be called once") - } + require.Len(t, myCustomGetter.repoUrls, 1, "Custom Getter.Get should be called once") expectedRepoIndexURL := repoURL + "/index.yaml" - if myCustomGetter.repoUrls[0] != expectedRepoIndexURL { - t.Fatalf("Custom Getter.Get should be called with %s", expectedRepoIndexURL) - } + require.Equalf(t, expectedRepoIndexURL, myCustomGetter.repoUrls[0], "Custom Getter.Get should be called with %s", expectedRepoIndexURL) } func TestConcurrencyDownloadIndex(t *testing.T) { srv, err := startLocalServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() repo, err := NewChartRepository(&Entry{ @@ -106,16 +95,12 @@ func TestConcurrencyDownloadIndex(t *testing.T) { URL: srv.URL, }, getter.All(&cli.EnvSettings{})) - if err != nil { - t.Fatalf("Problem loading chart repository from %s: %v", srv.URL, err) - } + require.NoErrorf(t, err, "Problem loading chart repository from %s", srv.URL) repo.CachePath = t.TempDir() // initial download index idx, err := repo.DownloadIndexFile() - if err != nil { - t.Fatalf("Failed to download index file to %s: %v", idx, err) - } + require.NoErrorf(t, err, "Failed to download index file to %s", idx) indexFName := filepath.Join(repo.CachePath, helmpath.CacheIndexFile(repo.Config.Name)) @@ -128,16 +113,12 @@ func TestConcurrencyDownloadIndex(t *testing.T) { for range 150 { wg.Go(func() { idx, err := repo.DownloadIndexFile() - if err != nil { - t.Errorf("Failed to download index file to %s: %v", idx, err) - } + assert.NoErrorf(t, err, "Failed to download index file to %s", idx) }) wg.Go(func() { _, err := LoadIndexFile(indexFName) - if err != nil { - t.Errorf("Failed to load index file: %v", err) - } + assert.NoErrorf(t, err, "Failed to load index file") }) } wg.Wait() @@ -175,9 +156,7 @@ func startLocalTLSServerForTests(handler http.Handler) (*httptest.Server, error) func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) { srv, err := startLocalTLSServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() chartURL, err := FindChartInRepoURL( @@ -186,12 +165,8 @@ func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) { getter.All(&cli.EnvSettings{}), WithInsecureSkipTLSVerify(true), ) - if err != nil { - t.Fatalf("%v", err) - } - if chartURL != "https://charts.helm.sh/stable/nginx-0.2.0.tgz" { - t.Errorf("%s is not the valid URL", chartURL) - } + require.NoError(t, err) + assert.Equalf(t, "https://charts.helm.sh/stable/nginx-0.2.0.tgz", chartURL, "%s is not the valid URL", chartURL) // If the insecureSkipTLSVerify is false, it will return an error that contains "x509: certificate signed by unknown authority". _, err = FindChartInRepoURL(srv.URL, "nginx", getter.All(&cli.EnvSettings{}), WithChartVersion("0.1.0")) @@ -200,36 +175,25 @@ func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) { // versions of Darwin do not. As there are people developing Helm using both old and new versions of Darwin we test // for both messages. if runtime.GOOS == "darwin" { - if !strings.Contains(err.Error(), "x509: “Acme Co” certificate is not trusted") && !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { - t.Errorf("Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err) - } - } else if !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { - t.Errorf("Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err) + require.Error(t, err) + assert.True(t, strings.Contains(err.Error(), "x509: “Acme Co” certificate is not trusted") || strings.Contains(err.Error(), "x509: certificate signed by unknown authority"), "Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err) + } else { + assert.ErrorContainsf(t, err, "x509: certificate signed by unknown authority", "Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error") } } func TestFindChartInRepoURL(t *testing.T) { srv, err := startLocalServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() chartURL, err := FindChartInRepoURL(srv.URL, "nginx", getter.All(&cli.EnvSettings{})) - if err != nil { - t.Fatalf("%v", err) - } - if chartURL != "https://charts.helm.sh/stable/nginx-0.2.0.tgz" { - t.Errorf("%s is not the valid URL", chartURL) - } + require.NoError(t, err) + assert.Equalf(t, "https://charts.helm.sh/stable/nginx-0.2.0.tgz", chartURL, "%s is not the valid URL", chartURL) chartURL, err = FindChartInRepoURL(srv.URL, "nginx", getter.All(&cli.EnvSettings{}), WithChartVersion("0.1.0")) - if err != nil { - t.Errorf("%s", err) - } - if chartURL != "https://charts.helm.sh/stable/nginx-0.1.0.tgz" { - t.Errorf("%s is not the valid URL", chartURL) - } + require.NoError(t, err) + assert.Equalf(t, "https://charts.helm.sh/stable/nginx-0.1.0.tgz", chartURL, "%s is not the valid URL", chartURL) } func TestErrorFindChartInRepoURL(t *testing.T) { @@ -237,38 +201,22 @@ func TestErrorFindChartInRepoURL(t *testing.T) { RepositoryCache: t.TempDir(), }) - if _, err := FindChartInRepoURL("http://someserver/something", "nginx", g); err == nil { - t.Error("Expected error for bad chart URL, but did not get any errors") - } else if !strings.Contains(err.Error(), `looks like "http://someserver/something" is not a valid chart repository or cannot be reached`) { - t.Errorf("Expected error for bad chart URL, but got a different error (%v)", err) - } + _, err := FindChartInRepoURL("http://someserver/something", "nginx", g) + require.ErrorContainsf(t, err, `looks like "http://someserver/something" is not a valid chart repository or cannot be reached`, "Expected error for bad chart URL, but got a different error") srv, err := startLocalServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() - if _, err = FindChartInRepoURL(srv.URL, "nginx1", g); err == nil { - t.Error("Expected error for chart not found, but did not get any errors") - } else if err.Error() != `chart "nginx1" not found in `+srv.URL+` repository` { - t.Errorf("Expected error for chart not found, but got a different error (%v)", err) - } - if !errors.Is(err, ChartNotFoundError{}) { - t.Error("error is not of correct error type structure") - } + _, err = FindChartInRepoURL(srv.URL, "nginx1", g) + require.EqualError(t, err, `chart "nginx1" not found in `+srv.URL+` repository`, "Expected error for chart not found, but got a different error") + require.ErrorIs(t, err, ChartNotFoundError{}, "error is not of correct error type structure") - if _, err = FindChartInRepoURL(srv.URL, "nginx1", g, WithChartVersion("0.1.0")); err == nil { - t.Error("Expected error for chart not found, but did not get any errors") - } else if err.Error() != `chart "nginx1" version "0.1.0" not found in `+srv.URL+` repository` { - t.Errorf("Expected error for chart not found, but got a different error (%v)", err) - } + _, err = FindChartInRepoURL(srv.URL, "nginx1", g, WithChartVersion("0.1.0")) + require.EqualError(t, err, `chart "nginx1" version "0.1.0" not found in `+srv.URL+` repository`, "Expected error for chart not found, but got a different error") - if _, err = FindChartInRepoURL(srv.URL, "chartWithNoURL", g); err == nil { - t.Error("Expected error for no chart URLs available, but did not get any errors") - } else if err.Error() != `chart "chartWithNoURL" has no downloadable URLs` { - t.Errorf("Expected error for chart not found, but got a different error (%v)", err) - } + _, err = FindChartInRepoURL(srv.URL, "chartWithNoURL", g) + assert.EqualError(t, err, `chart "chartWithNoURL" has no downloadable URLs`, "Expected error for chart not found, but got a different error") } func TestResolveReferenceURL(t *testing.T) { @@ -286,11 +234,7 @@ func TestResolveReferenceURL(t *testing.T) { {"http://localhost:8123/charts?with=queryparameter", "/nginx-0.2.0.tgz", "http://localhost:8123/nginx-0.2.0.tgz?with=queryparameter"}, } { chartURL, err := ResolveReferenceURL(tt.baseURL, tt.refURL) - if err != nil { - t.Errorf("unexpected error in ResolveReferenceURL(%q, %q): %s", tt.baseURL, tt.refURL, err) - } - if chartURL != tt.chartURL { - t.Errorf("expected ResolveReferenceURL(%q, %q) to equal %q, got %q", tt.baseURL, tt.refURL, tt.chartURL, chartURL) - } + require.NoErrorf(t, err, "unexpected error in ResolveReferenceURL(%q, %q)", tt.baseURL, tt.refURL) + assert.Equalf(t, chartURL, tt.chartURL, "expected ResolveReferenceURL(%q, %q) to equal %q, got %q", tt.baseURL, tt.refURL, tt.chartURL, chartURL) } } diff --git a/pkg/repo/v1/index.go b/pkg/repo/v1/index.go index 839a4cca9..1c1497c5e 100644 --- a/pkg/repo/v1/index.go +++ b/pkg/repo/v1/index.go @@ -421,8 +421,8 @@ func jsonOrYamlUnmarshal(b []byte, i any) error { // And repository indexes may be generated by older/non-compliant software, which doesn't // conform to all validations. func ignoreSkippableChartValidationError(err error) error { - verr, ok := err.(chart.ValidationError) - if !ok { + var verr chart.ValidationError + if !errors.As(err, &verr) { return err } diff --git a/pkg/repo/v1/index_test.go b/pkg/repo/v1/index_test.go index 126be125f..09fc7de8a 100644 --- a/pkg/repo/v1/index_test.go +++ b/pkg/repo/v1/index_test.go @@ -28,6 +28,9 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/cli" "helm.sh/helm/v4/pkg/getter" @@ -95,48 +98,34 @@ func TestIndexFile(t *testing.T) { {&chart.Metadata{APIVersion: "v2", Name: "setter", Version: "0.1.8"}, "setter-0.1.8.tgz", "http://example.com/charts", "sha256:1234567890abc"}, {&chart.Metadata{APIVersion: "v2", Name: "setter", Version: "0.1.8+beta"}, "setter-0.1.8+beta.tgz", "http://example.com/charts", "sha256:1234567890abc"}, } { - if err := i.MustAdd(x.md, x.filename, x.baseURL, x.digest); err != nil { - t.Errorf("unexpected error adding to index: %s", err) - } + require.NoErrorf(t, i.MustAdd(x.md, x.filename, x.baseURL, x.digest), "unexpected error adding to index") } i.SortEntries() - if i.APIVersion != APIVersionV1 { - t.Error("Expected API version v1") - } + assert.Equal(t, APIVersionV1, i.APIVersion, "Expected API version v1") - if len(i.Entries) != 3 { - t.Errorf("Expected 3 charts. Got %d", len(i.Entries)) - } + assert.Lenf(t, i.Entries, 3, "Expected 3 charts. Got %d", len(i.Entries)) - if i.Entries["clipper"][0].Name != "clipper" { - t.Errorf("Expected clipper, got %s", i.Entries["clipper"][0].Name) - } + assert.Equalf(t, "clipper", i.Entries["clipper"][0].Name, "Expected clipper, got %s", i.Entries["clipper"][0].Name) - if len(i.Entries["cutter"]) != 3 { - t.Error("Expected three cutters.") - } + assert.Len(t, i.Entries["cutter"], 3, "Expected three cutters.") // Test that the sort worked. 0.2 should be at the first index for Cutter. - if v := i.Entries["cutter"][0].Version; v != "0.2.0" { - t.Errorf("Unexpected first version: %s", v) - } + v := i.Entries["cutter"][0].Version + assert.Equalf(t, "0.2.0", v, "Unexpected first version: %s", v) cv, err := i.Get("setter", "0.1.9") - if err == nil && !strings.Contains(cv.Version, "0.1.9") { - t.Errorf("Unexpected version: %s", cv.Version) - } + require.NoError(t, err) + assert.Contains(t, cv.Version, "0.1.9", "Unexpected version: %s", cv.Version) cv, err = i.Get("setter", "0.1.9+alpha") - if err != nil || cv.Version != "0.1.9+alpha" { - t.Error("Expected version: 0.1.9+alpha") - } + require.NoError(t, err, "Expected version: 0.1.9+alpha") + assert.Equal(t, "0.1.9+alpha", cv.Version, "Expected version: 0.1.9+alpha") cv, err = i.Get("setter", "0.1.8") - if err != nil || cv.Version != "0.1.8" { - t.Error("Expected version: 0.1.8") - } + require.NoError(t, err, "Expected version: 0.1.8") + assert.Equal(t, "0.1.8", cv.Version, "Expected version: 0.1.8") } func TestLoadIndex(t *testing.T) { @@ -162,9 +151,7 @@ func TestLoadIndex(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { t.Parallel() i, err := LoadIndexFile(tc.Filename) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) verifyLocalIndex(t, i) }) } @@ -172,52 +159,39 @@ func TestLoadIndex(t *testing.T) { // TestLoadIndex_Duplicates is a regression to make sure that we don't non-deterministically allow duplicate packages. func TestLoadIndex_Duplicates(t *testing.T) { - if _, err := loadIndex([]byte(indexWithDuplicates), "indexWithDuplicates"); err == nil { - t.Error("Expected an error when duplicate entries are present") - } + _, err := loadIndex([]byte(indexWithDuplicates), "indexWithDuplicates") + assert.Error(t, err, "Expected an error when duplicate entries are present") } func TestLoadIndex_EmptyEntry(t *testing.T) { - if _, err := loadIndex([]byte(indexWithEmptyEntry), "indexWithEmptyEntry"); err != nil { - t.Errorf("unexpected error: %s", err) - } + _, err := loadIndex([]byte(indexWithEmptyEntry), "indexWithEmptyEntry") + assert.NoError(t, err) } func TestLoadIndex_Empty(t *testing.T) { - if _, err := loadIndex([]byte(""), "indexWithEmpty"); err == nil { - t.Error("Expected an error when index.yaml is empty.") - } + _, err := loadIndex([]byte(""), "indexWithEmpty") + assert.Error(t, err, "Expected an error when index.yaml is empty.") } func TestLoadIndexFileAnnotations(t *testing.T) { i, err := LoadIndexFile(annotationstestfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) verifyLocalIndex(t, i) - if len(i.Annotations) != 1 { - t.Fatalf("Expected 1 annotation but got %d", len(i.Annotations)) - } - if i.Annotations["helm.sh/test"] != "foo bar" { - t.Error("Did not get expected value for helm.sh/test annotation") - } + require.Lenf(t, i.Annotations, 1, "Expected 1 annotation but got %d", len(i.Annotations)) + assert.Equal(t, "foo bar", i.Annotations["helm.sh/test"], "Did not get expected value for helm.sh/test annotation") } func TestLoadUnorderedIndex(t *testing.T) { i, err := LoadIndexFile(unorderedTestfile) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) verifyLocalIndex(t, i) } func TestMerge(t *testing.T) { ind1 := NewIndexFile() - if err := ind1.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "dreadnought", Version: "0.1.0"}, "dreadnought-0.1.0.tgz", "http://example.com", "aaaa"); err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, ind1.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "dreadnought", Version: "0.1.0"}, "dreadnought-0.1.0.tgz", "http://example.com", "aaaa")) ind2 := NewIndexFile() @@ -230,121 +204,89 @@ func TestMerge(t *testing.T) { {&chart.Metadata{APIVersion: "v2", Name: "dreadnought", Version: "0.2.0"}, "dreadnought-0.2.0.tgz", "http://example.com", "aaaabbbb"}, {&chart.Metadata{APIVersion: "v2", Name: "doughnut", Version: "0.2.0"}, "doughnut-0.2.0.tgz", "http://example.com", "ccccbbbb"}, } { - if err := ind2.MustAdd(x.md, x.filename, x.baseURL, x.digest); err != nil { - t.Errorf("unexpected error: %s", err) - } + require.NoError(t, ind2.MustAdd(x.md, x.filename, x.baseURL, x.digest)) } ind1.Merge(ind2) - if len(ind1.Entries) != 2 { - t.Errorf("Expected 2 entries, got %d", len(ind1.Entries)) - } + assert.Lenf(t, ind1.Entries, 2, "Expected 2 entries, got %d", len(ind1.Entries)) vs := ind1.Entries["dreadnought"] - if len(vs) != 2 { - t.Errorf("Expected 2 versions, got %d", len(vs)) - } + assert.Lenf(t, vs, 2, "Expected 2 versions, got %d", len(vs)) - if v := vs[1]; v.Version != "0.2.0" { - t.Errorf("Expected %q version to be 0.2.0, got %s", v.Name, v.Version) - } + v := vs[1] + assert.Equalf(t, "0.2.0", v.Version, "Expected %q version to be 0.2.0, got %s", v.Name, v.Version) } func TestDownloadIndexFile(t *testing.T) { t.Run("should download index file", func(t *testing.T) { srv, err := startLocalServerForTests(nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() r, err := NewChartRepository(&Entry{ Name: testRepo, URL: srv.URL, }, getter.All(&cli.EnvSettings{})) - if err != nil { - t.Errorf("Problem creating chart repository from %s: %v", testRepo, err) - } + require.NoErrorf(t, err, "Problem creating chart repository from %s", testRepo) idx, err := r.DownloadIndexFile() - if err != nil { - t.Fatalf("Failed to download index file to %s: %#v", idx, err) - } + require.NoErrorf(t, err, "Failed to download index file to %s", idx) - if _, err := os.Stat(idx); err != nil { - t.Fatalf("error finding created index file: %#v", err) - } + _, err = os.Stat(idx) + + require.NoErrorf(t, err, "error finding created index file") i, err := LoadIndexFile(idx) - if err != nil { - t.Fatalf("Index %q failed to parse: %s", testfile, err) - } + require.NoErrorf(t, err, "Index %q failed to parse", testfile) verifyLocalIndex(t, i) // Check that charts file is also created idx = filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name)) - if _, err := os.Stat(idx); err != nil { - t.Fatalf("error finding created charts file: %#v", err) - } + _, err = os.Stat(idx) + require.NoErrorf(t, err, "error finding created charts file") b, err := os.ReadFile(idx) - if err != nil { - t.Fatalf("error reading charts file: %#v", err) - } + require.NoErrorf(t, err, "error reading charts file") verifyLocalChartsFile(t, b, i) }) t.Run("should not decode the path in the repo url while downloading index", func(t *testing.T) { chartRepoURLPath := "/some%2Fpath/test" fileBytes, err := os.ReadFile("testdata/local-index.yaml") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.RawPath == chartRepoURLPath+"/index.yaml" { w.Write(fileBytes) } }) srv, err := startLocalServerForTests(handler) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer srv.Close() r, err := NewChartRepository(&Entry{ Name: testRepo, URL: srv.URL + chartRepoURLPath, }, getter.All(&cli.EnvSettings{})) - if err != nil { - t.Errorf("Problem creating chart repository from %s: %v", testRepo, err) - } + require.NoErrorf(t, err, "Problem creating chart repository from %s", testRepo) idx, err := r.DownloadIndexFile() - if err != nil { - t.Fatalf("Failed to download index file to %s: %#v", idx, err) - } + require.NoErrorf(t, err, "Failed to download index file to %s", idx) - if _, err := os.Stat(idx); err != nil { - t.Fatalf("error finding created index file: %#v", err) - } + _, err = os.Stat(idx) + require.NoErrorf(t, err, "error finding created index file") i, err := LoadIndexFile(idx) - if err != nil { - t.Fatalf("Index %q failed to parse: %s", testfile, err) - } + require.NoErrorf(t, err, "Index %q failed to parse", testfile) verifyLocalIndex(t, i) // Check that charts file is also created idx = filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name)) - if _, err := os.Stat(idx); err != nil { - t.Fatalf("error finding created charts file: %#v", err) - } + _, err = os.Stat(idx) + require.NoErrorf(t, err, "error finding created charts file") b, err := os.ReadFile(idx) - if err != nil { - t.Fatalf("error reading charts file: %#v", err) - } + require.NoErrorf(t, err, "error reading charts file") verifyLocalChartsFile(t, b, i) }) } @@ -352,23 +294,17 @@ func TestDownloadIndexFile(t *testing.T) { func verifyLocalIndex(t *testing.T, i *IndexFile) { t.Helper() numEntries := len(i.Entries) - if numEntries != 3 { - t.Errorf("Expected 3 entries in index file but got %d", numEntries) - } + assert.Equalf(t, 3, numEntries, "Expected 3 entries in index file but got %d", numEntries) alpine, ok := i.Entries["alpine"] - if !ok { - t.Fatal("'alpine' section not found.") - } + require.True(t, ok, "'alpine' section not found.") - if l := len(alpine); l != 1 { - t.Fatalf("'alpine' should have 1 chart, got %d", l) - } + l := len(alpine) + require.Equalf(t, 1, l, "'alpine' should have 1 chart, got %d", l) nginx, ok := i.Entries["nginx"] - if !ok || len(nginx) != 2 { - t.Fatal("Expected 2 nginx entries") - } + require.True(t, ok) + require.Len(t, nginx, 2, "Expected 2 nginx entries") expects := []*ChartVersion{ { @@ -419,31 +355,17 @@ func verifyLocalIndex(t *testing.T, i *IndexFile) { for i, tt := range tests { expect := expects[i] - if tt.Name != expect.Name { - t.Errorf("Expected name %q, got %q", expect.Name, tt.Name) - } - if tt.Description != expect.Description { - t.Errorf("Expected description %q, got %q", expect.Description, tt.Description) - } - if tt.Version != expect.Version { - t.Errorf("Expected version %q, got %q", expect.Version, tt.Version) - } - if tt.Digest != expect.Digest { - t.Errorf("Expected digest %q, got %q", expect.Digest, tt.Digest) - } - if tt.Home != expect.Home { - t.Errorf("Expected home %q, got %q", expect.Home, tt.Home) - } + assert.Equalf(t, expect.Name, tt.Name, "Expected name %q, got %q", expect.Name, tt.Name) + assert.Equalf(t, expect.Description, tt.Description, "Expected description %q, got %q", expect.Description, tt.Description) + assert.Equalf(t, expect.Version, tt.Version, "Expected version %q, got %q", expect.Version, tt.Version) + assert.Equalf(t, expect.Digest, tt.Digest, "Expected digest %q, got %q", expect.Digest, tt.Digest) + assert.Equalf(t, expect.Home, tt.Home, "Expected home %q, got %q", expect.Home, tt.Home) for i, url := range tt.URLs { - if url != expect.URLs[i] { - t.Errorf("Expected URL %q, got %q", expect.URLs[i], url) - } + assert.Equalf(t, expect.URLs[i], url, "Expected URL %q, got %q", expect.URLs[i], url) } for i, kw := range tt.Keywords { - if kw != expect.Keywords[i] { - t.Errorf("Expected keywords %q, got %q", expect.Keywords[i], kw) - } + assert.Equalf(t, expect.Keywords[i], kw, "Expected keywords %q, got %q", expect.Keywords[i], kw) } } } @@ -462,21 +384,16 @@ func verifyLocalChartsFile(t *testing.T, chartsContent []byte, indexContent *Ind } sort.Strings(reald) - if strings.Join(expected, " ") != strings.Join(reald, " ") { - t.Errorf("Cached charts file content unexpected. Expected:\n%s\ngot:\n%s", expected, reald) - } + assert.Equalf(t, strings.Join(expected, " "), strings.Join(reald, " "), "Cached charts file content unexpected. Expected:\n%s\ngot:\n%s", expected, reald) } func TestIndexDirectory(t *testing.T) { dir := "testdata/repository" index, err := IndexDirectory(dir, "http://localhost:8080") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) - if l := len(index.Entries); l != 3 { - t.Fatalf("Expected 3 entries, got %d", l) - } + l := len(index.Entries) + require.Equalf(t, 3, l, "Expected 3 entries, got %d", l) // Other things test the entry generation more thoroughly. We just test a // few fields. @@ -489,20 +406,12 @@ func TestIndexDirectory(t *testing.T) { for _, test := range corpus { cname := test.chartName frobs, ok := index.Entries[cname] - if !ok { - t.Fatalf("Could not read chart %s", cname) - } + require.Truef(t, ok, "Could not read chart %s", cname) frob := frobs[0] - if frob.Digest == "" { - t.Errorf("Missing digest of file %s.", frob.Name) - } - if frob.URLs[0] != test.downloadLink { - t.Errorf("Unexpected URLs: %v", frob.URLs) - } - if frob.Name != cname { - t.Errorf("Expected %q, got %q", cname, frob.Name) - } + assert.NotEmptyf(t, frob.Digest, "Missing digest of file %s.", frob.Name) + assert.Equalf(t, test.downloadLink, frob.URLs[0], "Unexpected URLs: %v", frob.URLs) + assert.Equalf(t, cname, frob.Name, "Expected %q, got %q", cname, frob.Name) } } @@ -520,64 +429,40 @@ func TestIndexAdd(t *testing.T) { {&chart.Metadata{APIVersion: "v2", Name: "alpine", Version: "0.1.0"}, "/home/charts/alpine-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"}, {&chart.Metadata{APIVersion: "v2", Name: "deis", Version: "0.1.0"}, "/home/charts/deis-0.1.0.tgz", "http://example.com/charts/", "sha256:1234567890"}, } { - if err := i.MustAdd(x.md, x.filename, x.baseURL, x.digest); err != nil { - t.Errorf("unexpected error adding to index: %s", err) - } + require.NoErrorf(t, i.MustAdd(x.md, x.filename, x.baseURL, x.digest), "unexpected error adding to index") } - if i.Entries["clipper"][0].URLs[0] != "http://example.com/charts/clipper-0.1.0.tgz" { - t.Errorf("Expected http://example.com/charts/clipper-0.1.0.tgz, got %s", i.Entries["clipper"][0].URLs[0]) - } - if i.Entries["alpine"][0].URLs[0] != "http://example.com/charts/alpine-0.1.0.tgz" { - t.Errorf("Expected http://example.com/charts/alpine-0.1.0.tgz, got %s", i.Entries["alpine"][0].URLs[0]) - } - if i.Entries["deis"][0].URLs[0] != "http://example.com/charts/deis-0.1.0.tgz" { - t.Errorf("Expected http://example.com/charts/deis-0.1.0.tgz, got %s", i.Entries["deis"][0].URLs[0]) - } + assert.Equalf(t, "http://example.com/charts/clipper-0.1.0.tgz", i.Entries["clipper"][0].URLs[0], "Expected http://example.com/charts/clipper-0.1.0.tgz, got %s", i.Entries["clipper"][0].URLs[0]) + assert.Equalf(t, "http://example.com/charts/alpine-0.1.0.tgz", i.Entries["alpine"][0].URLs[0], "Expected http://example.com/charts/alpine-0.1.0.tgz, got %s", i.Entries["alpine"][0].URLs[0]) + assert.Equalf(t, "http://example.com/charts/deis-0.1.0.tgz", i.Entries["deis"][0].URLs[0], "Expected http://example.com/charts/deis-0.1.0.tgz, got %s", i.Entries["deis"][0].URLs[0]) // test error condition - if err := i.MustAdd(&chart.Metadata{}, "error-0.1.0.tgz", "", ""); err == nil { - t.Fatal("expected error adding to index") - } + require.Error(t, i.MustAdd(&chart.Metadata{}, "error-0.1.0.tgz", "", ""), "expected error adding to index") } func TestIndexWrite(t *testing.T) { i := NewIndexFile() - if err := i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"); err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890")) dir := t.TempDir() testpath := filepath.Join(dir, "test") i.WriteFile(testpath, 0o600) got, err := os.ReadFile(testpath) - if err != nil { - t.Fatal(err) - } - if !strings.Contains(string(got), "clipper-0.1.0.tgz") { - t.Fatal("Index files doesn't contain expected content") - } + require.NoError(t, err) + require.Contains(t, string(got), "clipper-0.1.0.tgz", "Index files doesn't contain expected content") } func TestIndexJSONWrite(t *testing.T) { i := NewIndexFile() - if err := i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"); err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890")) dir := t.TempDir() testpath := filepath.Join(dir, "test") i.WriteJSONFile(testpath, 0o600) got, err := os.ReadFile(testpath) - if err != nil { - t.Fatal(err) - } - if !json.Valid(got) { - t.Fatal("Index files doesn't contain valid JSON") - } - if !strings.Contains(string(got), "clipper-0.1.0.tgz") { - t.Fatal("Index files doesn't contain expected content") - } + require.NoError(t, err) + require.True(t, json.Valid(got), "Index files doesn't contain valid JSON") + require.Contains(t, string(got), "clipper-0.1.0.tgz", "Index files doesn't contain expected content") } func TestAddFileIndexEntriesNil(t *testing.T) { @@ -592,9 +477,7 @@ func TestAddFileIndexEntriesNil(t *testing.T) { }{ {&chart.Metadata{APIVersion: "v2", Name: " ", Version: "8033-5.apinie+s.r"}, "setter-0.1.9+beta.tgz", "http://example.com/charts", "sha256:1234567890abc"}, } { - if err := i.MustAdd(x.md, x.filename, x.baseURL, x.digest); err == nil { - t.Error("expected err to be non-nil when entries not initialized") - } + assert.Error(t, i.MustAdd(x.md, x.filename, x.baseURL, x.digest), "expected err to be non-nil when entries not initialized") } } @@ -622,23 +505,13 @@ func TestIgnoreSkippableChartValidationError(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { result := ignoreSkippableChartValidationError(tc.Input) - - if tc.Input == nil { - if result != nil { - t.Error("expected nil result for nil input") - } - return - } - - if tc.ErrorSkipped { - if result != nil { - t.Error("expected nil result for skipped error") - } - return - } - - if !errors.Is(tc.Input, result) { - t.Error("expected the result equal to input") + switch { + case tc.Input == nil: + assert.NoError(t, result, "expected nil result for nil input") + case tc.ErrorSkipped: + assert.NoError(t, result, "expected nil result for skipped error") + default: + assert.ErrorIs(t, tc.Input, result, "expected the result equal to input") } }) } @@ -700,17 +573,11 @@ func TestLoadIndex_DuplicateChartDeps(t *testing.T) { for _, tc := range tests { t.Run(tc.source, func(t *testing.T) { idx, err := loadIndex([]byte(tc.data), tc.source) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) cvs := idx.Entries["nginx"] - if cvs == nil { - t.Error("expected one chart version not to be filtered out") - } + assert.NotNil(t, cvs, "expected one chart version not to be filtered out") for _, v := range cvs { - if v.Name == "alpine" { - t.Error("malformed version was not filtered out") - } + assert.NotEqual(t, "alpine", v.Name, "malformed version was not filtered out") } }) } @@ -751,9 +618,7 @@ func TestIsVersionRange(t *testing.T) { for _, tt := range tests { t.Run(tt.version, func(t *testing.T) { got := isVersionRange(tt.version) - if got != tt.expected { - t.Errorf("isVersionRange(%q) = %v, want %v", tt.version, got, tt.expected) - } + assert.Equalf(t, tt.expected, got, "isVersionRange(%q) = %v, want %v", tt.version, got, tt.expected) }) } } diff --git a/pkg/repo/v1/repo.go b/pkg/repo/v1/repo.go index 199b56ed8..be241a0ab 100644 --- a/pkg/repo/v1/repo.go +++ b/pkg/repo/v1/repo.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package repo // import "helm.sh/helm/v4/pkg/repo/v1" +package repo import ( "fmt" diff --git a/pkg/repo/v1/repo_test.go b/pkg/repo/v1/repo_test.go index 960635fc5..f7f5df9be 100644 --- a/pkg/repo/v1/repo_test.go +++ b/pkg/repo/v1/repo_test.go @@ -18,8 +18,10 @@ package repo import ( "os" - "strings" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const testRepositoriesFile = "testdata/repositories.yaml" @@ -37,24 +39,14 @@ func TestFile(t *testing.T) { }, ) - if len(rf.Repositories) != 2 { - t.Fatal("Expected 2 repositories") - } + require.Len(t, rf.Repositories, 2, "Expected 2 repositories") - if rf.Has("nosuchrepo") { - t.Error("Found nonexistent repo") - } - if !rf.Has("incubator") { - t.Error("incubator repo is missing") - } + assert.False(t, rf.Has("nosuchrepo"), "Found nonexistent repo") + assert.True(t, rf.Has("incubator"), "incubator repo is missing") stable := rf.Repositories[0] - if stable.Name != "stable" { - t.Error("stable is not named stable") - } - if stable.URL != "https://example.com/stable/charts" { - t.Error("Wrong URL for stable") - } + assert.Equal(t, "stable", stable.Name, "stable is not named stable") + assert.Equal(t, "https://example.com/stable/charts", stable.URL, "Wrong URL for stable") } func TestNewFile(t *testing.T) { @@ -71,22 +63,14 @@ func TestNewFile(t *testing.T) { ) file, err := LoadFile(testRepositoriesFile) - if err != nil { - t.Errorf("%q could not be loaded: %s", testRepositoriesFile, err) - } + require.NoErrorf(t, err, "%q could not be loaded", testRepositoriesFile) - if len(expects.Repositories) != len(file.Repositories) { - t.Fatalf("Unexpected repo data: %#v", file.Repositories) - } + require.Lenf(t, file.Repositories, len(expects.Repositories), "Unexpected repo data: %#v", file.Repositories) for i, expect := range expects.Repositories { got := file.Repositories[i] - if expect.Name != got.Name { - t.Errorf("Expected name %q, got %q", expect.Name, got.Name) - } - if expect.URL != got.URL { - t.Errorf("Expected url %q, got %q", expect.URL, got.URL) - } + assert.Equalf(t, expect.Name, got.Name, "Expected name %q, got %q", expect.Name, got.Name) + assert.Equalf(t, expect.URL, got.URL, "Expected url %q, got %q", expect.URL, got.URL) } } @@ -114,18 +98,12 @@ func TestRepoFile_Get(t *testing.T) { name := "second" entry := repo.Get(name) - if entry == nil { - t.Fatalf("Expected repo entry %q to be found", name) - } + require.NotNilf(t, entry, "Expected repo entry %q to be found", name) - if entry.URL != "https://example.com/second" { - t.Errorf("Expected repo URL to be %q but got %q", "https://example.com/second", entry.URL) - } + assert.Equalf(t, "https://example.com/second", entry.URL, "Expected repo URL to be %q but got %q", "https://example.com/second", entry.URL) entry = repo.Get("nonexistent") - if entry != nil { - t.Errorf("Got unexpected entry %+v", entry) - } + assert.Nilf(t, entry, "Got unexpected entry %+v", entry) } func TestRemoveRepository(t *testing.T) { @@ -142,15 +120,8 @@ func TestRemoveRepository(t *testing.T) { ) removeRepository := "stable" - found := sampleRepository.Remove(removeRepository) - if !found { - t.Errorf("expected repository %s not found", removeRepository) - } - - found = sampleRepository.Has(removeRepository) - if found { - t.Errorf("repository %s not deleted", removeRepository) - } + assert.Truef(t, sampleRepository.Remove(removeRepository), "expected repository %s not found", removeRepository) + assert.Falsef(t, sampleRepository.Has(removeRepository), "repository %s not deleted", removeRepository) } func TestUpdateRepository(t *testing.T) { @@ -170,18 +141,14 @@ func TestUpdateRepository(t *testing.T) { URL: "https://example.com/sample", }) - if !sampleRepository.Has(newRepoName) { - t.Errorf("expected repository %s not found", newRepoName) - } + assert.Truef(t, sampleRepository.Has(newRepoName), "expected repository %s not found", newRepoName) repoCount := len(sampleRepository.Repositories) sampleRepository.Update(&Entry{Name: newRepoName, URL: "https://example.com/sample", }) - if repoCount != len(sampleRepository.Repositories) { - t.Errorf("invalid number of repositories found %d, expected number of repositories %d", len(sampleRepository.Repositories), repoCount) - } + assert.Lenf(t, sampleRepository.Repositories, repoCount, "invalid number of repositories found %d, expected number of repositories %d", len(sampleRepository.Repositories), repoCount) } func TestWriteFile(t *testing.T) { @@ -198,31 +165,21 @@ func TestWriteFile(t *testing.T) { ) file, err := os.CreateTemp(t.TempDir(), "helm-repo") - if err != nil { - t.Errorf("failed to create test-file (%v)", err) - } + require.NoErrorf(t, err, "failed to create test-file") defer os.Remove(file.Name()) - if err := sampleRepository.WriteFile(file.Name(), 0o600); err != nil { - t.Errorf("failed to write file (%v)", err) - } + require.NoErrorf(t, sampleRepository.WriteFile(file.Name(), 0o600), "failed to write file") repos, err := LoadFile(file.Name()) - if err != nil { - t.Errorf("failed to load file (%v)", err) - } + require.NoErrorf(t, err, "failed to load file") for _, repo := range sampleRepository.Repositories { - if !repos.Has(repo.Name) { - t.Errorf("expected repository %s not found", repo.Name) - } + assert.Truef(t, repos.Has(repo.Name), "expected repository %s not found", repo.Name) } } func TestRepoNotExists(t *testing.T) { - if _, err := LoadFile("/this/path/does/not/exist.yaml"); err == nil { - t.Error("expected err to be non-nil when path does not exist") - } else if !strings.Contains(err.Error(), "couldn't load repositories file") { - t.Error("expected prompt `couldn't load repositories file`") - } + _, err := LoadFile("/this/path/does/not/exist.yaml") + require.Error(t, err, "expected err to be non-nil when path does not exist") + assert.ErrorContains(t, err, "couldn't load repositories file", "expected prompt `couldn't load repositories file`") } func TestRemoveRepositoryInvalidEntries(t *testing.T) { @@ -245,13 +202,6 @@ func TestRemoveRepositoryInvalidEntries(t *testing.T) { ) removeRepository := "stable" - found := sampleRepository.Remove(removeRepository) - if !found { - t.Errorf("expected repository %s not found", removeRepository) - } - - found = sampleRepository.Has(removeRepository) - if found { - t.Errorf("repository %s not deleted", removeRepository) - } + assert.Truef(t, sampleRepository.Remove(removeRepository), "expected repository %s not found", removeRepository) + assert.Falsef(t, sampleRepository.Has(removeRepository), "repository %s not deleted", removeRepository) } diff --git a/pkg/repo/v1/repotest/server_test.go b/pkg/repo/v1/repotest/server_test.go index 7008e2305..f74adb445 100644 --- a/pkg/repo/v1/repotest/server_test.go +++ b/pkg/repo/v1/repotest/server_test.go @@ -42,24 +42,25 @@ func TestServer(t *testing.T) { c, err := srv.CopyCharts("testdata/*.tgz") require.NoError(t, err) - - assert.Len(t, c, 1) - + require.Len(t, c, 1) assert.Equal(t, "examplechart-0.1.0.tgz", filepath.Base(c[0])) req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/examplechart-0.1.0.tgz", http.NoBody) require.NoError(t, err) + client := http.DefaultClient res, err := client.Do(req) require.NoError(t, err) - res.Body.Close() + res.Body.Close() assert.GreaterOrEqual(t, res.ContentLength, int64(500)) req, err = http.NewRequestWithContext(t.Context(), http.MethodGet, srv.URL()+"/index.yaml", http.NoBody) require.NoError(t, err) + res, err = client.Do(req) require.NoError(t, err) + data, err := io.ReadAll(res.Body) res.Body.Close() require.NoError(t, err) diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 2636755a9..f71ce44f1 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "context" diff --git a/pkg/storage/driver/cfgmaps_test.go b/pkg/storage/driver/cfgmaps_test.go index 947ebff71..b8449f67e 100644 --- a/pkg/storage/driver/cfgmaps_test.go +++ b/pkg/storage/driver/cfgmaps_test.go @@ -16,10 +16,10 @@ package driver import ( "encoding/base64" "encoding/json" - "errors" - "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" "helm.sh/helm/v4/pkg/release" @@ -29,9 +29,7 @@ import ( func TestConfigMapName(t *testing.T) { c := newTestFixtureCfgMaps(t) - if c.Name() != ConfigMapsDriverName { - t.Errorf("Expected name to be %q, got %q", ConfigMapsDriverName, c.Name()) - } + assert.Equal(t, ConfigMapsDriverName, c.Name(), "Expected name to be %q, got %q", ConfigMapsDriverName, c.Name()) } func TestConfigMapGet(t *testing.T) { @@ -45,13 +43,9 @@ func TestConfigMapGet(t *testing.T) { // get release with key got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } + require.NoError(t, err, "Failed to get release") // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestUncompressedConfigMapGet(t *testing.T) { @@ -63,13 +57,9 @@ func TestUncompressedConfigMapGet(t *testing.T) { // Create a test fixture which contains an uncompressed release cfgmap, err := newConfigMapsObject(key, rel, nil) - if err != nil { - t.Fatalf("Failed to create configmap: %s", err) - } + require.NoError(t, err, "Failed to create configmap") b, err := json.Marshal(rel) - if err != nil { - t.Fatalf("Failed to marshal release: %s", err) - } + require.NoError(t, err, "Failed to marshal release") cfgmap.Data["release"] = base64.StdEncoding.EncodeToString(b) var mock MockConfigMapsInterface mock.objects = map[string]*v1.ConfigMap{key: cfgmap} @@ -77,13 +67,9 @@ func TestUncompressedConfigMapGet(t *testing.T) { // get release with key got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } + require.NoError(t, err, "Failed to get release") // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func convertReleaserToV1(t *testing.T, rel release.Releaser) *rspb.Release { @@ -117,12 +103,8 @@ func TestConfigMapList(t *testing.T) { return rls.Info.Status == common.StatusUninstalled }) // check - if err != nil { - t.Errorf("Failed to list deleted: %s", err) - } - if len(del) != 2 { - t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) - } + require.NoError(t, err, "Failed to list deleted") + assert.Len(t, del, 2, "Expected 2 deleted") // list all deployed releases dpl, err := cfgmaps.List(func(rel release.Releaser) bool { @@ -130,12 +112,8 @@ func TestConfigMapList(t *testing.T) { return rls.Info.Status == common.StatusDeployed }) // check - if err != nil { - t.Errorf("Failed to list deployed: %s", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d", len(dpl)) - } + require.NoError(t, err, "Failed to list deployed") + assert.Len(t, dpl, 2, "Expected 2 deployed") // list all superseded releases ssd, err := cfgmaps.List(func(rel release.Releaser) bool { @@ -143,22 +121,12 @@ func TestConfigMapList(t *testing.T) { return rls.Info.Status == common.StatusSuperseded }) // check - if err != nil { - t.Errorf("Failed to list superseded: %s", err) - } - if len(ssd) != 2 { - t.Errorf("Expected 2 superseded, got %d", len(ssd)) - } + require.NoError(t, err, "Failed to list superseded") + assert.Len(t, ssd, 2, "Expected 2 superseded") // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) - _, ok := rls.Labels["name"] - if !ok { - t.Fatalf("Expected 'name' label in results, actual %v", rls.Labels) - } - _, ok = rls.Labels["key1"] - if !ok { - t.Fatalf("Expected 'key1' label in results, actual %v", rls.Labels) - } + require.Contains(t, rls.Labels, "name", "Expected 'name' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "key1", "Expected 'key1' label in results, actual %v", rls.Labels) } func TestConfigMapQuery(t *testing.T) { @@ -172,17 +140,11 @@ func TestConfigMapQuery(t *testing.T) { }...) rls, err := cfgmaps.Query(map[string]string{"status": "deployed"}) - if err != nil { - t.Errorf("Failed to query: %s", err) - } - if len(rls) != 2 { - t.Errorf("Expected 2 results, got %d", len(rls)) - } + require.NoError(t, err, "Failed to query") + assert.Len(t, rls, 2, "Expected 2 results") _, err = cfgmaps.Query(map[string]string{"name": "notExist"}) - if !errors.Is(err, ErrReleaseNotFound) { - t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err) - } + assert.ErrorIs(t, err, ErrReleaseNotFound) } func TestConfigMapCreate(t *testing.T) { @@ -195,20 +157,14 @@ func TestConfigMapCreate(t *testing.T) { rel := releaseStub(name, vers, namespace, common.StatusDeployed) // store the release in a configmap - if err := cfgmaps.Create(key, rel); err != nil { - t.Fatalf("Failed to create release with key %q: %s", key, err) - } + require.NoErrorf(t, cfgmaps.Create(key, rel), "Failed to create release with key %q", key) // get the release back got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } + require.NoError(t, err, "Failed to get release with key %q", key) // compare created release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestConfigMapUpdate(t *testing.T) { @@ -224,21 +180,15 @@ func TestConfigMapUpdate(t *testing.T) { rel.Info.Status = common.StatusSuperseded // perform the update - if err := cfgmaps.Update(key, rel); err != nil { - t.Fatalf("Failed to update release: %s", err) - } + require.NoErrorf(t, cfgmaps.Update(key, rel), "Failed to update release") // fetch the updated release goti, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } + require.NoError(t, err, "Failed to get release with key %q", key) got := convertReleaserToV1(t, goti) // check release has actually been updated by comparing modified fields - if rel.Info.Status != got.Info.Status { - t.Errorf("Expected status %s, got status %s", rel.Info.Status.String(), got.Info.Status.String()) - } + assert.Equal(t, got.Info.Status, rel.Info.Status, "Expected status %s, got status %s", rel.Info.Status.String(), got.Info.Status.String()) } func TestConfigMapDelete(t *testing.T) { @@ -252,20 +202,12 @@ func TestConfigMapDelete(t *testing.T) { // perform the delete on a non-existent release _, err := cfgmaps.Delete("nonexistent") - if !errors.Is(err, ErrReleaseNotFound) { - t.Fatalf("Expected ErrReleaseNotFound: got {%v}", err) - } + require.ErrorIs(t, err, ErrReleaseNotFound) // perform the delete rls, err := cfgmaps.Delete(key) - if err != nil { - t.Fatalf("Failed to delete release with key %q: %s", key, err) - } - if !reflect.DeepEqual(rel, rls) { - t.Errorf("Expected {%v}, got {%v}", rel, rls) - } + require.NoError(t, err, "Failed to delete release with key %q", key) + assert.Equalf(t, rel, rls, "Expected {%v}, got {%v}", rel, rls) _, err = cfgmaps.Get(key) - if !errors.Is(err, ErrReleaseNotFound) { - t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err) - } + assert.ErrorIs(t, err, ErrReleaseNotFound) } diff --git a/pkg/storage/driver/driver.go b/pkg/storage/driver/driver.go index 6efd1dbaa..a7d194d69 100644 --- a/pkg/storage/driver/driver.go +++ b/pkg/storage/driver/driver.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "errors" diff --git a/pkg/storage/driver/labels_test.go b/pkg/storage/driver/labels_test.go index 81e561c15..34f01be79 100644 --- a/pkg/storage/driver/labels_test.go +++ b/pkg/storage/driver/labels_test.go @@ -14,10 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "testing" + + "github.com/stretchr/testify/require" ) func TestLabelsMatch(t *testing.T) { @@ -42,8 +44,12 @@ func TestLabelsMatch(t *testing.T) { } for _, tt := range tests { - if !tt.set1.match(tt.set2) && tt.expect { - t.Fatalf("Expected match '%s'\n", tt.desc) - } + t.Run(tt.desc, func(t *testing.T) { + if tt.expect { + require.True(t, tt.set1.match(tt.set2)) + } else { + require.False(t, tt.set1.match(tt.set2)) + } + }) } } diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index 6040daf59..c0eff3cf9 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -18,9 +18,9 @@ package driver import ( "fmt" - "reflect" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/release" @@ -29,9 +29,8 @@ import ( ) func TestMemoryName(t *testing.T) { - if mem := NewMemory(); mem.Name() != MemoryDriverName { - t.Errorf("Expected name to be %q, got %q", MemoryDriverName, mem.Name()) - } + mem := NewMemory() + assert.Equalf(t, MemoryDriverName, mem.Name(), "Expected name to be %q, got %q", MemoryDriverName, mem.Name()) } func TestMemoryCreate(t *testing.T) { @@ -66,13 +65,12 @@ func TestMemoryCreate(t *testing.T) { for _, tt := range tests { key := testKey(tt.rls.Name, tt.rls.Version) rls := tt.rls + err := ts.Create(key, rls) - if err := ts.Create(key, rls); err != nil { - if !tt.err { - t.Fatalf("failed to create %q: %s", tt.desc, err) - } - } else if tt.err { - t.Fatalf("Did not get expected error for %q\n", tt.desc) + if tt.err { + require.Error(t, err, "Did not get expected error for %q\n", tt.desc) + } else { + require.NoError(t, err, "failed to create %q", tt.desc) } } } @@ -93,12 +91,11 @@ func TestMemoryGet(t *testing.T) { ts := tsFixtureMemory(t) for _, tt := range tests { ts.SetNamespace(tt.namespace) - if _, err := ts.Get(tt.key); err != nil { - if !tt.err { - t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) - } - } else if tt.err { - t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key) + _, err := ts.Get(tt.key) + if tt.err { + require.Error(t, err, "Did not get expected error for %q '%s'\n", tt.desc, tt.key) + } else { + require.NoError(t, err, "Failed %q to get '%s'", tt.desc, tt.key) } } } @@ -113,12 +110,8 @@ func TestMemoryList(t *testing.T) { return rls.Info.Status == common.StatusDeployed }) // check - if err != nil { - t.Errorf("Failed to list deployed releases: %s", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d", len(dpl)) - } + require.NoError(t, err, "Failed to list deployed releases") + assert.Len(t, dpl, 2, "Expected 2 deployed") // list all superseded releases ssd, err := ts.List(func(rel release.Releaser) bool { @@ -126,12 +119,8 @@ func TestMemoryList(t *testing.T) { return rls.Info.Status == common.StatusSuperseded }) // check - if err != nil { - t.Errorf("Failed to list superseded releases: %s", err) - } - if len(ssd) != 6 { - t.Errorf("Expected 6 superseded, got %d", len(ssd)) - } + require.NoError(t, err, "Failed to list superseded releases") + assert.Len(t, ssd, 6, "Expected 6 superseded") // list all deleted releases del, err := ts.List(func(rel release.Releaser) bool { @@ -139,12 +128,8 @@ func TestMemoryList(t *testing.T) { return rls.Info.Status == common.StatusUninstalled }) // check - if err != nil { - t.Errorf("Failed to list deleted releases: %s", err) - } - if len(del) != 0 { - t.Errorf("Expected 0 deleted, got %d", len(del)) - } + require.NoError(t, err, "Failed to list deleted releases") + assert.Empty(t, del, "Expected 0 deleted, got %d", len(del)) } func TestMemoryQuery(t *testing.T) { @@ -172,13 +157,9 @@ func TestMemoryQuery(t *testing.T) { for _, tt := range tests { ts.SetNamespace(tt.namespace) l, err := ts.Query(tt.lbs) - if err != nil { - t.Fatalf("Failed to query: %s\n", err) - } + require.NoError(t, err, "Failed to query") - if tt.xlen != len(l) { - t.Fatalf("Expected %d results, actual %d\n", tt.xlen, len(l)) - } + require.Equal(t, len(l), tt.xlen, "Expected %d results, actual %d\n", tt.xlen, len(l)) } } @@ -217,23 +198,18 @@ func TestMemoryUpdate(t *testing.T) { ts := tsFixtureMemory(t) for _, tt := range tests { - if err := ts.Update(tt.key, tt.rls); err != nil { - if !tt.err { - t.Fatalf("Failed %q: %s\n", tt.desc, err) - } - continue - } else if tt.err { - t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key) - } + err := ts.Update(tt.key, tt.rls) - ts.SetNamespace(tt.rls.Namespace) - r, err := ts.Get(tt.key) - if err != nil { - t.Fatalf("Failed to get: %s\n", err) - } + if tt.err { + require.Error(t, err, "Did not get expected error for %q '%s'\n", tt.desc, tt.key) + } else { + require.NoError(t, err, "Failed %q", tt.desc) + + ts.SetNamespace(tt.rls.Namespace) - if !reflect.DeepEqual(r, tt.rls) { - t.Fatalf("Expected %v, actual %v\n", tt.rls, r) + r, err := ts.Get(tt.key) + require.NoError(t, err, "Failed to get") + require.Equalf(t, r, tt.rls, "Expected %v, actual %v\n", tt.rls, r) } } } @@ -256,9 +232,7 @@ func TestMemoryDelete(t *testing.T) { ts := tsFixtureMemory(t) ts.SetNamespace("") start, err := ts.Query(map[string]string{"status": "deployed"}) - if err != nil { - t.Errorf("Query failed: %s", err) - } + require.NoError(t, err, "Query failed") startLen := len(start) for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { @@ -280,13 +254,9 @@ func TestMemoryDelete(t *testing.T) { // Make sure that the deleted records are gone. ts.SetNamespace("") end, err := ts.Query(map[string]string{"status": "deployed"}) - if err != nil { - t.Errorf("Query failed: %s", err) - } - endLen := len(end) + require.NoError(t, err, "Query failed") - if startLen-2 != endLen { - t.Errorf("expected end to be %d instead of %d", startLen-2, endLen) + if !assert.Len(t, end, startLen-2) { for _, ee := range end { rac, err := release.NewAccessor(ee) require.NoError(t, err, "unable to get release accessor") diff --git a/pkg/storage/driver/mock_test.go b/pkg/storage/driver/mock_test.go index e62b02f43..c366d106d 100644 --- a/pkg/storage/driver/mock_test.go +++ b/pkg/storage/driver/mock_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "context" @@ -24,6 +24,7 @@ import ( sqlmock "github.com/DATA-DOG/go-sqlmock" sq "github.com/Masterminds/squirrel" "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -74,10 +75,7 @@ func tsFixtureMemory(t *testing.T) *Memory { mem := NewMemory() for _, tt := range hs { - err := mem.Create(testKey(tt.Name, tt.Version), tt) - if err != nil { - t.Fatalf("Test setup failed to create: %s\n", err) - } + require.NoError(t, mem.Create(testKey(tt.Name, tt.Version), tt), "Test setup failed to create") } return mem } @@ -108,9 +106,7 @@ func (mock *MockConfigMapsInterface) Init(t *testing.T, releases ...*rspb.Releas objkey := testKey(rls.Name, rls.Version) cfgmap, err := newConfigMapsObject(objkey, rls, nil) - if err != nil { - t.Fatalf("Failed to create configmap: %s", err) - } + require.NoError(t, err, "Failed to create configmap") mock.objects[objkey] = cfgmap } } @@ -196,9 +192,7 @@ func (mock *MockSecretsInterface) Init(t *testing.T, releases ...*rspb.Release) objkey := testKey(rls.Name, rls.Version) secret, err := newSecretsObject(objkey, rls, nil) - if err != nil { - t.Fatalf("Failed to create secret: %s", err) - } + require.NoError(t, err, "Failed to create secret") mock.objects[objkey] = secret } } @@ -262,9 +256,7 @@ func (mock *MockSecretsInterface) Delete(_ context.Context, name string, _ metav func newTestFixtureSQL(t *testing.T, _ ...*rspb.Release) (*SQL, sqlmock.Sqlmock) { t.Helper() sqlDB, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("error when opening stub database connection: %v", err) - } + require.NoError(t, err, "error when opening stub database connection") sqlxDB := sqlx.NewDb(sqlDB, "sqlmock") return &SQL{ diff --git a/pkg/storage/driver/records.go b/pkg/storage/driver/records.go index 6b4efef3a..f78b76b8b 100644 --- a/pkg/storage/driver/records.go +++ b/pkg/storage/driver/records.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "sort" diff --git a/pkg/storage/driver/records_test.go b/pkg/storage/driver/records_test.go index 24e4ccb4e..22d54e6cc 100644 --- a/pkg/storage/driver/records_test.go +++ b/pkg/storage/driver/records_test.go @@ -14,12 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( - "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "helm.sh/helm/v4/pkg/release/common" ) @@ -50,10 +52,11 @@ func TestRecordsAdd(t *testing.T) { } for _, tt := range tests { - if err := rs.Add(tt.rec); err != nil { - if !tt.ok { - t.Fatalf("failed: %q: %s\n", tt.desc, err) - } + err := rs.Add(tt.rec) + if !tt.ok { + require.NoError(t, err, "failed: %q:", tt.desc) + } else { + require.Error(t, err) } } } @@ -77,23 +80,18 @@ func TestRecordsRemove(t *testing.T) { startLen := rs.Len() for _, tt := range tests { - if r := rs.Remove(tt.key); r == nil { - if !tt.ok { - t.Fatalf("Failed to %q (key = %s). Expected nil, got %v", - tt.desc, - tt.key, - r, - ) - } + r := rs.Remove(tt.key) + if tt.ok { + require.Nil(t, r, "Failed to %q (key = %s). Expected nil, got %v", tt.desc, tt.key, r) + } else { + require.NotNil(t, r) } } // We expect the total number of records will be less now than there were // when we started. endLen := rs.Len() - if endLen >= startLen { - t.Errorf("expected ending length %d to be less than starting length %d", endLen, startLen) - } + assert.Lessf(t, endLen, startLen, "expected ending length %d to be less than starting length %d", endLen, startLen) } func TestRecordsRemoveAt(t *testing.T) { @@ -102,14 +100,10 @@ func TestRecordsRemoveAt(t *testing.T) { newRecord("rls-a.v2", releaseStub("rls-a", 2, "default", common.StatusDeployed)), }) - if len(rs) != 2 { - t.Fatal("Expected len=2 for mock") - } + require.Len(t, rs, 2, "Expected len=2 for mock") rs.Remove("rls-a.v1") - if len(rs) != 1 { - t.Fatalf("Expected length of rs to be 1, got %d", len(rs)) - } + require.Len(t, rs, 1, "Expected length of rs to be 1, got %d", len(rs)) } func TestRecordsGet(t *testing.T) { @@ -137,9 +131,7 @@ func TestRecordsGet(t *testing.T) { for _, tt := range tests { got := rs.Get(tt.key) - if !reflect.DeepEqual(tt.rec, got) { - t.Fatalf("Expected %v, got %v", tt.rec, got) - } + require.Equal(t, tt.rec, got, "Expected %v, got %v", tt.rec, got) } } @@ -168,9 +160,7 @@ func TestRecordsIndex(t *testing.T) { for _, tt := range tests { got, _ := rs.Index(tt.key) - if got != tt.sort { - t.Fatalf("Expected %d, got %d", tt.sort, got) - } + require.Equal(t, tt.sort, got, "Expected %d, got %d", tt.sort, got) } } @@ -199,9 +189,7 @@ func TestRecordsExists(t *testing.T) { for _, tt := range tests { got := rs.Exists(tt.key) - if got != tt.ok { - t.Fatalf("Expected %t, got %t", tt.ok, got) - } + require.Equal(t, tt.ok, got, "Expected %t, got %t", tt.ok, got) } } @@ -233,8 +221,6 @@ func TestRecordsReplace(t *testing.T) { for _, tt := range tests { got := rs.Replace(tt.key, tt.rec) - if !reflect.DeepEqual(tt.expected, got) { - t.Fatalf("Expected %v, got %v", tt.expected, got) - } + require.Equalf(t, tt.expected, got, "Expected %v, got %v", tt.expected, got) } } diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index 5e12684df..a1f3e94fc 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "context" diff --git a/pkg/storage/driver/secrets_test.go b/pkg/storage/driver/secrets_test.go index a11ec4380..b53f17ad9 100644 --- a/pkg/storage/driver/secrets_test.go +++ b/pkg/storage/driver/secrets_test.go @@ -16,10 +16,10 @@ package driver import ( "encoding/base64" "encoding/json" - "errors" - "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" "helm.sh/helm/v4/pkg/release" @@ -29,9 +29,7 @@ import ( func TestSecretName(t *testing.T) { c := newTestFixtureSecrets(t) - if c.Name() != SecretsDriverName { - t.Errorf("Expected name to be %q, got %q", SecretsDriverName, c.Name()) - } + assert.Equal(t, SecretsDriverName, c.Name(), "Expected name to be %q, got %q", SecretsDriverName, c.Name()) } func TestSecretGet(t *testing.T) { @@ -45,13 +43,9 @@ func TestSecretGet(t *testing.T) { // get release with key got, err := secrets.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } + require.NoError(t, err, "Failed to get release") // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestUNcompressedSecretGet(t *testing.T) { @@ -63,13 +57,9 @@ func TestUNcompressedSecretGet(t *testing.T) { // Create a test fixture which contains an uncompressed release secret, err := newSecretsObject(key, rel, nil) - if err != nil { - t.Fatalf("Failed to create secret: %s", err) - } + require.NoError(t, err, "Failed to create secret") b, err := json.Marshal(rel) - if err != nil { - t.Fatalf("Failed to marshal release: %s", err) - } + require.NoError(t, err, "Failed to marshal release") secret.Data["release"] = []byte(base64.StdEncoding.EncodeToString(b)) var mock MockSecretsInterface mock.objects = map[string]*v1.Secret{key: secret} @@ -77,13 +67,9 @@ func TestUNcompressedSecretGet(t *testing.T) { // get release with key got, err := secrets.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } + require.NoError(t, err, "Failed to get release") // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestSecretList(t *testing.T) { @@ -102,12 +88,8 @@ func TestSecretList(t *testing.T) { return rls.Info.Status == common.StatusUninstalled }) // check - if err != nil { - t.Errorf("Failed to list deleted: %s", err) - } - if len(del) != 2 { - t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) - } + require.NoError(t, err, "Failed to list deleted") + assert.Len(t, del, 2, "Expected 2 deleted") // list all deployed releases dpl, err := secrets.List(func(rel release.Releaser) bool { @@ -115,12 +97,8 @@ func TestSecretList(t *testing.T) { return rls.Info.Status == common.StatusDeployed }) // check - if err != nil { - t.Errorf("Failed to list deployed: %s", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d", len(dpl)) - } + require.NoError(t, err, "Failed to list deployed") + assert.Len(t, dpl, 2, "Expected 2 deployed") // list all superseded releases ssd, err := secrets.List(func(rel release.Releaser) bool { @@ -128,22 +106,12 @@ func TestSecretList(t *testing.T) { return rls.Info.Status == common.StatusSuperseded }) // check - if err != nil { - t.Errorf("Failed to list superseded: %s", err) - } - if len(ssd) != 2 { - t.Errorf("Expected 2 superseded, got %d", len(ssd)) - } + require.NoError(t, err, "Failed to list superseded") + require.Len(t, ssd, 2, "Expected 2 superseded") // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) - _, ok := rls.Labels["name"] - if !ok { - t.Fatalf("Expected 'name' label in results, actual %v", rls.Labels) - } - _, ok = rls.Labels["key1"] - if !ok { - t.Fatalf("Expected 'key1' label in results, actual %v", rls.Labels) - } + require.Contains(t, rls.Labels, "name", "Expected 'name' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "key1", "Expected 'key1' label in results, actual %v", rls.Labels) } func TestSecretQuery(t *testing.T) { @@ -157,17 +125,11 @@ func TestSecretQuery(t *testing.T) { }...) rls, err := secrets.Query(map[string]string{"status": "deployed"}) - if err != nil { - t.Fatalf("Failed to query: %s", err) - } - if len(rls) != 2 { - t.Fatalf("Expected 2 results, actual %d", len(rls)) - } + require.NoError(t, err, "Failed to query") + require.Len(t, rls, 2, "Expected 2 results, actual %d", len(rls)) _, err = secrets.Query(map[string]string{"name": "notExist"}) - if !errors.Is(err, ErrReleaseNotFound) { - t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err) - } + assert.ErrorIs(t, err, ErrReleaseNotFound) } func TestSecretCreate(t *testing.T) { @@ -180,20 +142,14 @@ func TestSecretCreate(t *testing.T) { rel := releaseStub(name, vers, namespace, common.StatusDeployed) // store the release in a secret - if err := secrets.Create(key, rel); err != nil { - t.Fatalf("Failed to create release with key %q: %s", key, err) - } + require.NoErrorf(t, secrets.Create(key, rel), "Failed to create release with key %q", key) // get the release back got, err := secrets.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } + require.NoError(t, err, "Failed to get release with key %q", key) // compare created release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%v}, got {%v}", rel, got) - } + assert.Equalf(t, rel, got, "Expected {%v}, got {%v}", rel, got) } func TestSecretUpdate(t *testing.T) { @@ -209,21 +165,15 @@ func TestSecretUpdate(t *testing.T) { rel.Info.Status = common.StatusSuperseded // perform the update - if err := secrets.Update(key, rel); err != nil { - t.Fatalf("Failed to update release: %s", err) - } + require.NoErrorf(t, secrets.Update(key, rel), "Failed to update release") // fetch the updated release goti, err := secrets.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } + require.NoError(t, err, "Failed to get release with key %q", key) got := convertReleaserToV1(t, goti) // check release has actually been updated by comparing modified fields - if rel.Info.Status != got.Info.Status { - t.Errorf("Expected status %s, got status %s", rel.Info.Status.String(), got.Info.Status.String()) - } + assert.Equal(t, got.Info.Status, rel.Info.Status, "Expected status %s, got status %s", rel.Info.Status.String(), got.Info.Status.String()) } func TestSecretDelete(t *testing.T) { @@ -237,20 +187,12 @@ func TestSecretDelete(t *testing.T) { // perform the delete on a non-existing release _, err := secrets.Delete("nonexistent") - if !errors.Is(err, ErrReleaseNotFound) { - t.Fatalf("Expected ErrReleaseNotFound, got: {%v}", err) - } + require.ErrorIs(t, err, ErrReleaseNotFound, "Expected ErrReleaseNotFound") // perform the delete rls, err := secrets.Delete(key) - if err != nil { - t.Fatalf("Failed to delete release with key %q: %s", key, err) - } - if !reflect.DeepEqual(rel, rls) { - t.Errorf("Expected {%v}, got {%v}", rel, rls) - } + require.NoError(t, err, "Failed to delete release with key %q", key) + assert.Equalf(t, rel, rls, "Expected {%v}, got {%v}", rel, rls) _, err = secrets.Get(key) - if !errors.Is(err, ErrReleaseNotFound) { - t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err) - } + assert.ErrorIs(t, err, ErrReleaseNotFound) } diff --git a/pkg/storage/driver/sql.go b/pkg/storage/driver/sql.go index 88d24123d..85e6cbd3f 100644 --- a/pkg/storage/driver/sql.go +++ b/pkg/storage/driver/sql.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "fmt" diff --git a/pkg/storage/driver/sql_test.go b/pkg/storage/driver/sql_test.go index 6044ce3c6..044e9df7b 100644 --- a/pkg/storage/driver/sql_test.go +++ b/pkg/storage/driver/sql_test.go @@ -24,6 +24,8 @@ import ( sqlmock "github.com/DATA-DOG/go-sqlmock" migrate "github.com/rubenv/sql-migrate" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/release" "helm.sh/helm/v4/pkg/release/common" @@ -59,9 +61,7 @@ func (recentUnixTimestampArgument) Match(value driver.Value) bool { func TestSQLName(t *testing.T) { sqlDriver, _ := newTestFixtureSQL(t) - if sqlDriver.Name() != SQLDriverName { - t.Errorf("Expected name to be %s, got %s", SQLDriverName, sqlDriver.Name()) - } + assert.Equal(t, SQLDriverName, sqlDriver.Name(), "Expected name to be %s, got %s", SQLDriverName, sqlDriver.Name()) } func TestSQLGet(t *testing.T) { @@ -97,17 +97,10 @@ func TestSQLGet(t *testing.T) { mockGetReleaseCustomLabels(mock, key, namespace, rel.Labels) got, err := sqlDriver.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %v", err) - } + require.NoError(t, err, "Failed to get release") - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected release {%v}, got {%v}", rel, got) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + assert.Equalf(t, rel, got, "Expected release {%v}, got {%v}", rel, got) + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSQLList(t *testing.T) { @@ -157,12 +150,8 @@ func TestSQLList(t *testing.T) { return rls.Info.Status == common.StatusUninstalled }) // check - if err != nil { - t.Errorf("Failed to list deleted: %v", err) - } - if len(del) != 2 { - t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) - } + require.NoError(t, err, "Failed to list deleted") + assert.Len(t, del, 2, "Expected 2 deleted") // list all deployed releases dpl, err := sqlDriver.List(func(rel release.Releaser) bool { @@ -170,12 +159,8 @@ func TestSQLList(t *testing.T) { return rls.Info.Status == common.StatusDeployed }) // check - if err != nil { - t.Errorf("Failed to list deployed: %v", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d:\n%v\n", len(dpl), dpl) - } + require.NoError(t, err, "Failed to list deployed") + assert.Len(t, dpl, 2, "Expected 2 deployed") // list all superseded releases ssd, err := sqlDriver.List(func(rel release.Releaser) bool { @@ -183,27 +168,14 @@ func TestSQLList(t *testing.T) { return rls.Info.Status == common.StatusSuperseded }) // check - if err != nil { - t.Errorf("Failed to list superseded: %v", err) - } - if len(ssd) != 2 { - t.Errorf("Expected 2 superseded, got %d:\n%v\n", len(ssd), ssd) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + require.NoError(t, err, "Failed to list superseded") + require.Len(t, ssd, 2, "Expected 2 superseded") + require.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") // Check if release having both system and custom labels, this is needed to ensure that selector filtering would work. rls := convertReleaserToV1(t, ssd[0]) - _, ok := rls.Labels["name"] - if !ok { - t.Fatalf("Expected 'name' label in results, actual %v", rls.Labels) - } - _, ok = rls.Labels["key1"] - if !ok { - t.Fatalf("Expected 'key1' label in results, actual %v", rls.Labels) - } + require.Contains(t, rls.Labels, "name", "Expected 'name' label in results, actual %v", rls.Labels) + require.Contains(t, rls.Labels, "key1", "Expected 'key1' label in results, actual %v", rls.Labels) } func TestSqlCreate(t *testing.T) { @@ -254,13 +226,8 @@ func TestSqlCreate(t *testing.T) { } mock.ExpectCommit() - if err := sqlDriver.Create(key, rel); err != nil { - t.Fatalf("failed to create release with key %s: %v", key, err) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + require.NoErrorf(t, sqlDriver.Create(key, rel), "failed to create release with key %s", key) + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSqlCreateAlreadyExists(t *testing.T) { @@ -315,13 +282,8 @@ func TestSqlCreateAlreadyExists(t *testing.T) { ).RowsWillBeClosed() mock.ExpectRollback() - if err := sqlDriver.Create(key, rel); err == nil { - t.Fatalf("failed to create release with key %s: %v", key, err) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + require.Errorf(t, sqlDriver.Create(key, rel), "failed to create release with key %s", key) + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSqlUpdate(t *testing.T) { @@ -352,13 +314,8 @@ func TestSqlUpdate(t *testing.T) { WithArgs(body, rel.Name, int(rel.Version), rel.Info.Status.String(), sqlReleaseDefaultOwner, recentUnixTimestamp(), key, namespace). WillReturnResult(sqlmock.NewResult(0, 1)) - if err := sqlDriver.Update(key, rel); err != nil { - t.Fatalf("failed to update release with key %s: %v", key, err) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + require.NoErrorf(t, sqlDriver.Update(key, rel), "failed to update release with key %s", key) + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSqlQuery(t *testing.T) { @@ -448,41 +405,25 @@ func TestSqlQuery(t *testing.T) { mockGetReleaseCustomLabels(mock, "", deployedRelease.Namespace, deployedRelease.Labels) _, err := sqlDriver.Query(labelSetUnknown) - if err == nil { - t.Errorf("Expected error {%v}, got nil", ErrReleaseNotFound) - } else if !errors.Is(err, ErrReleaseNotFound) { - t.Fatalf("failed to query for unknown smug-pigeon release: %v", err) - } + require.Errorf(t, err, "Expected error {%v}, got nil", ErrReleaseNotFound) + require.ErrorIsf(t, err, ErrReleaseNotFound, "failed to query for unknown smug-pigeon release") results, err := sqlDriver.Query(labelSetDeployed) - if err != nil { - t.Fatalf("failed to query for deployed smug-pigeon release: %v", err) - } + require.NoError(t, err, "failed to query for deployed smug-pigeon release") for _, res := range results { - if !reflect.DeepEqual(res, deployedRelease) { - t.Errorf("Expected release {%v}, got {%v}", deployedRelease, res) - } + assert.Equalf(t, res, deployedRelease, "Expected release {%v}, got {%v}", deployedRelease, res) } results, err = sqlDriver.Query(labelSetAll) - if err != nil { - t.Fatalf("failed to query release history for smug-pigeon: %v", err) - } - - if len(results) != 2 { - t.Errorf("expected a resultset of size 2, got %d", len(results)) - } + require.NoError(t, err, "failed to query release history for smug-pigeon") + assert.Len(t, results, 2, "expected a resultset of size 2") for _, res := range results { - if !reflect.DeepEqual(res, deployedRelease) && !reflect.DeepEqual(res, supersededRelease) { - t.Errorf("Expected release {%v} or {%v}, got {%v}", deployedRelease, supersededRelease, res) - } + assert.False(t, !reflect.DeepEqual(res, deployedRelease) && !reflect.DeepEqual(res, supersededRelease), "Expected release {%v} or {%v}, got {%v}", deployedRelease, supersededRelease, res) } - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } + assert.NoErrorf(t, mock.ExpectationsWereMet(), "sql expectations weren't met") } func TestSqlDelete(t *testing.T) { @@ -544,16 +485,12 @@ func TestSqlDelete(t *testing.T) { mock.ExpectCommit() deletedRelease, err := sqlDriver.Delete(key) - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("sql expectations weren't met: %v", err) - } - if err != nil { - t.Fatalf("failed to delete release with key %q: %v", key, err) - } + require.NoError(t, err) + err = mock.ExpectationsWereMet() + assert.NoErrorf(t, err, "sql expectations weren't met") + require.NoError(t, err, "failed to delete release with key %q", key) - if !reflect.DeepEqual(rel, deletedRelease) { - t.Errorf("Expected release {%v}, got {%v}", rel, deletedRelease) - } + assert.Equalf(t, rel, deletedRelease, "Expected release {%v}, got {%v}", rel, deletedRelease) } func mockGetReleaseCustomLabels(mock sqlmock.Sqlmock, key string, namespace string, labels map[string]string) { @@ -621,8 +558,6 @@ func TestSqlCheckAppliedMigrations(t *testing.T) { ExpectQuery(""). WillReturnRows(rows) mock.ExpectCommit() - if sqlDriver.checkAlreadyApplied(c.migrationsToApply) != c.expectedResult { - t.Errorf("Test case: %v, Expected: %v, Have: %v, Explanation: %v", i, c.expectedResult, !c.expectedResult, c.errorExplanation) - } + assert.Equal(t, c.expectedResult, sqlDriver.checkAlreadyApplied(c.migrationsToApply), "Test case: %v, Expected: %v, Have: %v, Explanation: %v", i, c.expectedResult, !c.expectedResult, c.errorExplanation) } } diff --git a/pkg/storage/driver/util.go b/pkg/storage/driver/util.go index 4bc48db23..08c38585c 100644 --- a/pkg/storage/driver/util.go +++ b/pkg/storage/driver/util.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package driver // import "helm.sh/helm/v4/pkg/storage/driver" +package driver import ( "bytes" diff --git a/pkg/storage/driver/util_test.go b/pkg/storage/driver/util_test.go index d16043924..5dda3cd1f 100644 --- a/pkg/storage/driver/util_test.go +++ b/pkg/storage/driver/util_test.go @@ -14,14 +14,14 @@ limitations under the License. package driver import ( - "reflect" "testing" + + "github.com/stretchr/testify/assert" ) func TestGetSystemLabel(t *testing.T) { - if output := GetSystemLabels(); !reflect.DeepEqual(systemLabels, output) { - t.Errorf("Expected {%v}, got {%v}", systemLabels, output) - } + output := GetSystemLabels() + assert.Equalf(t, systemLabels, output, "Expected {%v}, got {%v}", systemLabels, output) } func TestIsSystemLabel(t *testing.T) { @@ -32,9 +32,8 @@ func TestIsSystemLabel(t *testing.T) { "NaMe": false, } for label, result := range tests { - if output := isSystemLabel(label); output != result { - t.Errorf("Output %t not equal to expected %t", output, result) - } + output := isSystemLabel(label) + assert.Equalf(t, output, result, "Output %t not equal to expected %t", output, result) } } @@ -68,9 +67,8 @@ func TestFilterSystemLabels(t *testing.T) { }}, } for _, test := range tests { - if output := filterSystemLabels(test[0]); !reflect.DeepEqual(test[1], output) { - t.Errorf("Expected {%v}, got {%v}", test[1], output) - } + output := filterSystemLabels(test[0]) + assert.Equalf(t, test[1], output, "Expected {%v}, got {%v}", test[1], output) } } @@ -101,8 +99,7 @@ func TestContainsSystemLabels(t *testing.T) { }, false}, } for _, test := range tests { - if output := ContainsSystemLabels(test.input); !reflect.DeepEqual(test.output, output) { - t.Errorf("Expected {%v}, got {%v}", test.output, output) - } + output := ContainsSystemLabels(test.input) + assert.Equalf(t, test.output, output, "Expected {%v}, got {%v}", test.output, output) } } diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index d5d2ea317..1d7fb9103 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package storage // import "helm.sh/helm/v4/pkg/storage" +package storage import ( "errors" diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 32f926e08..58cb56776 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -14,16 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -package storage // import "helm.sh/helm/v4/pkg/storage" +package storage import ( "context" "errors" - "fmt" "log/slog" - "reflect" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v4/pkg/release" @@ -42,16 +41,14 @@ func TestStorageCreate(t *testing.T) { Version: 1, }.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") + require.NoError(t, storage.Create(rls), "StoreRelease") // fetch the release res, err := storage.Get(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "QueryRelease") + require.NoError(t, err, "QueryRelease") // verify the fetched and created release are the same - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %v, got %v", rls, res) - } + require.Equalf(t, rls, res, "Expected %v, got %v", rls, res) } func TestStorageUpdate(t *testing.T) { @@ -65,20 +62,18 @@ func TestStorageUpdate(t *testing.T) { Status: common.StatusDeployed, }.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") + require.NoError(t, storage.Create(rls), "StoreRelease") // modify the release rls.Info.Status = common.StatusUninstalled - assertErrNil(t.Fatal, storage.Update(rls), "UpdateRelease") + require.NoError(t, storage.Update(rls), "UpdateRelease") // retrieve the updated release res, err := storage.Get(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "QueryRelease") + require.NoError(t, err, "QueryRelease") // verify updated and fetched releases are the same. - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %v, got %v", rls, res) - } + require.Equalf(t, rls, res, "Expected %v, got %v", rls, res) } func TestStorageDelete(t *testing.T) { @@ -95,34 +90,26 @@ func TestStorageDelete(t *testing.T) { Version: 2, }.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") - assertErrNil(t.Fatal, storage.Create(rls2), "StoreRelease") + require.NoError(t, storage.Create(rls), "StoreRelease") + require.NoError(t, storage.Create(rls2), "StoreRelease") // delete the release res, err := storage.Delete(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "DeleteRelease") + require.NoError(t, err, "DeleteRelease") // verify updated and fetched releases are the same. - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %v, got %v", rls, res) - } + require.Equalf(t, rls, res, "Expected %v, got %v", rls, res) hist, err := storage.History(rls.Name) - if err != nil { - t.Errorf("unexpected error: %s", err) - } + require.NoError(t, err) rhist, err := releaseListToV1List(hist) require.NoError(t, err) // We have now deleted one of the two records. - if len(rhist) != 1 { - t.Errorf("expected 1 record for deleted release version, got %d", len(hist)) - } + assert.Len(t, rhist, 1, "expected 1 record for deleted release version, got %d", len(hist)) - if rhist[0].Version != 2 { - t.Errorf("Expected version to be 2, got %d", rhist[0].Version) - } + assert.Equal(t, 2, rhist[0].Version, "Expected version to be 2, got %d", rhist[0].Version) } func TestStorageList(t *testing.T) { @@ -141,13 +128,13 @@ func TestStorageList(t *testing.T) { rls6 := ReleaseTestData{Name: "happy-liger", Status: common.StatusUninstalled}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'rls0'") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'rls1'") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'rls2'") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'rls3'") - assertErrNil(t.Fatal, storage.Create(rls4), "Storing release 'rls4'") - assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'rls5'") - assertErrNil(t.Fatal, storage.Create(rls6), "Storing release 'rls6'") + require.NoError(t, storage.Create(rls0), "Storing release 'rls0'") + require.NoError(t, storage.Create(rls1), "Storing release 'rls1'") + require.NoError(t, storage.Create(rls2), "Storing release 'rls2'") + require.NoError(t, storage.Create(rls3), "Storing release 'rls3'") + require.NoError(t, storage.Create(rls4), "Storing release 'rls4'") + require.NoError(t, storage.Create(rls5), "Storing release 'rls5'") + require.NoError(t, storage.Create(rls6), "Storing release 'rls6'") } var listTests = []struct { @@ -164,14 +151,9 @@ func TestStorageList(t *testing.T) { for _, tt := range listTests { list, err := tt.ListFunc() - assertErrNil(t.Fatal, err, tt.Description) + require.NoError(t, err, tt.Description) // verify the count of releases returned - if len(list) != tt.NumExpected { - t.Errorf("ListReleases(%s): expected %d, actual %d", - tt.Description, - tt.NumExpected, - len(list)) - } + assert.Len(t, list, tt.NumExpected, "ListReleases(%s): expected %d, actual %d", tt.Description, tt.NumExpected, len(list)) } } @@ -190,32 +172,24 @@ func TestStorageDeployed(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusDeployed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() rls, err := storage.Last(name) - if err != nil { - t.Fatalf("Failed to query for deployed release: %s\n", err) - } + require.NoError(t, err, "Failed to query for deployed release") rel, err := releaserToV1Release(rls) require.NoError(t, err) - switch { - case rls == nil: - t.Fatal("Release is nil") - case rel.Name != name: - t.Fatalf("Expected release name %q, actual %q\n", name, rel.Name) - case rel.Version != vers: - t.Fatalf("Expected release version %d, actual %d\n", vers, rel.Version) - case rel.Info.Status != common.StatusDeployed: - t.Fatalf("Expected release status 'DEPLOYED', actual %s\n", rel.Info.Status.String()) - } + require.NotNil(t, rls, "Release is nil") + require.Equal(t, name, rel.Name, "Expected release name %q, actual %q\n", name, rel.Name) + require.Equal(t, vers, rel.Version, "Expected release version %d, actual %d\n", vers, rel.Version) + require.Equal(t, common.StatusDeployed, rel.Info.Status, "Expected release status 'DEPLOYED', actual %s\n", rel.Info.Status.String()) } func TestStorageDeployedWithCorruption(t *testing.T) { @@ -233,32 +207,24 @@ func TestStorageDeployedWithCorruption(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 2, Status: common.StatusDeployed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() rls, err := storage.Deployed(name) - if err != nil { - t.Fatalf("Failed to query for deployed release: %s\n", err) - } + require.NoError(t, err, "Failed to query for deployed release") rel, err := releaserToV1Release(rls) require.NoError(t, err) - switch { - case rls == nil: - t.Fatal("Release is nil") - case rel.Name != name: - t.Fatalf("Expected release name %q, actual %q\n", name, rel.Name) - case rel.Version != vers: - t.Fatalf("Expected release version %d, actual %d\n", vers, rel.Version) - case rel.Info.Status != common.StatusDeployed: - t.Fatalf("Expected release status 'DEPLOYED', actual %s\n", rel.Info.Status.String()) - } + require.NotNil(t, rls, "Release is nil") + require.Equal(t, name, rel.Name, "Expected release name %q, actual %q\n", name, rel.Name) + require.Equal(t, vers, rel.Version, "Expected release version %d, actual %d\n", vers, rel.Version) + require.Equal(t, common.StatusDeployed, rel.Info.Status, "Expected release status 'DEPLOYED', actual %s\n", rel.Info.Status.String()) } func TestStorageHistory(t *testing.T) { @@ -275,21 +241,17 @@ func TestStorageHistory(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusDeployed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() h, err := storage.History(name) - if err != nil { - t.Fatalf("Failed to query for release history (%q): %s\n", name, err) - } - if len(h) != 4 { - t.Fatalf("Release history (%q) is empty\n", name) - } + require.NoError(t, err, "Failed to query for release history (%q)", name) + require.Len(t, h, 4, "Release history (%q) is empty\n", name) } var errMaxHistoryMockDriverSomethingHappened = errors.New("something happened") @@ -336,16 +298,14 @@ func TestMaxHistoryErrorHandling(t *testing.T) { rls1 := ReleaseTestData{Name: name, Version: 1, Status: common.StatusSuperseded}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Driver.Create(makeKey(rls1.Name, rls1.Version), rls1), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Driver.Create(makeKey(rls1.Name, rls1.Version), rls1), "Storing release 'angry-bird' (v1)") } setup() rls2 := ReleaseTestData{Name: name, Version: 2, Status: common.StatusSuperseded}.ToRelease() wantErr := errMaxHistoryMockDriverSomethingHappened gotErr := storage.Create(rls2) - if !errors.Is(gotErr, wantErr) { - t.Fatalf("Storing release 'angry-bird' (v2) should return the error %#v, but returned %#v", wantErr, gotErr) - } + require.ErrorIs(t, gotErr, wantErr, "Storing release 'angry-bird' (v2) should return the error %#v, but returned %#v", wantErr, gotErr) } func TestStorageRemoveLeastRecent(t *testing.T) { @@ -365,43 +325,40 @@ func TestStorageRemoveLeastRecent(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusDeployed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() // Because we have not set a limit, we expect 4. expect := 4 - if hist, err := storage.History(name); err != nil { - t.Fatal(err) - } else if len(hist) != expect { - t.Fatalf("expected %d items in history, got %d", expect, len(hist)) - } + hist, err := storage.History(name) + require.NoError(t, err) + require.Equal(t, len(hist), expect, "expected %d items in history, got %d", expect, len(hist)) storage.MaxHistory = 3 rls5 := ReleaseTestData{Name: name, Version: 5, Status: common.StatusDeployed}.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'angry-bird' (v5)") + require.NoError(t, storage.Create(rls5), "Storing release 'angry-bird' (v5)") // On inserting the 5th record, we expect two records to be pruned from history. - hist, err := storage.History(name) + hist, err = storage.History(name) require.NoError(t, err) rhist, err := releaseListToV1List(hist) require.NoError(t, err) - if len(rhist) != storage.MaxHistory { + if !assert.Len(t, rhist, storage.MaxHistory) { for _, item := range rhist { t.Logf("%s %v", item.Name, item.Version) } - t.Fatalf("expected %d items in history, got %d", storage.MaxHistory, len(rhist)) } + require.Len(t, rhist, storage.MaxHistory) // We expect the existing records to be 3, 4, and 5. for i, item := range rhist { v := item.Version - if expect := i + 3; v != expect { - t.Errorf("Expected release %d, got %d", expect, v) - } + expect := i + 3 + assert.Equalf(t, v, expect, "Expected release %d, got %d", expect, v) } } @@ -420,29 +377,28 @@ func TestStorageDoNotDeleteDeployed(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusFailed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() rls5 := ReleaseTestData{Name: name, Version: 5, Status: common.StatusFailed}.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'angry-bird' (v5)") + require.NoError(t, storage.Create(rls5), "Storing release 'angry-bird' (v5)") // On inserting the 5th record, we expect a total of 3 releases, but we expect version 2 // (the only deployed release), to still exist hist, err := storage.History(name) - if err != nil { - t.Fatal(err) - } else if len(hist) != storage.MaxHistory { + require.NoError(t, err) + if !assert.Len(t, hist, storage.MaxHistory) { rhist, err := releaseListToV1List(hist) require.NoError(t, err) for _, item := range rhist { t.Logf("%s %v", item.Name, item.Version) } - t.Fatalf("expected %d items in history, got %d", storage.MaxHistory, len(rhist)) } + require.Len(t, hist, storage.MaxHistory) expectedVersions := map[int]bool{ 2: true, @@ -453,9 +409,7 @@ func TestStorageDoNotDeleteDeployed(t *testing.T) { rhist, err := releaseListToV1List(hist) require.NoError(t, err) for _, item := range rhist { - if !expectedVersions[item.Version] { - t.Errorf("Release version %d, found when not expected", item.Version) - } + assert.Truef(t, expectedVersions[item.Version], "Release version %d, found when not expected", item.Version) } } @@ -473,25 +427,21 @@ func TestStorageLast(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusFailed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") } setup() h, err := storage.Last(name) - if err != nil { - t.Fatalf("Failed to query for release history (%q): %s\n", name, err) - } + require.NoError(t, err, "Failed to query for release history (%q)", name) rel, err := releaserToV1Release(h) require.NoError(t, err) - if rel.Version != 4 { - t.Errorf("Expected revision 4, got %d", rel.Version) - } + assert.Equal(t, 4, rel.Version, "Expected revision 4, got %d", rel.Version) } // TestUpgradeInitiallyFailedReleaseWithHistoryLimit tests a case when there are no deployed release yet, but history limit has been @@ -511,47 +461,34 @@ func TestUpgradeInitiallyFailedReleaseWithHistoryLimit(t *testing.T) { rls3 := ReleaseTestData{Name: name, Version: 4, Status: common.StatusFailed}.ToRelease() // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + require.NoError(t, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + require.NoError(t, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + require.NoError(t, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + require.NoError(t, storage.Create(rls3), "Storing release 'angry-bird' (v4)") hist, err := storage.History(name) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) wantHistoryLen := 4 - if len(hist) != wantHistoryLen { - t.Fatalf("expected history of release %q to contain %d releases, got %d", name, wantHistoryLen, len(hist)) - } + require.Len(t, hist, wantHistoryLen, "expected history of release %q to contain %d releases, got %d", name, wantHistoryLen, len(hist)) } setup() rls5 := ReleaseTestData{Name: name, Version: 5, Status: common.StatusFailed}.ToRelease() - err := storage.Create(rls5) - if err != nil { - t.Fatalf("Failed to create a new release version: %s", err) - } + require.NoError(t, storage.Create(rls5), "Failed to create a new release version") hist, err := storage.History(name) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + require.NoError(t, err) rhist, err := releaseListToV1List(hist) require.NoError(t, err) for i, rel := range rhist { wantVersion := i + 2 - if rel.Version != wantVersion { - t.Fatalf("Expected history release %d version to equal %d, got %d", i+1, wantVersion, rel.Version) - } + require.Equal(t, wantVersion, rel.Version, "Expected history release %d version to equal %d, got %d", i+1, wantVersion, rel.Version) wantStatus := common.StatusFailed - if rel.Info.Status != wantStatus { - t.Fatalf("Expected history release %d status to equal %q, got %q", i+1, wantStatus, rel.Info.Status) - } + require.Equal(t, wantStatus, rel.Info.Status, "Expected history release %d status to equal %q, got %q", i+1, wantStatus, rel.Info.Status) } } @@ -573,21 +510,13 @@ func (test ReleaseTestData) ToRelease() *rspb.Release { } } -func assertErrNil(eh func(args ...any), err error, message string) { - if err != nil { - eh(fmt.Sprintf("%s: %q", message, err)) - } -} - func TestStorageGetsLoggerFromDriver(t *testing.T) { d := driver.NewMemory() l := &mockSLogHandler{} d.SetLogger(l) s := Init(d) _, _ = s.Get("doesnt-matter", 123) - if !l.Called { - t.Fatal("Expected storage to use driver's logger, but it did not") - } + require.True(t, l.Called, "Expected storage to use driver's logger, but it did not") } type mockSLogHandler struct { diff --git a/pkg/strvals/literal_parser_test.go b/pkg/strvals/literal_parser_test.go index 6c22a732b..94e0c6050 100644 --- a/pkg/strvals/literal_parser_test.go +++ b/pkg/strvals/literal_parser_test.go @@ -16,7 +16,6 @@ limitations under the License. package strvals import ( - "bytes" "fmt" "strings" "testing" @@ -279,29 +278,21 @@ func TestParseLiteral(t *testing.T) { } for _, tt := range cases { - got, err := ParseLiteral(tt.str) - if err != nil { - if !tt.err { - require.NoError(t, err, tt.str) - } - continue - } - - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } - - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) + t.Run(tt.str, func(t *testing.T) { + got, err := ParseLiteral(tt.str) + if tt.err { + require.Error(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) - y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + assert.YAMLEq(t, string(y1), string(y2), tt.str) + } + }) } } @@ -386,17 +377,13 @@ func TestParseLiteralInto(t *testing.T) { } for _, tt := range tests { - if err := ParseLiteralInto(tt.input, tt.got); err != nil { - require.NoError(t, err) - } + require.NoError(t, ParseLiteralInto(tt.input, tt.got)) if tt.err { assert.Fail(t, "Expected error. Got nil", tt.input) } if tt.input2 != "" { - if err := ParseLiteralInto(tt.input2, tt.got); err != nil { - require.NoError(t, err) - } + require.NoError(t, ParseLiteralInto(tt.input2, tt.got)) if tt.err { assert.Fail(t, "Expected error. Got nil", tt.input2) } @@ -406,13 +393,9 @@ func TestParseLiteralInto(t *testing.T) { require.NoError(t, err) y2, err := yaml.Marshal(tt.got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + require.NoError(t, err, "Error serializing parsed value") - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.input) - } + assert.YAMLEq(t, string(y1), string(y2), tt.input) } } @@ -447,29 +430,23 @@ func TestParseLiteralNestedLevels(t *testing.T) { } for _, tt := range tests { - got, err := ParseLiteral(tt.str) - if err != nil { + t.Run(tt.str, func(t *testing.T) { + got, err := ParseLiteral(tt.str) if tt.err { + require.Error(t, err) if tt.errStr != "" { require.EqualError(t, err, tt.errStr) } - continue - } - require.NoError(t, err, tt.str) - } - - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } - - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) - y2, err := yaml.Marshal(got) - require.NoError(t, err, "Error serializing parsed value") + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + assert.YAMLEq(t, string(y1), string(y2), tt.str) + } + }) } } diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index d74e46986..be3b1e71b 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -238,16 +238,16 @@ func (t *parser) key(data map[string]any, nestedNameLevel int) (reterr error) { // End of key. Consume =, Get value. // FIXME: Get value list first vl, e := t.valList() - switch e { - case nil: + switch { + case e == nil: set(data, string(k), vl) return nil - case io.EOF: + case errors.Is(e, io.EOF): set(data, string(k), "") return e - case ErrNotList: + case errors.Is(e, ErrNotList): rs, e := t.val() - if e != nil && e != io.EOF { + if e != nil && !errors.Is(e, io.EOF) { return e } v, e := t.reader(rs) @@ -370,14 +370,14 @@ func (t *parser) listItem(list []any, i, nestedNameLevel int) ([]any, error) { return list, err } vl, e := t.valList() - switch e { - case nil: + switch { + case e == nil: return setIndex(list, i, vl) - case io.EOF: + case errors.Is(e, io.EOF): return setIndex(list, i, "") - case ErrNotList: + case errors.Is(e, ErrNotList): rs, e := t.val() - if e != nil && e != io.EOF { + if e != nil && !errors.Is(e, io.EOF) { return list, e } v, e := t.reader(rs) @@ -476,7 +476,7 @@ func (t *parser) valList() ([]any, error) { for { switch rs, last, err := runesUntil(t.sc, stop); { case err != nil: - if err == io.EOF { + if errors.Is(err, io.EOF) { err = errors.New("list must terminate with '}'") } return list, err diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index e68bc4e19..c6c866711 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -16,8 +16,8 @@ limitations under the License. package strvals import ( - "bytes" "fmt" + "strconv" "strings" "testing" @@ -383,50 +383,37 @@ func TestParseSet(t *testing.T) { } for _, tt := range tests { - got, err := Parse(tt.str) - if err != nil { + t.Run(tt.str, func(t *testing.T) { + got, err := Parse(tt.str) if tt.err { - continue - } - require.NoError(t, err, tt.str) - } - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } - - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) - y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + require.Error(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) + y2, err := yaml.Marshal(got) + if err != nil { + require.NoError(t, err, "Error serializing parsed value") + } - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + assert.YAMLEq(t, string(y1), string(y2), tt.str) + } + }) } for _, tt := range testsString { - got, err := ParseString(tt.str) - if err != nil { + t.Run(tt.str, func(t *testing.T) { + got, err := ParseString(tt.str) if tt.err { - continue + require.Error(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2)) } - require.NoError(t, err, tt.str) - } - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } - - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) - y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } - - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + }) } } @@ -511,33 +498,26 @@ func TestParseInto(t *testing.T) { err: false, }, } - for _, tt := range tests { - if err := ParseInto(tt.input, tt.got); err != nil { - require.NoError(t, err) - } - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.input) - } - - if tt.input2 != "" { - if err := ParseInto(tt.input2, tt.got); err != nil { - require.NoError(t, err) - } + for i, tt := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + require.NoError(t, ParseInto(tt.input, tt.got)) if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.input2) + assert.Fail(t, "Expected error. Got nil", tt.input) } - } - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) - y2, err := yaml.Marshal(tt.got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + if tt.input2 != "" { + require.NoError(t, ParseInto(tt.input2, tt.got)) + if tt.err { + assert.Fail(t, "Expected error. Got nil", tt.input2) + } + } - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.input) - } + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) + y2, err := yaml.Marshal(tt.got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2), tt.input) + }) } } @@ -564,13 +544,8 @@ func TestParseIntoString(t *testing.T) { y1, err := yaml.Marshal(expect) require.NoError(t, err) y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } - - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), input) - } + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2), input) } func TestParseJSON(t *testing.T) { @@ -650,27 +625,19 @@ func TestParseJSON(t *testing.T) { }, } for _, tt := range tests { - if err := ParseJSON(tt.input, tt.got); err != nil { + t.Run(tt.input, func(t *testing.T) { + err := ParseJSON(tt.input, tt.got) if tt.err { - continue + require.Error(t, err) + } else { + require.NoError(t, err) + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err, "Error serializing expected value") + y2, err := yaml.Marshal(tt.got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2)) } - require.NoError(t, err, tt.input) - } - if tt.err { - require.Fail(t, "Expected error. Got nil", tt.input) - } - y1, err := yaml.Marshal(tt.expect) - if err != nil { - require.NoError(t, err, "Error serializing expected value") - } - y2, err := yaml.Marshal(tt.got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } - - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.input) - } + }) } } @@ -693,14 +660,10 @@ func TestParseFile(t *testing.T) { y1, err := yaml.Marshal(expect) require.NoError(t, err) - y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), input) - } + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2), input) } func TestParseIntoFile(t *testing.T) { @@ -725,13 +688,9 @@ func TestParseIntoFile(t *testing.T) { y1, err := yaml.Marshal(expect) require.NoError(t, err) y2, err := yaml.Marshal(got) - if err != nil { - require.NoError(t, err, "Error serializing parsed value") - } + require.NoError(t, err, "Error serializing parsed value") - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), input) - } + assert.YAMLEq(t, string(y1), string(y2), input) } func TestToYAML(t *testing.T) { @@ -775,27 +734,23 @@ func TestParseSetNestedLevels(t *testing.T) { } for _, tt := range tests { - got, err := Parse(tt.str) - if err != nil { + t.Run(tt.str, func(t *testing.T) { + got, err := Parse(tt.str) if tt.err { + require.Error(t, err) if tt.errStr != "" { require.EqualError(t, err, tt.errStr) } - continue - } - require.NoError(t, err, tt.str) - } - if tt.err { - assert.Fail(t, "Expected error. Got nil", tt.str) - } + } else { + require.NoError(t, err) - y1, err := yaml.Marshal(tt.expect) - require.NoError(t, err) - y2, err := yaml.Marshal(got) - require.NoError(t, err, "Error serializing parsed value") + y1, err := yaml.Marshal(tt.expect) + require.NoError(t, err) - if !bytes.Equal(y1, y2) { - assert.Equal(t, string(y1), string(y2), tt.str) - } + y2, err := yaml.Marshal(got) + require.NoError(t, err, "Error serializing parsed value") + assert.YAMLEq(t, string(y1), string(y2), tt.str) + } + }) } }