// Copyright 2021 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package integration import ( "bytes" "os/exec" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.pinniped.dev/test/library" ) func runTestKubectlCommand(t *testing.T, args ...string) (string, string) { t.Helper() var lock sync.Mutex var stdOut, stdErr bytes.Buffer var err error start := time.Now() attempts := 0 if !assert.Eventually(t, func() bool { lock.Lock() defer lock.Unlock() attempts++ stdOut.Reset() stdErr.Reset() cmd := exec.Command("kubectl", args...) cmd.Stdout = &stdOut cmd.Stderr = &stdErr err = cmd.Run() return err == nil }, 120*time.Second, 200*time.Millisecond, ) { lock.Lock() defer lock.Unlock() t.Logf( "never ran %q successfully even after %d attempts (%s)", "kubectl "+strings.Join(args, " "), attempts, time.Since(start).Round(time.Second), ) t.Logf("last error: %v", err) t.Logf("stdout:\n%s\n", stdOut.String()) t.Logf("stderr:\n%s\n", stdErr.String()) t.FailNow() } return stdOut.String(), stdErr.String() } func requireCleanKubectlStderr(t *testing.T, stderr string) { // Every line must be empty or contain a known, innocuous warning. for _, line := range strings.Split(stderr, "\n") { if strings.TrimSpace(line) == "" { continue } if strings.Contains(line, "Throttling request took") { continue } require.Failf(t, "unexpected kubectl stderr", "kubectl produced unexpected stderr output:\n%s\n\n", stderr) return } } func TestGetPinnipedCategory(t *testing.T) { env := library.IntegrationEnv(t) dotSuffix := "." + env.APIGroupSuffix t.Run("category, no special params", func(t *testing.T) { t.Parallel() stdout, stderr := runTestKubectlCommand(t, "get", "pinniped", "-A") requireCleanKubectlStderr(t, stderr) require.NotContains(t, stdout, "MethodNotAllowed") require.Contains(t, stdout, dotSuffix) }) t.Run("category, table params", func(t *testing.T) { t.Parallel() stdout, stderr := runTestKubectlCommand(t, "get", "pinniped", "-A", "-o", "wide", "-v", "10") require.NotContains(t, stdout, "MethodNotAllowed") require.Contains(t, stdout, dotSuffix) require.Contains(t, stderr, `"kind":"Table"`) require.Contains(t, stderr, `"resourceVersion":"0"`) require.Contains(t, stderr, `/v1alpha1/tokencredentialrequests`) require.Contains(t, stderr, `/v1alpha1/whoamirequests`) }) t.Run("list, no special params", func(t *testing.T) { t.Parallel() stdout, stderr := runTestKubectlCommand(t, "get", "tokencredentialrequests.login.concierge"+dotSuffix, "-A") require.Empty(t, stdout) require.NotContains(t, stderr, "MethodNotAllowed") require.Contains(t, stderr, `No resources found`) }) t.Run("list, table params", func(t *testing.T) { t.Parallel() stdout, stderr := runTestKubectlCommand(t, "get", "tokencredentialrequests.login.concierge"+dotSuffix, "-A", "-o", "wide", "-v", "10") require.Empty(t, stdout) require.NotContains(t, stderr, "MethodNotAllowed") require.Contains(t, stderr, `"kind":"Table"`) require.Contains(t, stderr, `"resourceVersion":"0"`) }) t.Run("raw request to see body, token cred", func(t *testing.T) { t.Parallel() stdout, stderr := runTestKubectlCommand(t, "get", "--raw", "/apis/login.concierge"+dotSuffix+"/v1alpha1/tokencredentialrequests") require.NotContains(t, stdout, "MethodNotAllowed") require.Contains(t, stdout, `{"kind":"TokenCredentialRequestList","apiVersion":"login.concierge`+ dotSuffix+`/v1alpha1","metadata":{"resourceVersion":"0"},"items":[]}`) requireCleanKubectlStderr(t, stderr) }) t.Run("raw request to see body, whoami", func(t *testing.T) { t.Parallel() stdout, stderr := runTestKubectlCommand(t, "get", "--raw", "/apis/identity.concierge"+dotSuffix+"/v1alpha1/whoamirequests") require.NotContains(t, stdout, "MethodNotAllowed") require.Contains(t, stdout, `{"kind":"WhoAmIRequestList","apiVersion":"identity.concierge`+ dotSuffix+`/v1alpha1","metadata":{"resourceVersion":"0"},"items":[]}`) requireCleanKubectlStderr(t, stderr) }) }