From 20078c431675b9ba0eacd56cb6523d23ff1633fb Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Fri, 18 Apr 2025 23:47:28 +0530 Subject: [PATCH 01/10] updated run_test.sh to install kmeshctl in e2e Signed-off-by: ravjot07 --- test/e2e/run_test.sh | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/e2e/run_test.sh b/test/e2e/run_test.sh index 78e362aad..413963a5c 100755 --- a/test/e2e/run_test.sh +++ b/test/e2e/run_test.sh @@ -211,6 +211,24 @@ function cleanup_docker_registry() { docker rm "${KIND_REGISTRY_NAME}" || echo "Failed to remove or no such registry '${KIND_REGISTRY_NAME}'." } +TMPBIN="${TMPBIN:-$(mktemp -d)/bin}" +mkdir -p "$TMPBIN" +export PATH="$PATH:$TMPBIN" + + +# Function to install kmeshctl into the test environment. +function install_kmeshctl() { + echo "Installing kmeshctl CLI into test environment..." + if [[ -f "$ROOT_DIR/kmeshctl" ]]; then + cp "$ROOT_DIR/kmeshctl" "$TMPBIN/" + echo "kmeshctl installed successfully in $TMPBIN." + else + echo "Error: kmeshctl binary not found in $ROOT_DIR. Please build it before running E2E tests." >&2 + return 1 + fi +} + + PARAMS=() while (( "$#" )); do @@ -272,8 +290,11 @@ if [[ -z "${SKIP_SETUP:-}" ]]; then fi if [[ -z "${SKIP_BUILD:-}" ]]; then - setup_kind_registry - build_and_push_images + setup_kind_registry + build_and_push_images + echo "Building kmeshctl CLI..." + make kmeshctl || { echo "Failed to build kmeshctl" >&2; exit 1; } + install_kmeshctl || { echo "Failed to install kmeshctl into PATH" >&2; exit 1; } fi kubectl config use-context "kind-$NAME" From 8ca5412589be9eb0d09e51dd66d91f3c5f68f864 Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Sat, 19 Apr 2025 00:15:24 +0530 Subject: [PATCH 02/10] test: added test for kmeshctl version Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 105 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 test/e2e/kmeshctl_test.go diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go new file mode 100644 index 000000000..5d6795d5a --- /dev/null +++ b/test/e2e/kmeshctl_test.go @@ -0,0 +1,105 @@ +//go:build integ +// +build integ + +/* + * Copyright The Kmesh 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 kmesh + +import ( + "encoding/json" + "os/exec" + "strings" + "testing" + "time" +) + +func runVersionCmd(args ...string) (string, error) { + cmdArgs := append([]string{"version"}, args...) + cmd := exec.Command("kmeshctl", cmdArgs...) + out, err := cmd.CombinedOutput() + return string(out), err +} + +func findKmeshPod(t *testing.T) string { + const ns = "kmesh-system" + const label = "app=kmesh" + cmd := exec.Command("kubectl", "-n", ns, "get", "pods", + "-l", label, "-o", "jsonpath={.items[0].metadata.name}") + out, err := cmd.Output() + if err != nil || len(out) == 0 { + list := exec.Command("kubectl", "-n", ns, "get", "pods", "-o", "wide") + all, _ := list.CombinedOutput() + t.Fatalf("could not find pod with label %q: %v\nPods:\n%s", label, err, string(all)) + } + name := strings.TrimSpace(string(out)) + t.Logf("Found Kmesh pod: %s", name) + return name +} + +func waitForPodRunning(t *testing.T, pod string) { + const ns = "kmesh-system" + const retries = 20 + const delay = 2 * time.Second + for i := 0; i < retries; i++ { + cmd := exec.Command("kubectl", "-n", ns, "get", "pod", pod, "-o", "jsonpath={.status.phase}") + out, err := cmd.Output() + if err == nil && strings.EqualFold(strings.TrimSpace(string(out)), "Running") { + t.Logf("Pod %s is Running", pod) + return + } + time.Sleep(delay) + } + t.Fatalf("pod %s did not become Running in time", pod) +} + +func TestKmeshctlVersion(t *testing.T) { + pod := findKmeshPod(t) + waitForPodRunning(t, pod) + + t.Run("client-and-daemon-summary", func(t *testing.T) { + out, err := runVersionCmd() + t.Logf("Output of 'kmeshctl version':\n%s", out) + if err != nil { + t.Fatalf("version command failed: %v", err) + } + if !strings.Contains(out, "client version:") { + t.Errorf("expected 'client version:' in output, got:\n%s", out) + } + if !strings.Contains(out, "kmesh-daemon version:") { + t.Errorf("expected 'kmesh-daemon version:' in output, got:\n%s", out) + } + }) + + t.Run("daemon-version-json", func(t *testing.T) { + out, err := runVersionCmd(pod) + t.Logf("Output of 'kmeshctl version %s':\n%s", pod, out) + if err != nil { + t.Fatalf("version command failed: %v", err) + } + var info struct { + GitVersion string `json:"GitVersion"` + GitCommit string `json:"GitCommit"` + } + if err := json.Unmarshal([]byte(out), &info); err != nil { + t.Fatalf("invalid JSON output: %v", err) + } + if info.GitVersion == "" || info.GitCommit == "" { + t.Errorf("expected non-empty GitVersion and GitCommit, got: %+v", info) + } + }) +} From d30a31888080f42e06ac4a8a96a94e0e67b449fe Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Sat, 19 Apr 2025 00:37:31 +0530 Subject: [PATCH 03/10] test: added test for kmeshctl Dump and accesslog Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 97 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go index 5d6795d5a..224b9bc56 100644 --- a/test/e2e/kmeshctl_test.go +++ b/test/e2e/kmeshctl_test.go @@ -103,3 +103,100 @@ func TestKmeshctlVersion(t *testing.T) { } }) } + +func runDumpCmd(args ...string) (string, error) { + cmdArgs := append([]string{"dump"}, args...) + cmd := exec.Command("kmeshctl", cmdArgs...) + out, err := cmd.CombinedOutput() + return string(out), err + } + +func TestKmeshctlDump(t *testing.T) { + pod := findKmeshPod(t) + waitForPodRunning(t, pod) + + + t.Run("kernel-native", func(t *testing.T) { + out, err := runDumpCmd(pod, "kernel-native") + t.Logf("Output of 'kmeshctl dump %s kernel-native':\n%s", pod, out) + if err != nil { + t.Fatalf("dump kernel-native failed: %v", err) + } + if strings.TrimSpace(out) == "" { + t.Errorf("expected non-empty output for kernel-native, got empty") + } + }) + + + t.Run("dual-engine", func(t *testing.T) { + out, err := runDumpCmd(pod, "dual-engine") + t.Logf("Output of 'kmeshctl dump %s dual-engine':\n%s", pod, out) + if err != nil { + t.Fatalf("dump dual-engine failed: %v", err) + } + if strings.TrimSpace(out) == "" { + t.Errorf("expected non-empty output for dual-engine, got empty") + } + }) + + + t.Run("invalid-mode", func(t *testing.T) { + out, err := runDumpCmd(pod, "invalid-mode") + t.Logf("Output of 'kmeshctl dump %s invalid-mode':\n%s", pod, out) + if err == nil { + t.Fatal("expected error for invalid mode, but command succeeded") + } + if !strings.Contains(out, "Argument must be 'kernel-native' or 'dual-engine'") { + t.Errorf("expected error message about valid modes, got:\n%s", out) + } + }) + } + + func runAccesslogCmd(args ...string) (string, error) { + cmdArgs := append([]string{"monitoring"}, args...) + cmd := exec.Command("kmeshctl", cmdArgs...) + out, err := cmd.CombinedOutput() + return string(out), err + } + + func TestKmeshctlAccesslog(t *testing.T) { + pod := findKmeshPod(t) + waitForPodRunning(t, pod) + + + t.Run("enable-on-pod", func(t *testing.T) { + out, err := runAccesslogCmd(pod, "--accesslog", "enable") + t.Logf("enable-on-pod output:\n%s", out) + if err != nil { + t.Fatalf("failed to enable accesslog on pod %s: %v", pod, err) + } + }) + + + t.Run("disable-on-pod", func(t *testing.T) { + out, err := runAccesslogCmd(pod, "--accesslog", "disable") + t.Logf("disable-on-pod output:\n%s", out) + if err != nil { + t.Fatalf("failed to disable accesslog on pod %s: %v", pod, err) + } + }) + + + t.Run("enable-cluster", func(t *testing.T) { + out, err := runAccesslogCmd("--accesslog", "enable") + t.Logf("enable-cluster output:\n%s", out) + if err != nil { + t.Fatalf("failed to enable accesslog cluster-wide: %v", err) + } + }) + + + t.Run("disable-cluster", func(t *testing.T) { + out, err := runAccesslogCmd("--accesslog", "disable") + t.Logf("disable-cluster output:\n%s", out) + if err != nil { + t.Fatalf("failed to disable accesslog cluster-wide: %v", err) + } + }) + } + \ No newline at end of file From 1eda40b6ce2b1164e714e5209579728b74a29ddf Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Sat, 19 Apr 2025 01:16:32 +0530 Subject: [PATCH 04/10] test: added test for kmeshctl log and secret Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 186 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go index 224b9bc56..e04b2ab5d 100644 --- a/test/e2e/kmeshctl_test.go +++ b/test/e2e/kmeshctl_test.go @@ -21,11 +21,20 @@ package kmesh import ( + "bufio" + "context" + "crypto/rand" + "encoding/hex" "encoding/json" + "fmt" "os/exec" "strings" "testing" "time" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kmesh.net/kmesh/ctl/utils" ) func runVersionCmd(args ...string) (string, error) { @@ -199,4 +208,181 @@ func TestKmeshctlDump(t *testing.T) { } }) } + + func verifyLogOutputHeaders(t *testing.T, output, expectedHeader string) { + scanner := bufio.NewScanner(strings.NewReader(output)) + found := false + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if strings.Contains(line, expectedHeader) { + found = true + break + } + } + if !found { + t.Errorf("Expected output to contain header %q but it did not. Full output:\n%s", expectedHeader, output) + } + } + + func TestKmeshctlLog(t *testing.T) { + podName := findKmeshPod(t) + waitForPodRunning(t, podName) + + t.Run("get-all-loggers", func(t *testing.T) { + output, err := getLogOutputs(podName) + if err != nil { + t.Fatalf("Failed to get logger names: %v, output: %s", err, output) + } + t.Logf("Output of 'kmeshctl log %s':\n%s", podName, output) + verifyLogOutputHeaders(t, output, "Existing Loggers:") + }) + + t.Run("get-default-logger-level", func(t *testing.T) { + output, err := getLogOutputs(podName, "default") + if err != nil { + t.Fatalf("Failed to get default logger level: %v, output: %s", err, output) + } + t.Logf("Output of 'kmeshctl log %s default':\n%s", podName, output) + if !strings.Contains(output, "Logger Name:") || !strings.Contains(output, "Logger Level:") { + t.Errorf("Expected output to contain 'Logger Name:' and 'Logger Level:', but got: %s", output) + } + }) + + + t.Run("set-default-logger-level", func(t *testing.T) { + output, err := getLogOutputs(podName, "--set", "default:debug") + if err != nil { + t.Fatalf("Failed to set default logger level: %v, output: %s", err, output) + } + t.Logf("Output of 'kmeshctl log %s --set default:debug':\n%s", podName, output) + output2, err := getLogOutputs(podName, "default") + if err != nil { + t.Fatalf("Failed to get default logger level after setting: %v, output: %s", err, output2) + } + t.Logf("Output of 'kmeshctl log %s default' after setting:\n%s", podName, output2) + if !strings.Contains(strings.ToLower(output2), "debug") { + t.Errorf("Expected default logger level to be 'debug', but output was: %s", output2) + } + }) + } + + type IpSecKey struct { + AeadKeyName string `json:"AeadKeyName"` + AeadKey []byte `json:"AeadKey"` + Length int `json:"Length"` + Spi int `json:"Spi"` + } + + + func waitForSecret(secretName, namespace string, timeout time.Duration) (*v1.Secret, error) { + clientset, err := utils.CreateKubeClient() + if err != nil { + return nil, fmt.Errorf("failed to create kube client: %v", err) + } + + + deadline := time.Now().Add(timeout) + for time.Now().Before(deadline) { + sec, err := clientset.Kube().CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + if err == nil { + return sec, nil + } + time.Sleep(2 * time.Second) + } + return nil, fmt.Errorf("timeout waiting for secret %q in namespace %q", secretName, namespace) + } + + func deleteSecret(secretName, namespace string) error { + clientset, err := utils.CreateKubeClient() + if err != nil { + return fmt.Errorf("failed to create kube client: %v", err) + } + _ = clientset.Kube().CoreV1().Secrets(namespace).Delete(context.TODO(), secretName, metav1.DeleteOptions{}) + return nil + } + + func generateRandomKey() (string, error) { + keyBytes := make([]byte, 36) + _, err := rand.Read(keyBytes) + if err != nil { + return "", fmt.Errorf("failed to generate random key: %v", err) + } + return hex.EncodeToString(keyBytes), nil + } + + + func TestKmeshctlSecret(t *testing.T) { + const secretName = "kmesh-ipsec" + const namespace = "kmesh-system" + + _ = deleteSecret(secretName, namespace) + t.Log("Deleted existing secret (if any)") + + + key1, err := generateRandomKey() + if err != nil { + t.Fatalf("failed to generate random key: %v", err) + } + t.Logf("Generated key1: %s", key1) + + + cmd := exec.Command("kmeshctl", "secret", "--key", key1) + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("failed to run kmeshctl secret command: %v, output: %s", err, string(output)) + } + t.Logf("Output of first 'kmeshctl secret' command: %s", string(output)) + + + sec, err := waitForSecret(secretName, namespace, 30*time.Second) + if err != nil { + t.Fatalf("failed to get created secret: %v", err) + } + + dataB64, exists := sec.Data["ipSec"] + if !exists { + t.Fatalf("secret %q does not contain key 'ipSec'", secretName) + } + + var ipSecKey IpSecKey + err = json.Unmarshal(dataB64, &ipSecKey) + if err != nil { + t.Fatalf("failed to unmarshal secret data: %v", err) + } + t.Logf("Created secret with SPI: %d", ipSecKey.Spi) + if ipSecKey.Spi != 1 { + t.Errorf("Expected SPI to be 1 on creation, got %d", ipSecKey.Spi) + } + + key2, err := generateRandomKey() + if err != nil { + t.Fatalf("failed to generate second random key: %v", err) + } + t.Logf("Generated key2: %s", key2) + cmd = exec.Command("kmeshctl", "secret", "--key", key2) + output, err = cmd.CombinedOutput() + if err != nil { + t.Fatalf("failed to run kmeshctl secret command for update: %v, output: %s", err, string(output)) + } + t.Logf("Output of second 'kmeshctl secret' command: %s", string(output)) + + + secUpdated, err := waitForSecret(secretName, namespace, 30*time.Second) + if err != nil { + t.Fatalf("failed to get updated secret: %v", err) + } + dataB64 = secUpdated.Data["ipSec"] + var ipSecKeyUpdated IpSecKey + err = json.Unmarshal(dataB64, &ipSecKeyUpdated) + if err != nil { + t.Fatalf("failed to unmarshal updated secret data: %v", err) + } + t.Logf("Updated secret with SPI: %d", ipSecKeyUpdated.Spi) + expectedSPI := ipSecKey.Spi + 1 + if ipSecKeyUpdated.Spi != expectedSPI { + t.Errorf("Expected updated SPI to be %d, but got %d", expectedSPI, ipSecKeyUpdated.Spi) + } + } + + \ No newline at end of file From f783cd2d45fa9d4b31fef6ab57eb9ebcb129adc1 Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Sat, 19 Apr 2025 01:35:12 +0530 Subject: [PATCH 05/10] minor changes Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go index e04b2ab5d..15729b415 100644 --- a/test/e2e/kmeshctl_test.go +++ b/test/e2e/kmeshctl_test.go @@ -208,6 +208,14 @@ func TestKmeshctlDump(t *testing.T) { } }) } + + func getLogOutputs(args ...string) (string, error) { + cmdArgs := append([]string{"log"}, args...) + cmd := exec.Command("kmeshctl", cmdArgs...) + output, err := cmd.CombinedOutput() + return string(output), err + } + func verifyLogOutputHeaders(t *testing.T, output, expectedHeader string) { scanner := bufio.NewScanner(strings.NewReader(output)) From 02633f86853eb9e32bf63e4906d9810e4a93d806 Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Sat, 19 Apr 2025 02:02:49 +0530 Subject: [PATCH 06/10] test: added test for kmeshctl authz Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 43 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go index 15729b415..a9a3f208b 100644 --- a/test/e2e/kmeshctl_test.go +++ b/test/e2e/kmeshctl_test.go @@ -392,5 +392,46 @@ func TestKmeshctlDump(t *testing.T) { } } + func runAuthzCmd(args ...string) (string, error) { + cmdArgs := append([]string{"authz"}, args...) + cmd := exec.Command("kmeshctl", cmdArgs...) + out, err := cmd.CombinedOutput() + return string(out), err +} - \ No newline at end of file +func TestKmeshctlAuthzEnableDisable(t *testing.T) { + pod := findKmeshPod(t) + waitForPodRunning(t, pod) + + t.Run("enable-cluster", func(t *testing.T) { + out, err := runAuthzCmd("enable") + t.Logf("Output of 'kmeshctl authz enable':\n%s", out) + if err != nil { + t.Fatalf("cluster-wide enable failed: %v", err) + } + }) + + t.Run("disable-cluster", func(t *testing.T) { + out, err := runAuthzCmd("disable") + t.Logf("Output of 'kmeshctl authz disable':\n%s", out) + if err != nil { + t.Fatalf("cluster-wide disable failed: %v", err) + } + }) + + t.Run("enable-pod", func(t *testing.T) { + out, err := runAuthzCmd("enable", pod) + t.Logf("Output of 'kmeshctl authz enable %s':\n%s", pod, out) + if err != nil { + t.Fatalf("per-pod enable failed: %v", err) + } + }) + + t.Run("disable-pod", func(t *testing.T) { + out, err := runAuthzCmd("disable", pod) + t.Logf("Output of 'kmeshctl authz disable %s':\n%s", pod, out) + if err != nil { + t.Fatalf("per-pod disable failed: %v", err) + } + }) +} \ No newline at end of file From 43d7bb7e6e075d1d6c0167fec9738bbc3bba8f86 Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Sat, 26 Apr 2025 01:19:22 +0530 Subject: [PATCH 07/10] Updated dump test Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 95 ++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go index a9a3f208b..cd1e67692 100644 --- a/test/e2e/kmeshctl_test.go +++ b/test/e2e/kmeshctl_test.go @@ -120,46 +120,61 @@ func runDumpCmd(args ...string) (string, error) { return string(out), err } -func TestKmeshctlDump(t *testing.T) { - pod := findKmeshPod(t) - waitForPodRunning(t, pod) - - - t.Run("kernel-native", func(t *testing.T) { - out, err := runDumpCmd(pod, "kernel-native") - t.Logf("Output of 'kmeshctl dump %s kernel-native':\n%s", pod, out) - if err != nil { - t.Fatalf("dump kernel-native failed: %v", err) - } - if strings.TrimSpace(out) == "" { - t.Errorf("expected non-empty output for kernel-native, got empty") - } - }) - - - t.Run("dual-engine", func(t *testing.T) { - out, err := runDumpCmd(pod, "dual-engine") - t.Logf("Output of 'kmeshctl dump %s dual-engine':\n%s", pod, out) - if err != nil { - t.Fatalf("dump dual-engine failed: %v", err) - } - if strings.TrimSpace(out) == "" { - t.Errorf("expected non-empty output for dual-engine, got empty") - } - }) - - - t.Run("invalid-mode", func(t *testing.T) { - out, err := runDumpCmd(pod, "invalid-mode") - t.Logf("Output of 'kmeshctl dump %s invalid-mode':\n%s", pod, out) - if err == nil { - t.Fatal("expected error for invalid mode, but command succeeded") - } - if !strings.Contains(out, "Argument must be 'kernel-native' or 'dual-engine'") { - t.Errorf("expected error message about valid modes, got:\n%s", out) - } - }) - } + func TestKmeshctlDump(t *testing.T) { + pod := findKmeshPod(t) + waitForPodRunning(t, pod) + + t.Run("kernel-native", func(t *testing.T) { + out, err := runDumpCmd(pod, "kernel-native") + t.Logf("Output of 'kmeshctl dump %s kernel-native':\n%s", pod, out) + + if strings.Contains(out, "Invalid Client Mode") { + t.Log("kernel-native not supported; got expected error") + return + } + if err != nil { + t.Fatalf("dump kernel-native failed: %v\n%s", err, out) + } + if !strings.Contains(out, `"workloads"`) { + t.Errorf("expected JSON to contain \"workloads\" array, got:\n%s", out) + } + if !strings.Contains(out, `"services"`) { + t.Errorf("expected JSON to contain \"services\" array, got:\n%s", out) + } + }) + + t.Run("dual-engine", func(t *testing.T) { + out, err := runDumpCmd(pod, "dual-engine") + t.Logf("Output of 'kmeshctl dump %s dual-engine':\n%s", pod, out) + if err != nil { + t.Fatalf("dump dual-engine failed: %v\n%s", err, out) + } + if !strings.Contains(out, `"workloads"`) { + t.Errorf("expected JSON to contain \"workloads\" array, got:\n%s", out) + } + if !strings.Contains(out, `"services"`) { + t.Errorf("expected JSON to contain \"services\" array, got:\n%s", out) + } + }) + + t.Run("invalid-mode", func(t *testing.T) { + out, err := runDumpCmd(pod, "invalid-mode") + t.Logf("Output of 'kmeshctl dump %s invalid-mode':\n%s", pod, out) + if err == nil { + t.Fatal("expected error for invalid mode, but command succeeded") + } + if !strings.Contains(out, "Argument must be 'kernel-native' or 'dual-engine'") { + t.Errorf("expected usage error, got:\n%s", out) + } + }) +} + + func runAccesslogCmd(args ...string) (string, error) { + cmdArgs := append([]string{"monitoring"}, args...) + cmd := exec.Command("kmeshctl", cmdArgs...) + out, err := cmd.CombinedOutput() + return string(out), err + } func runAccesslogCmd(args ...string) (string, error) { cmdArgs := append([]string{"monitoring"}, args...) From 2af2fee5009294d3c54651b3ee3f9a450e4d7617 Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Sat, 26 Apr 2025 01:32:55 +0530 Subject: [PATCH 08/10] minor changes Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go index cd1e67692..51d6f9bf3 100644 --- a/test/e2e/kmeshctl_test.go +++ b/test/e2e/kmeshctl_test.go @@ -169,13 +169,6 @@ func runDumpCmd(args ...string) (string, error) { }) } - func runAccesslogCmd(args ...string) (string, error) { - cmdArgs := append([]string{"monitoring"}, args...) - cmd := exec.Command("kmeshctl", cmdArgs...) - out, err := cmd.CombinedOutput() - return string(out), err - } - func runAccesslogCmd(args ...string) (string, error) { cmdArgs := append([]string{"monitoring"}, args...) cmd := exec.Command("kmeshctl", cmdArgs...) From f5bf4de2941f3a1cf6c2ee7563020c80e788cfb3 Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Sun, 4 May 2025 10:05:58 +0530 Subject: [PATCH 09/10] add: waypoints test and minor chages in structure of rest of the code Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 582 ++++++++++++++++++-------------------- 1 file changed, 281 insertions(+), 301 deletions(-) diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go index 51d6f9bf3..f2a85ac90 100644 --- a/test/e2e/kmeshctl_test.go +++ b/test/e2e/kmeshctl_test.go @@ -17,14 +17,13 @@ * limitations under the License. */ - package kmesh import ( "bufio" "context" "crypto/rand" - "encoding/hex" + "encoding/hex" "encoding/json" "fmt" "os/exec" @@ -33,413 +32,394 @@ import ( "time" v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "kmesh.net/kmesh/ctl/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kmesh.net/kmesh/ctl/utils" +) + +const ( + kmeshNamespace = "kmesh-system" + waypointNamespace = "default" + waypointName = "waypoint" + waitTimeout = 90 * time.Second ) -func runVersionCmd(args ...string) (string, error) { - cmdArgs := append([]string{"version"}, args...) +var ( + podName string +) + +func runCtlCmd(t *testing.T, subcmd string, args ...string) (string, error) { + t.Helper() + cmdArgs := append([]string{subcmd}, args...) cmd := exec.Command("kmeshctl", cmdArgs...) out, err := cmd.CombinedOutput() - return string(out), err + outStr := strings.TrimSpace(string(out)) + t.Logf(">>> kmeshctl %s: %s", strings.Join(cmdArgs, " "), outStr) + return outStr, err +} + +func waitForPodReady(t *testing.T, pod string) { + t.Helper() + cmd := exec.Command("kubectl", "-n", kmeshNamespace, "wait", + "--for=condition=Ready", "pod/"+pod, + "--timeout=120s", + ) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("pod %s did not become Ready: %v\nOutput:\n%s", + pod, err, string(out)) + } } func findKmeshPod(t *testing.T) string { - const ns = "kmesh-system" - const label = "app=kmesh" - cmd := exec.Command("kubectl", "-n", ns, "get", "pods", - "-l", label, "-o", "jsonpath={.items[0].metadata.name}") + t.Helper() + cmd := exec.Command("kubectl", "-n", kmeshNamespace, "get", "pods", + "-l", "app=kmesh", "-o", "jsonpath={.items[0].metadata.name}") out, err := cmd.Output() if err != nil || len(out) == 0 { - list := exec.Command("kubectl", "-n", ns, "get", "pods", "-o", "wide") - all, _ := list.CombinedOutput() - t.Fatalf("could not find pod with label %q: %v\nPods:\n%s", label, err, string(all)) + all, _ := exec.Command("kubectl", "-n", kmeshNamespace, + "get", "pods", "-o", "wide").CombinedOutput() + t.Fatalf("could not find kmesh pod: %v\nPods:\n%s", + err, string(all)) } name := strings.TrimSpace(string(out)) - t.Logf("Found Kmesh pod: %s", name) + t.Logf("Using Kmesh pod: %s", name) return name } -func waitForPodRunning(t *testing.T, pod string) { - const ns = "kmesh-system" - const retries = 20 - const delay = 2 * time.Second - for i := 0; i < retries; i++ { - cmd := exec.Command("kubectl", "-n", ns, "get", "pod", pod, "-o", "jsonpath={.status.phase}") - out, err := cmd.Output() - if err == nil && strings.EqualFold(strings.TrimSpace(string(out)), "Running") { - t.Logf("Pod %s is Running", pod) - return - } - time.Sleep(delay) +func init() { + wait := exec.Command("kubectl", "-n", kmeshNamespace, "wait", + "--for=condition=Ready", "pod", "-l", "app=kmesh", + "--timeout=2m", + ) + if out, err := wait.CombinedOutput(); err != nil { + panic(fmt.Sprintf("timed out waiting for Kmesh pods: %v\n%s", + err, string(out))) + } + + getPod := exec.Command("kubectl", "-n", kmeshNamespace, "get", "pods", + "-l", "app=kmesh", "-o", "jsonpath={.items[0].metadata.name}") + out, err := getPod.Output() + if err != nil || len(out) == 0 { + panic(fmt.Sprintf("failed to find any Kmesh pod: %v\n%s", + err, string(out))) } - t.Fatalf("pod %s did not become Running in time", pod) + podName = strings.TrimSpace(string(out)) } -func TestKmeshctlVersion(t *testing.T) { - pod := findKmeshPod(t) - waitForPodRunning(t, pod) +// --- Version tests --- +func TestKmeshctlVersion(t *testing.T) { t.Run("client-and-daemon-summary", func(t *testing.T) { - out, err := runVersionCmd() - t.Logf("Output of 'kmeshctl version':\n%s", out) + out, err := runCtlCmd(t, "version") if err != nil { t.Fatalf("version command failed: %v", err) } if !strings.Contains(out, "client version:") { - t.Errorf("expected 'client version:' in output, got:\n%s", out) + t.Errorf("expected 'client version:' in output\n%s", out) } if !strings.Contains(out, "kmesh-daemon version:") { - t.Errorf("expected 'kmesh-daemon version:' in output, got:\n%s", out) + t.Errorf("expected 'kmesh-daemon version:' in output\n%s", out) } }) t.Run("daemon-version-json", func(t *testing.T) { - out, err := runVersionCmd(pod) - t.Logf("Output of 'kmeshctl version %s':\n%s", pod, out) + out, err := runCtlCmd(t, "version", podName) if err != nil { - t.Fatalf("version command failed: %v", err) + t.Fatalf("version failed: %v", err) } var info struct { GitVersion string `json:"GitVersion"` GitCommit string `json:"GitCommit"` } if err := json.Unmarshal([]byte(out), &info); err != nil { - t.Fatalf("invalid JSON output: %v", err) + t.Fatalf("invalid JSON: %v", err) } if info.GitVersion == "" || info.GitCommit == "" { - t.Errorf("expected non-empty GitVersion and GitCommit, got: %+v", info) + t.Errorf("expected non-empty GitVersion and GitCommit, got %+v", info) } }) } -func runDumpCmd(args ...string) (string, error) { - cmdArgs := append([]string{"dump"}, args...) - cmd := exec.Command("kmeshctl", cmdArgs...) - out, err := cmd.CombinedOutput() - return string(out), err - } - - func TestKmeshctlDump(t *testing.T) { - pod := findKmeshPod(t) - waitForPodRunning(t, pod) - - t.Run("kernel-native", func(t *testing.T) { - out, err := runDumpCmd(pod, "kernel-native") - t.Logf("Output of 'kmeshctl dump %s kernel-native':\n%s", pod, out) - - if strings.Contains(out, "Invalid Client Mode") { - t.Log("kernel-native not supported; got expected error") - return - } - if err != nil { - t.Fatalf("dump kernel-native failed: %v\n%s", err, out) - } - if !strings.Contains(out, `"workloads"`) { - t.Errorf("expected JSON to contain \"workloads\" array, got:\n%s", out) - } - if !strings.Contains(out, `"services"`) { - t.Errorf("expected JSON to contain \"services\" array, got:\n%s", out) - } - }) - - t.Run("dual-engine", func(t *testing.T) { - out, err := runDumpCmd(pod, "dual-engine") - t.Logf("Output of 'kmeshctl dump %s dual-engine':\n%s", pod, out) - if err != nil { - t.Fatalf("dump dual-engine failed: %v\n%s", err, out) - } - if !strings.Contains(out, `"workloads"`) { - t.Errorf("expected JSON to contain \"workloads\" array, got:\n%s", out) - } - if !strings.Contains(out, `"services"`) { - t.Errorf("expected JSON to contain \"services\" array, got:\n%s", out) - } - }) - - t.Run("invalid-mode", func(t *testing.T) { - out, err := runDumpCmd(pod, "invalid-mode") - t.Logf("Output of 'kmeshctl dump %s invalid-mode':\n%s", pod, out) - if err == nil { - t.Fatal("expected error for invalid mode, but command succeeded") - } - if !strings.Contains(out, "Argument must be 'kernel-native' or 'dual-engine'") { - t.Errorf("expected usage error, got:\n%s", out) - } - }) -} - - func runAccesslogCmd(args ...string) (string, error) { - cmdArgs := append([]string{"monitoring"}, args...) - cmd := exec.Command("kmeshctl", cmdArgs...) - out, err := cmd.CombinedOutput() - return string(out), err - } - - func TestKmeshctlAccesslog(t *testing.T) { - pod := findKmeshPod(t) - waitForPodRunning(t, pod) - - - t.Run("enable-on-pod", func(t *testing.T) { - out, err := runAccesslogCmd(pod, "--accesslog", "enable") - t.Logf("enable-on-pod output:\n%s", out) +// --- Dump tests --- + +func TestKmeshctlDump(t *testing.T) { + t.Run("kernel-native", func(t *testing.T) { + out, err := runCtlCmd(t, "dump", podName, "kernel-native") + if strings.Contains(out, "Invalid Client Mode") { + t.Log("kernel-native not supported; skipping") + return + } if err != nil { - t.Fatalf("failed to enable accesslog on pod %s: %v", pod, err) + t.Fatalf("dump kernel-native failed: %v\n%s", err, out) + } + if !strings.Contains(out, `"workloads"`) { + t.Errorf("expected \"workloads\" in dump\n%s", out) + } + if !strings.Contains(out, `"services"`) { + t.Errorf("expected \"services\" in dump\n%s", out) } }) - - - t.Run("disable-on-pod", func(t *testing.T) { - out, err := runAccesslogCmd(pod, "--accesslog", "disable") - t.Logf("disable-on-pod output:\n%s", out) + + t.Run("dual-engine", func(t *testing.T) { + out, err := runCtlCmd(t, "dump", podName, "dual-engine") if err != nil { - t.Fatalf("failed to disable accesslog on pod %s: %v", pod, err) + t.Fatalf("dump dual-engine failed: %v\n%s", err, out) + } + if !strings.Contains(out, `"workloads"`) || !strings.Contains(out, `"services"`) { + t.Errorf("unexpected dump output:\n%s", out) } }) - - - t.Run("enable-cluster", func(t *testing.T) { - out, err := runAccesslogCmd("--accesslog", "enable") - t.Logf("enable-cluster output:\n%s", out) - if err != nil { - t.Fatalf("failed to enable accesslog cluster-wide: %v", err) + + t.Run("invalid-mode", func(t *testing.T) { + out, err := runCtlCmd(t, "dump", podName, "bogus-mode") + if err == nil { + t.Fatal("expected error for invalid mode") + } + if !strings.Contains(out, "Argument must be") { + t.Errorf("expected usage error, got:\n%s", out) } }) - - - t.Run("disable-cluster", func(t *testing.T) { - out, err := runAccesslogCmd("--accesslog", "disable") - t.Logf("disable-cluster output:\n%s", out) - if err != nil { - t.Fatalf("failed to disable accesslog cluster-wide: %v", err) +} + +// --- Accesslog tests --- + +func TestKmeshctlAccesslog(t *testing.T) { + t.Run("pod-enable", func(t *testing.T) { + if _, err := runCtlCmd(t, "monitoring", podName, "--accesslog", "enable"); err != nil { + t.Fatalf("enable accesslog on pod failed: %v", err) + } + }) + t.Run("pod-disable", func(t *testing.T) { + if _, err := runCtlCmd(t, "monitoring", podName, "--accesslog", "disable"); err != nil { + t.Fatalf("disable accesslog on pod failed: %v", err) + } + }) + t.Run("cluster-enable", func(t *testing.T) { + if _, err := runCtlCmd(t, "monitoring", "--accesslog", "enable"); err != nil { + t.Fatalf("cluster-wide accesslog enable failed: %v", err) + } + }) + t.Run("cluster-disable", func(t *testing.T) { + if _, err := runCtlCmd(t, "monitoring", "--accesslog", "disable"); err != nil { + t.Fatalf("cluster-wide accesslog disable failed: %v", err) } }) - } +} - func getLogOutputs(args ...string) (string, error) { - cmdArgs := append([]string{"log"}, args...) - cmd := exec.Command("kmeshctl", cmdArgs...) - output, err := cmd.CombinedOutput() - return string(output), err - } - - - func verifyLogOutputHeaders(t *testing.T, output, expectedHeader string) { +// --- Log tests --- + +func verifyLogHeader(t *testing.T, output, header string) { + t.Helper() scanner := bufio.NewScanner(strings.NewReader(output)) - found := false for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if strings.Contains(line, expectedHeader) { - found = true - break + if strings.Contains(scanner.Text(), header) { + return } } - if !found { - t.Errorf("Expected output to contain header %q but it did not. Full output:\n%s", expectedHeader, output) - } - } - - func TestKmeshctlLog(t *testing.T) { - podName := findKmeshPod(t) - waitForPodRunning(t, podName) - - t.Run("get-all-loggers", func(t *testing.T) { - output, err := getLogOutputs(podName) + t.Errorf("missing header %q in log output:\n%s", header, output) +} + +func TestKmeshctlLog(t *testing.T) { + t.Run("list-loggers", func(t *testing.T) { + out, err := runCtlCmd(t, "log", podName) if err != nil { - t.Fatalf("Failed to get logger names: %v, output: %s", err, output) + t.Fatalf("list loggers failed: %v", err) } - t.Logf("Output of 'kmeshctl log %s':\n%s", podName, output) - verifyLogOutputHeaders(t, output, "Existing Loggers:") + verifyLogHeader(t, out, "Existing Loggers:") }) - - t.Run("get-default-logger-level", func(t *testing.T) { - output, err := getLogOutputs(podName, "default") + + t.Run("get-default", func(t *testing.T) { + out, err := runCtlCmd(t, "log", podName, "default") if err != nil { - t.Fatalf("Failed to get default logger level: %v, output: %s", err, output) + t.Fatalf("get default logger failed: %v", err) } - t.Logf("Output of 'kmeshctl log %s default':\n%s", podName, output) - if !strings.Contains(output, "Logger Name:") || !strings.Contains(output, "Logger Level:") { - t.Errorf("Expected output to contain 'Logger Name:' and 'Logger Level:', but got: %s", output) + if !strings.Contains(out, "Logger Name:") || !strings.Contains(out, "Logger Level:") { + t.Errorf("unexpected get-default output:\n%s", out) } }) - - - t.Run("set-default-logger-level", func(t *testing.T) { - output, err := getLogOutputs(podName, "--set", "default:debug") - if err != nil { - t.Fatalf("Failed to set default logger level: %v, output: %s", err, output) + + t.Run("set-and-get-default", func(t *testing.T) { + if _, err := runCtlCmd(t, "log", podName, "--set", "default:debug"); err != nil { + t.Fatalf("set default to debug failed: %v", err) } - t.Logf("Output of 'kmeshctl log %s --set default:debug':\n%s", podName, output) - output2, err := getLogOutputs(podName, "default") + out, err := runCtlCmd(t, "log", podName, "default") if err != nil { - t.Fatalf("Failed to get default logger level after setting: %v, output: %s", err, output2) + t.Fatalf("get default after set failed: %v", err) } - t.Logf("Output of 'kmeshctl log %s default' after setting:\n%s", podName, output2) - if !strings.Contains(strings.ToLower(output2), "debug") { - t.Errorf("Expected default logger level to be 'debug', but output was: %s", output2) + if !strings.Contains(strings.ToLower(out), "debug") { + t.Errorf("expected log level debug, got:\n%s", out) } }) - } - - type IpSecKey struct { +} + +// --- Secret tests --- + +type ipSecKey struct { AeadKeyName string `json:"AeadKeyName"` AeadKey []byte `json:"AeadKey"` Length int `json:"Length"` Spi int `json:"Spi"` - } - - - func waitForSecret(secretName, namespace string, timeout time.Duration) (*v1.Secret, error) { +} + +func waitForSecret(t *testing.T, name, ns string, timeout time.Duration) *v1.Secret { + t.Helper() clientset, err := utils.CreateKubeClient() if err != nil { - return nil, fmt.Errorf("failed to create kube client: %v", err) + t.Fatalf("failed to create kube client: %v", err) } - - deadline := time.Now().Add(timeout) for time.Now().Before(deadline) { - sec, err := clientset.Kube().CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + sec, err := clientset.Kube().CoreV1(). + Secrets(ns). + Get(context.TODO(), name, metav1.GetOptions{}) if err == nil { - return sec, nil + return sec } time.Sleep(2 * time.Second) } - return nil, fmt.Errorf("timeout waiting for secret %q in namespace %q", secretName, namespace) - } - - func deleteSecret(secretName, namespace string) error { + t.Fatalf("timed out waiting for secret %q in %q", name, ns) + return nil +} + +func deleteSecret(t *testing.T, name, ns string) { + t.Helper() clientset, err := utils.CreateKubeClient() if err != nil { - return fmt.Errorf("failed to create kube client: %v", err) + t.Fatalf("failed to create kube client: %v", err) } - _ = clientset.Kube().CoreV1().Secrets(namespace).Delete(context.TODO(), secretName, metav1.DeleteOptions{}) - return nil - } - - func generateRandomKey() (string, error) { - keyBytes := make([]byte, 36) - _, err := rand.Read(keyBytes) - if err != nil { - return "", fmt.Errorf("failed to generate random key: %v", err) + _ = clientset.Kube().CoreV1(). + Secrets(ns). + Delete(context.TODO(), name, metav1.DeleteOptions{}) +} + +func genRandomKey(t *testing.T) string { + t.Helper() + b := make([]byte, 36) + if _, err := rand.Read(b); err != nil { + t.Fatalf("random key generation failed: %v", err) } - return hex.EncodeToString(keyBytes), nil - } - - - func TestKmeshctlSecret(t *testing.T) { + return hex.EncodeToString(b) +} + +func TestKmeshctlSecret(t *testing.T) { const secretName = "kmesh-ipsec" - const namespace = "kmesh-system" - - _ = deleteSecret(secretName, namespace) - t.Log("Deleted existing secret (if any)") - - - key1, err := generateRandomKey() - if err != nil { - t.Fatalf("failed to generate random key: %v", err) - } - t.Logf("Generated key1: %s", key1) - - - cmd := exec.Command("kmeshctl", "secret", "--key", key1) - output, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("failed to run kmeshctl secret command: %v, output: %s", err, string(output)) - } - t.Logf("Output of first 'kmeshctl secret' command: %s", string(output)) - - - sec, err := waitForSecret(secretName, namespace, 30*time.Second) - if err != nil { - t.Fatalf("failed to get created secret: %v", err) - } - - dataB64, exists := sec.Data["ipSec"] - if !exists { - t.Fatalf("secret %q does not contain key 'ipSec'", secretName) - } + deleteSecret(t, secretName, kmeshNamespace) - var ipSecKey IpSecKey - err = json.Unmarshal(dataB64, &ipSecKey) - if err != nil { - t.Fatalf("failed to unmarshal secret data: %v", err) - } - t.Logf("Created secret with SPI: %d", ipSecKey.Spi) - if ipSecKey.Spi != 1 { - t.Errorf("Expected SPI to be 1 on creation, got %d", ipSecKey.Spi) + key1 := genRandomKey(t) + t.Logf("Using key1=%s", key1) + if _, err := runCtlCmd(t, "secret", "--key", key1); err != nil { + t.Fatalf("first secret generate failed: %v", err) } - - key2, err := generateRandomKey() - if err != nil { - t.Fatalf("failed to generate second random key: %v", err) + sec1 := waitForSecret(t, secretName, kmeshNamespace, 30*time.Second) + raw1 := sec1.Data["ipSec"] + var k1 ipSecKey + if err := json.Unmarshal(raw1, &k1); err != nil { + t.Fatalf("unmarshal ipSec failed: %v", err) } - t.Logf("Generated key2: %s", key2) - cmd = exec.Command("kmeshctl", "secret", "--key", key2) - output, err = cmd.CombinedOutput() - if err != nil { - t.Fatalf("failed to run kmeshctl secret command for update: %v, output: %s", err, string(output)) + if k1.Spi != 1 { + t.Errorf("expected SPI=1 after create, got %d", k1.Spi) } - t.Logf("Output of second 'kmeshctl secret' command: %s", string(output)) - - secUpdated, err := waitForSecret(secretName, namespace, 30*time.Second) - if err != nil { - t.Fatalf("failed to get updated secret: %v", err) + key2 := genRandomKey(t) + t.Logf("Using key2=%s", key2) + if _, err := runCtlCmd(t, "secret", "--key", key2); err != nil { + t.Fatalf("second secret generate failed: %v", err) } - dataB64 = secUpdated.Data["ipSec"] - var ipSecKeyUpdated IpSecKey - err = json.Unmarshal(dataB64, &ipSecKeyUpdated) - if err != nil { - t.Fatalf("failed to unmarshal updated secret data: %v", err) + sec2 := waitForSecret(t, secretName, kmeshNamespace, 30*time.Second) + raw2 := sec2.Data["ipSec"] + var k2 ipSecKey + if err := json.Unmarshal(raw2, &k2); err != nil { + t.Fatalf("unmarshal updated ipSec failed: %v", err) } - t.Logf("Updated secret with SPI: %d", ipSecKeyUpdated.Spi) - expectedSPI := ipSecKey.Spi + 1 - if ipSecKeyUpdated.Spi != expectedSPI { - t.Errorf("Expected updated SPI to be %d, but got %d", expectedSPI, ipSecKeyUpdated.Spi) + if k2.Spi != k1.Spi+1 { + t.Errorf("expected SPI=%d after update, got %d", k1.Spi+1, k2.Spi) } - } - - func runAuthzCmd(args ...string) (string, error) { - cmdArgs := append([]string{"authz"}, args...) - cmd := exec.Command("kmeshctl", cmdArgs...) - out, err := cmd.CombinedOutput() - return string(out), err } - -func TestKmeshctlAuthzEnableDisable(t *testing.T) { - pod := findKmeshPod(t) - waitForPodRunning(t, pod) - - t.Run("enable-cluster", func(t *testing.T) { - out, err := runAuthzCmd("enable") - t.Logf("Output of 'kmeshctl authz enable':\n%s", out) + +// --- Authz tests --- + +func TestKmeshctlAuthz(t *testing.T) { + t.Run("cluster-enable-disable", func(t *testing.T) { + if _, err := runCtlCmd(t, "authz", "enable"); err != nil { + t.Fatalf("authz enable failed: %v", err) + } + if _, err := runCtlCmd(t, "authz", "disable"); err != nil { + t.Fatalf("authz disable failed: %v", err) + } + }) + + t.Run("pod-enable-disable", func(t *testing.T) { + if _, err := runCtlCmd(t, "authz", "enable", podName); err != nil { + t.Fatalf("authz enable %s failed: %v", podName, err) + } + if _, err := runCtlCmd(t, "authz", "disable", podName); err != nil { + t.Fatalf("authz disable %s failed: %v", podName, err) + } + }) +} + +// --- Waypoint tests --- + +func TestKmeshctlWaypoint(t *testing.T) { + t.Run("generate", func(t *testing.T) { + out, err := runCtlCmd(t, "waypoint", "generate", "-n", waypointNamespace) if err != nil { - t.Fatalf("cluster-wide enable failed: %v", err) + t.Fatalf("generate failed: %v", err) + } + if !strings.Contains(out, "kind: Gateway") { + t.Errorf("expected 'kind: Gateway', got:\n%s", out) } }) - t.Run("disable-cluster", func(t *testing.T) { - out, err := runAuthzCmd("disable") - t.Logf("Output of 'kmeshctl authz disable':\n%s", out) + t.Run("apply", func(t *testing.T) { + out, err := runCtlCmd(t, "waypoint", "apply", "-n", waypointNamespace, "-w") if err != nil { - t.Fatalf("cluster-wide disable failed: %v", err) + t.Fatalf("apply failed: %v", err) + } + want := fmt.Sprintf("waypoint %s/%s applied", waypointNamespace, waypointName) + if !strings.Contains(out, want) { + t.Errorf("expected %q, got:\n%s", want, out) } }) - t.Run("enable-pod", func(t *testing.T) { - out, err := runAuthzCmd("enable", pod) - t.Logf("Output of 'kmeshctl authz enable %s':\n%s", pod, out) + t.Run("list", func(t *testing.T) { + time.Sleep(2 * time.Second) + out, err := runCtlCmd(t, "waypoint", "list", "-n", waypointNamespace) if err != nil { - t.Fatalf("per-pod enable failed: %v", err) + t.Fatalf("list failed: %v", err) + } + if !strings.Contains(out, waypointName) { + t.Errorf("expected %q in list, got:\n%s", waypointName, out) } }) - t.Run("disable-pod", func(t *testing.T) { - out, err := runAuthzCmd("disable", pod) - t.Logf("Output of 'kmeshctl authz disable %s':\n%s", pod, out) + t.Run("status", func(t *testing.T) { + out, err := runCtlCmd(t, "waypoint", "status", "-n", waypointNamespace) if err != nil { - t.Fatalf("per-pod disable failed: %v", err) + t.Fatalf("status failed: %v", err) + } + if !strings.Contains(out, "NAME") || !strings.Contains(out, "STATUS") { + t.Errorf("expected headers in status, got:\n%s", out) + } + }) + + t.Run("delete", func(t *testing.T) { + out, err := runCtlCmd(t, "waypoint", "delete", "--all", "-n", waypointNamespace) + if err != nil { + t.Fatalf("delete failed: %v", err) + } + if !strings.Contains(out, fmt.Sprintf("waypoint %s/%s deleted", waypointNamespace, waypointName)) { + t.Errorf("expected delete confirmation, got:\n%s", out) } }) -} \ No newline at end of file + + t.Run("list-after-delete", func(t *testing.T) { + out, err := runCtlCmd(t, "waypoint", "list", "-n", waypointNamespace) + if err != nil { + t.Fatalf("list after delete failed: %v", err) + } + if !strings.Contains(out, "No waypoints found.") { + t.Errorf("expected 'No waypoints found.', got:\n%s", out) + } + }) +} From 37b13921dd156e6456e76b82203430505e835007 Mon Sep 17 00:00:00 2001 From: ravjot07 Date: Tue, 13 May 2025 10:53:45 +0530 Subject: [PATCH 10/10] minor changes Signed-off-by: ravjot07 --- test/e2e/kmeshctl_test.go | 61 +++++++++++++++------------------------ test/e2e/run_test.sh | 8 ++--- 2 files changed, 27 insertions(+), 42 deletions(-) diff --git a/test/e2e/kmeshctl_test.go b/test/e2e/kmeshctl_test.go index f2a85ac90..cb0b42003 100644 --- a/test/e2e/kmeshctl_test.go +++ b/test/e2e/kmeshctl_test.go @@ -44,9 +44,11 @@ const ( ) var ( + // podName is set once in init() after all Kmesh pods are Ready. podName string ) +// runCtlCmd runs `kmeshctl [args...]` and returns the trimmed output or error. func runCtlCmd(t *testing.T, subcmd string, args ...string) (string, error) { t.Helper() cmdArgs := append([]string{subcmd}, args...) @@ -57,50 +59,24 @@ func runCtlCmd(t *testing.T, subcmd string, args ...string) (string, error) { return outStr, err } -func waitForPodReady(t *testing.T, pod string) { - t.Helper() - cmd := exec.Command("kubectl", "-n", kmeshNamespace, "wait", - "--for=condition=Ready", "pod/"+pod, - "--timeout=120s", - ) - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("pod %s did not become Ready: %v\nOutput:\n%s", - pod, err, string(out)) - } -} - -func findKmeshPod(t *testing.T) string { - t.Helper() - cmd := exec.Command("kubectl", "-n", kmeshNamespace, "get", "pods", - "-l", "app=kmesh", "-o", "jsonpath={.items[0].metadata.name}") - out, err := cmd.Output() - if err != nil || len(out) == 0 { - all, _ := exec.Command("kubectl", "-n", kmeshNamespace, - "get", "pods", "-o", "wide").CombinedOutput() - t.Fatalf("could not find kmesh pod: %v\nPods:\n%s", - err, string(all)) - } - name := strings.TrimSpace(string(out)) - t.Logf("Using Kmesh pod: %s", name) - return name -} - +// Package‐level init ensures Kmesh is ready before any tests run. func init() { + // 1) Wait up to 2 minutes for all Kmesh pods to become Ready. wait := exec.Command("kubectl", "-n", kmeshNamespace, "wait", "--for=condition=Ready", "pod", "-l", "app=kmesh", "--timeout=2m", ) if out, err := wait.CombinedOutput(); err != nil { - panic(fmt.Sprintf("timed out waiting for Kmesh pods: %v\n%s", + panic(fmt.Sprintf("❌ timed out waiting for Kmesh pods: %v\n%s", err, string(out))) } + // 2) Retrieve the name of the first Ready Kmesh pod. getPod := exec.Command("kubectl", "-n", kmeshNamespace, "get", "pods", "-l", "app=kmesh", "-o", "jsonpath={.items[0].metadata.name}") out, err := getPod.Output() if err != nil || len(out) == 0 { - panic(fmt.Sprintf("failed to find any Kmesh pod: %v\n%s", + panic(fmt.Sprintf("❌ failed to find any Kmesh pod: %v\n%s", err, string(out))) } podName = strings.TrimSpace(string(out)) @@ -208,6 +184,7 @@ func TestKmeshctlAccesslog(t *testing.T) { // --- Log tests --- +// verifyLogHeader checks that output lines include the given header. func verifyLogHeader(t *testing.T, output, header string) { t.Helper() scanner := bufio.NewScanner(strings.NewReader(output)) @@ -383,13 +360,21 @@ func TestKmeshctlWaypoint(t *testing.T) { }) t.Run("list", func(t *testing.T) { - time.Sleep(2 * time.Second) - out, err := runCtlCmd(t, "waypoint", "list", "-n", waypointNamespace) - if err != nil { - t.Fatalf("list failed: %v", err) - } - if !strings.Contains(out, waypointName) { - t.Errorf("expected %q in list, got:\n%s", waypointName, out) + // Poll for the waypoint to appear in the list + found := false + start := time.Now() + for time.Since(start) < waitTimeout { + out, err := runCtlCmd(t, "waypoint", "list", "-n", waypointNamespace) + if err != nil { + t.Logf("waypoint list error (retrying): %v", err) + } else if strings.Contains(out, waypointName) { + found = true + break + } + time.Sleep(2 * time.Second) + } + if !found { + t.Fatalf("expected %q in 'kmeshctl waypoint list' within %v", waypointName, waitTimeout) } }) diff --git a/test/e2e/run_test.sh b/test/e2e/run_test.sh index 413963a5c..00a17e044 100755 --- a/test/e2e/run_test.sh +++ b/test/e2e/run_test.sh @@ -291,10 +291,10 @@ fi if [[ -z "${SKIP_BUILD:-}" ]]; then setup_kind_registry - build_and_push_images - echo "Building kmeshctl CLI..." - make kmeshctl || { echo "Failed to build kmeshctl" >&2; exit 1; } - install_kmeshctl || { echo "Failed to install kmeshctl into PATH" >&2; exit 1; } + build_and_push_images + echo "Building kmeshctl CLI..." + make kmeshctl || { echo "Failed to build kmeshctl" >&2; exit 1; } + install_kmeshctl || { echo "Failed to install kmeshctl into PATH" >&2; exit 1; } fi kubectl config use-context "kind-$NAME"