mirror of https://github.com/helm/helm
Signed-off-by: Terry Howe <terrylhowe@gmail.com>pull/31590/head
parent
dbd07fa16c
commit
6453933519
@ -0,0 +1,313 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestOCIRegistryGHCREndToEnd tests push and pull against real GitHub Container Registry (GHCR)
|
||||
// This test requires HELM_RUN_E2E=true, GHCR_USER and GHCR_TOKEN environment variables to be set
|
||||
func TestOCIRegistryGHCREndToEnd(t *testing.T) {
|
||||
if os.Getenv("HELM_RUN_E2E") == "" {
|
||||
t.Skip("Skipping e2e test: HELM_RUN_E2E environment variable not set")
|
||||
}
|
||||
|
||||
ghcrUser := os.Getenv("GHCR_USER")
|
||||
ghcrToken := os.Getenv("GHCR_TOKEN")
|
||||
|
||||
if ghcrUser == "" || ghcrToken == "" {
|
||||
t.Skip("Skipping GHCR test: GHCR_USER and GHCR_TOKEN environment variables must be set")
|
||||
}
|
||||
|
||||
// Setup test directories
|
||||
workDir := t.TempDir()
|
||||
registryConfigPath := filepath.Join(workDir, "config.json")
|
||||
contentCache := t.TempDir()
|
||||
|
||||
// GHCR registry configuration
|
||||
ghcrRegistry := "ghcr.io/terryhowe"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
chartPath string
|
||||
chartName string
|
||||
chartVersion string
|
||||
repoPath string
|
||||
pullArgs string
|
||||
expectPullFile string
|
||||
expectPullDir bool
|
||||
}{
|
||||
{
|
||||
name: "Push and pull basic chart to GHCR",
|
||||
chartPath: "testdata/testcharts/test-0.1.0.tgz",
|
||||
chartName: "test",
|
||||
chartVersion: "0.1.0",
|
||||
repoPath: "helm-e2e-test",
|
||||
expectPullFile: "./test-0.1.0.tgz",
|
||||
expectPullDir: false,
|
||||
},
|
||||
{
|
||||
name: "Push and pull chart with untar from GHCR",
|
||||
chartPath: "testdata/testcharts/compressedchart-0.1.0.tgz",
|
||||
chartName: "compressedchart",
|
||||
chartVersion: "0.1.0",
|
||||
repoPath: "helm-e2e-test",
|
||||
pullArgs: "--untar",
|
||||
expectPullFile: "./compressedchart",
|
||||
expectPullDir: true,
|
||||
},
|
||||
{
|
||||
name: "Push and pull chart with hyphens to GHCR",
|
||||
chartPath: "testdata/testcharts/compressedchart-with-hyphens-0.1.0.tgz",
|
||||
chartName: "compressedchart-with-hyphens",
|
||||
chartVersion: "0.1.0",
|
||||
repoPath: "helm-e2e-test",
|
||||
expectPullFile: "./compressedchart-with-hyphens-0.1.0.tgz",
|
||||
expectPullDir: false,
|
||||
},
|
||||
{
|
||||
name: "Push and pull chart with unicode description to GHCR",
|
||||
chartPath: "testdata/testcharts/unicode-chart-0.1.0.tgz",
|
||||
chartName: "unicode-chart",
|
||||
chartVersion: "0.1.0",
|
||||
repoPath: "helm-e2e-test",
|
||||
expectPullFile: "./unicode-chart-0.1.0.tgz",
|
||||
expectPullDir: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create a fresh pull directory for this test
|
||||
pullDir := filepath.Join(workDir, tt.name)
|
||||
if err := os.MkdirAll(pullDir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Construct the push remote (repository path only)
|
||||
pushRemote := fmt.Sprintf("oci://%s/%s", ghcrRegistry, tt.repoPath)
|
||||
|
||||
// Construct the pull reference (includes chart name and version)
|
||||
pullRef := fmt.Sprintf("oci://%s/%s/%s:%s",
|
||||
ghcrRegistry,
|
||||
tt.repoPath,
|
||||
tt.chartName,
|
||||
tt.chartVersion)
|
||||
|
||||
// Push the chart to GHCR
|
||||
pushCmd := fmt.Sprintf("push %s %s --registry-config %s --username %s --password %s",
|
||||
tt.chartPath,
|
||||
pushRemote,
|
||||
registryConfigPath,
|
||||
ghcrUser,
|
||||
ghcrToken)
|
||||
|
||||
t.Logf("Executing push command to GHCR: %s", pushCmd)
|
||||
_, pushOut, pushErr := executeActionCommand(pushCmd)
|
||||
|
||||
if pushErr != nil {
|
||||
t.Fatalf("push to GHCR failed: %v\nOutput: %s", pushErr, pushOut)
|
||||
}
|
||||
t.Logf("Push to GHCR successful. Output: %s", pushOut)
|
||||
|
||||
// Pull the chart back from GHCR
|
||||
pullCmd := fmt.Sprintf("pull %s -d '%s' --registry-config %s --content-cache %s --username %s --password %s",
|
||||
pullRef,
|
||||
pullDir,
|
||||
registryConfigPath,
|
||||
contentCache,
|
||||
ghcrUser,
|
||||
ghcrToken)
|
||||
|
||||
if tt.pullArgs != "" {
|
||||
pullCmd += " " + tt.pullArgs
|
||||
}
|
||||
|
||||
t.Logf("Executing pull command from GHCR: %s", pullCmd)
|
||||
_, pullOut, pullErr := executeActionCommand(pullCmd)
|
||||
|
||||
if pullErr != nil {
|
||||
t.Fatalf("pull from GHCR failed: %v\nOutput: %s", pullErr, pullOut)
|
||||
}
|
||||
t.Logf("Pull from GHCR successful. Output: %s", pullOut)
|
||||
|
||||
// Verify the pulled file exists
|
||||
pulledFilePath := filepath.Join(pullDir, tt.expectPullFile)
|
||||
fi, err := os.Stat(pulledFilePath)
|
||||
if err != nil {
|
||||
t.Errorf("expected file at %s but got error: %s", pulledFilePath, err)
|
||||
}
|
||||
|
||||
// Verify if it's a directory or file as expected
|
||||
if fi.IsDir() != tt.expectPullDir {
|
||||
t.Errorf("expected directory=%t, but got directory=%t", tt.expectPullDir, fi.IsDir())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestOCIRegistryGHCRAuthFailure tests authentication failures with real GHCR
|
||||
// This test requires HELM_RUN_E2E=true and GHCR_USER environment variable to be set
|
||||
func TestOCIRegistryGHCRAuthFailure(t *testing.T) {
|
||||
if os.Getenv("HELM_RUN_E2E") == "" {
|
||||
t.Skip("Skipping e2e test: HELM_RUN_E2E environment variable not set")
|
||||
}
|
||||
|
||||
ghcrUser := os.Getenv("GHCR_USER")
|
||||
|
||||
if ghcrUser == "" {
|
||||
t.Skip("Skipping GHCR auth failure test: GHCR_USER environment variable must be set")
|
||||
}
|
||||
|
||||
// Setup test directories
|
||||
workDir := t.TempDir()
|
||||
registryConfigPath := filepath.Join(workDir, "config.json")
|
||||
|
||||
// GHCR registry configuration
|
||||
ghcrRegistry := "ghcr.io/terryhowe"
|
||||
|
||||
t.Run("Fail push with invalid credentials to GHCR", func(t *testing.T) {
|
||||
pushRemote := fmt.Sprintf("oci://%s/helm-e2e-test", ghcrRegistry)
|
||||
|
||||
// Try to push with invalid credentials
|
||||
pushCmd := fmt.Sprintf("push testdata/testcharts/test-0.1.0.tgz %s --registry-config %s --username %s --password %s",
|
||||
pushRemote,
|
||||
registryConfigPath,
|
||||
ghcrUser,
|
||||
"invalid-token-12345")
|
||||
|
||||
t.Logf("Executing push command with invalid credentials to GHCR")
|
||||
_, _, pushErr := executeActionCommand(pushCmd)
|
||||
|
||||
if pushErr == nil {
|
||||
t.Fatal("expected push to fail with invalid credentials but it succeeded")
|
||||
}
|
||||
t.Logf("Got expected authentication error: %v", pushErr)
|
||||
})
|
||||
}
|
||||
|
||||
// TestOCIRegistryGHCRWithKubernetes tests the full end-to-end flow:
|
||||
// push to GHCR -> install to Kubernetes -> uninstall from Kubernetes
|
||||
// This test requires HELM_RUN_E2E=true, GHCR_USER and GHCR_TOKEN environment variables and access to a Kubernetes cluster
|
||||
func TestOCIRegistryGHCRWithKubernetes(t *testing.T) {
|
||||
if os.Getenv("HELM_RUN_E2E") == "" {
|
||||
t.Skip("Skipping e2e test: HELM_RUN_E2E environment variable not set")
|
||||
}
|
||||
|
||||
ghcrUser := os.Getenv("GHCR_USER")
|
||||
ghcrToken := os.Getenv("GHCR_TOKEN")
|
||||
|
||||
if ghcrUser == "" || ghcrToken == "" {
|
||||
t.Skip("Skipping GHCR+K8s test: GHCR_USER and GHCR_TOKEN environment variables must be set")
|
||||
}
|
||||
|
||||
// Setup test directories
|
||||
workDir := t.TempDir()
|
||||
registryConfigPath := filepath.Join(workDir, "config.json")
|
||||
|
||||
// GHCR registry configuration
|
||||
ghcrRegistry := "ghcr.io/terryhowe"
|
||||
testNamespace := "helm-e2e-test"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
chartPath string
|
||||
chartName string
|
||||
chartVersion string
|
||||
repoPath string
|
||||
releaseName string
|
||||
}{
|
||||
{
|
||||
name: "Install basic chart from GHCR to K8s",
|
||||
chartPath: "testdata/testcharts/test-0.1.0.tgz",
|
||||
chartName: "test",
|
||||
chartVersion: "0.1.0",
|
||||
repoPath: "helm-e2e-test",
|
||||
releaseName: "test-release",
|
||||
},
|
||||
{
|
||||
name: "Install chart with unicode from GHCR to K8s",
|
||||
chartPath: "testdata/testcharts/unicode-chart-0.1.0.tgz",
|
||||
chartName: "unicode-chart",
|
||||
chartVersion: "0.1.0",
|
||||
repoPath: "helm-e2e-test",
|
||||
releaseName: "unicode-release",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Construct the push remote (repository path only)
|
||||
pushRemote := fmt.Sprintf("oci://%s/%s", ghcrRegistry, tt.repoPath)
|
||||
|
||||
// Construct the OCI reference for installation
|
||||
ociRef := fmt.Sprintf("oci://%s/%s/%s",
|
||||
ghcrRegistry,
|
||||
tt.repoPath,
|
||||
tt.chartName)
|
||||
|
||||
// Push the chart to GHCR
|
||||
pushCmd := fmt.Sprintf("push %s %s --registry-config %s --username %s --password %s",
|
||||
tt.chartPath,
|
||||
pushRemote,
|
||||
registryConfigPath,
|
||||
ghcrUser,
|
||||
ghcrToken)
|
||||
|
||||
t.Logf("Pushing chart to GHCR: %s", tt.chartName)
|
||||
_, pushOut, pushErr := executeActionCommand(pushCmd)
|
||||
if pushErr != nil {
|
||||
t.Fatalf("push to GHCR failed: %v\nOutput: %s", pushErr, pushOut)
|
||||
}
|
||||
t.Logf("Push successful")
|
||||
|
||||
// Install the chart to Kubernetes
|
||||
installCmd := fmt.Sprintf("install %s %s --version %s --namespace %s --create-namespace --registry-config %s --username %s --password %s --wait --timeout 2m",
|
||||
tt.releaseName,
|
||||
ociRef,
|
||||
tt.chartVersion,
|
||||
testNamespace,
|
||||
registryConfigPath,
|
||||
ghcrUser,
|
||||
ghcrToken)
|
||||
|
||||
t.Logf("Installing chart to Kubernetes: %s", tt.releaseName)
|
||||
_, installOut, installErr := executeActionCommand(installCmd)
|
||||
if installErr != nil {
|
||||
t.Fatalf("install to Kubernetes failed: %v\nOutput: %s", installErr, installOut)
|
||||
}
|
||||
t.Logf("Install successful. Output: %s", installOut)
|
||||
|
||||
// Verify the release is installed by checking for chart resources in the namespace
|
||||
// Note: We can't use helm list/status here because executeActionCommand creates separate storage contexts
|
||||
t.Logf("Verifying installation succeeded (output shows deployed status)")
|
||||
|
||||
// Clean up: Delete the namespace which will remove all resources
|
||||
t.Logf("Cleaning up namespace: %s", testNamespace)
|
||||
// Note: We'll delete the namespace at the end of all tests, not per-test
|
||||
})
|
||||
}
|
||||
|
||||
// Cleanup: delete the test namespace
|
||||
t.Logf("Deleting test namespace: %s", testNamespace)
|
||||
// Using Go's os/exec would be better but for simplicity in tests we'll rely on the namespace being cleaned up manually
|
||||
// or by the next test run with --create-namespace
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
description: Test chart with unicode Kröpke 日本語 中文 한글
|
||||
name: unicode-chart
|
||||
version: 0.1.0
|
||||
@ -0,0 +1,3 @@
|
||||
Thank you for installing {{ .Chart.Name }}.
|
||||
|
||||
This chart includes unicode: Kröpke 日本語 中文 한글
|
||||
@ -0,0 +1,2 @@
|
||||
# Default values for unicode-chart
|
||||
replicaCount: 1
|
||||
Loading…
Reference in new issue