434e3fe435
This change replaces our previous test helpers for checking cluster capabilities and passing external test parameters. Prior to this change, we always used `$PINNIPED_*` environment variables and these variables were accessed throughout the test code. The new code introduces a more strongly-typed `TestEnv` structure and helpers which load and expose the parameters. Tests can now call `env := library.IntegrationEnv(t)`, then access parameters such as `env.Namespace` or `env.TestUser.Token`. This should make this data dependency easier to manage and refactor in the future. In many ways this is just an extended version of the previous cluster capabilities YAML. Tests can also check for cluster capabilities easily by using `env := library.IntegrationEnv(t).WithCapability(xyz)`. The actual parameters are still loaded from OS environment variables by default (for compatibility), but the code now also tries to load the data from a Kubernetes Secret (`integration/pinniped-test-env` by default). I'm hoping this will be a more convenient way to pass data between various scripts than the local `/tmp` directory. I hope to remove the OS environment code in a future commit. Signed-off-by: Matt Moyer <moyerm@vmware.com>
122 lines
3.5 KiB
Go
122 lines
3.5 KiB
Go
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package integration
|
|
|
|
import (
|
|
"context"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"go.pinniped.dev/test/library"
|
|
)
|
|
|
|
func TestCLI(t *testing.T) {
|
|
env := library.IntegrationEnv(t).WithCapability(library.ClusterSigningKeyIsAvailable)
|
|
|
|
// Create a test webhook configuration to use with the CLI.
|
|
ctx, cancelFunc := context.WithTimeout(context.Background(), 4*time.Minute)
|
|
defer cancelFunc()
|
|
|
|
idp := library.CreateTestWebhookIDP(ctx, t)
|
|
|
|
// Remove all Pinniped environment variables for the remainder of this test
|
|
// because some of their names clash with the env vars expected by our
|
|
// kubectl exec plugin. We would like this test to prove that the exec
|
|
// plugin receives all of the necessary env vars via the auto-generated
|
|
// kubeconfig from the Pinniped CLI.
|
|
initialEnvVars := make(map[string]string)
|
|
for _, e := range os.Environ() {
|
|
pair := strings.SplitN(e, "=", 2)
|
|
name := pair[0]
|
|
value := pair[1]
|
|
if strings.HasPrefix(name, "PINNIPED_") {
|
|
initialEnvVars[name] = value
|
|
err := os.Unsetenv(name)
|
|
require.NoError(t, err)
|
|
}
|
|
}
|
|
// Put them back for other tests to use after this one
|
|
t.Cleanup(func() {
|
|
for k, v := range initialEnvVars {
|
|
err := os.Setenv(k, v)
|
|
require.NoError(t, err)
|
|
}
|
|
})
|
|
|
|
// Build pinniped CLI.
|
|
pinnipedExe, cleanupFunc := buildPinnipedCLI(t)
|
|
defer cleanupFunc()
|
|
|
|
// Run pinniped CLI to get kubeconfig.
|
|
kubeConfigYAML := runPinnipedCLI(t, pinnipedExe, env.TestUser.Token, env.Namespace, "webhook", idp.Name)
|
|
|
|
// In addition to the client-go based testing below, also try the kubeconfig
|
|
// with kubectl to validate that it works.
|
|
adminClient := library.NewClientset(t)
|
|
t.Run(
|
|
"access as user with kubectl",
|
|
accessAsUserWithKubectlTest(ctx, adminClient, kubeConfigYAML, env.TestUser.ExpectedUsername, env.Namespace),
|
|
)
|
|
for _, group := range env.TestUser.ExpectedGroups {
|
|
group := group
|
|
t.Run(
|
|
"access as group "+group+" with kubectl",
|
|
accessAsGroupWithKubectlTest(ctx, adminClient, kubeConfigYAML, group, env.Namespace),
|
|
)
|
|
}
|
|
|
|
// Create Kubernetes client with kubeconfig from pinniped CLI.
|
|
kubeClient := library.NewClientsetForKubeConfig(t, kubeConfigYAML)
|
|
|
|
// Validate that we can auth to the API via our user.
|
|
t.Run("access as user with client-go", accessAsUserTest(ctx, adminClient, env.TestUser.ExpectedUsername, kubeClient))
|
|
for _, group := range env.TestUser.ExpectedGroups {
|
|
group := group
|
|
t.Run("access as group "+group+" with client-go", accessAsGroupTest(ctx, adminClient, group, kubeClient))
|
|
}
|
|
}
|
|
|
|
func buildPinnipedCLI(t *testing.T) (string, func()) {
|
|
t.Helper()
|
|
|
|
pinnipedExeDir, err := ioutil.TempDir("", "pinniped-cli-test-*")
|
|
require.NoError(t, err)
|
|
|
|
pinnipedExe := filepath.Join(pinnipedExeDir, "pinniped")
|
|
output, err := exec.Command(
|
|
"go",
|
|
"build",
|
|
"-o",
|
|
pinnipedExe,
|
|
"go.pinniped.dev/cmd/pinniped",
|
|
).CombinedOutput()
|
|
require.NoError(t, err, string(output))
|
|
|
|
return pinnipedExe, func() {
|
|
require.NoError(t, os.RemoveAll(pinnipedExeDir))
|
|
}
|
|
}
|
|
|
|
func runPinnipedCLI(t *testing.T, pinnipedExe, token, namespaceName, idpType, idpName string) string {
|
|
t.Helper()
|
|
|
|
output, err := exec.Command(
|
|
pinnipedExe,
|
|
"get-kubeconfig",
|
|
"--token", token,
|
|
"--pinniped-namespace", namespaceName,
|
|
"--idp-type", idpType,
|
|
"--idp-name", idpName,
|
|
).CombinedOutput()
|
|
require.NoError(t, err, string(output))
|
|
|
|
return string(output)
|
|
}
|