mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-05-02 22:06:07 +00:00
unit tests should not depend on real KUBECONFIG env var value to pass
This commit is contained in:
@@ -36,6 +36,7 @@ import (
|
||||
)
|
||||
|
||||
type kubeconfigDeps struct {
|
||||
getenv func(key string) string
|
||||
getPathToSelf func() (string, error)
|
||||
getClientset getConciergeClientsetFunc
|
||||
log plog.MinLogger
|
||||
@@ -43,6 +44,7 @@ type kubeconfigDeps struct {
|
||||
|
||||
func kubeconfigRealDeps() kubeconfigDeps {
|
||||
return kubeconfigDeps{
|
||||
getenv: os.Getenv,
|
||||
getPathToSelf: os.Executable,
|
||||
getClientset: getRealConciergeClientset,
|
||||
log: plog.New(),
|
||||
@@ -156,7 +158,7 @@ func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
|
||||
),
|
||||
)
|
||||
f.StringVar(&flags.oidc.upstreamIDPFlow, "upstream-identity-provider-flow", "", fmt.Sprintf("The type of client flow to use with the upstream identity provider during login with a Supervisor (e.g. '%s', '%s')", idpdiscoveryv1alpha1.IDPFlowCLIPassword, idpdiscoveryv1alpha1.IDPFlowBrowserAuthcode))
|
||||
f.StringVar(&flags.kubeconfigPath, "kubeconfig", os.Getenv("KUBECONFIG"), "Path to kubeconfig file")
|
||||
f.StringVar(&flags.kubeconfigPath, "kubeconfig", deps.getenv("KUBECONFIG"), "Path to kubeconfig file")
|
||||
f.StringVar(&flags.kubeconfigContextOverride, "kubeconfig-context", "", "Kubeconfig context name (default: current active context)")
|
||||
f.BoolVar(&flags.skipValidate, "skip-validation", false, "Skip final validation of the kubeconfig (default: false)")
|
||||
f.DurationVar(&flags.timeout, "timeout", 10*time.Minute, "Timeout for autodiscovery and validation")
|
||||
|
||||
@@ -97,6 +97,47 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
}`, issuerURL)
|
||||
}
|
||||
|
||||
helpOutputFormatString := here.Doc(`
|
||||
Generate a Pinniped-based kubeconfig for a cluster
|
||||
|
||||
Usage:
|
||||
kubeconfig [flags]
|
||||
|
||||
Flags:
|
||||
--concierge-api-group-suffix string Concierge API group suffix (default "pinniped.dev")
|
||||
--concierge-authenticator-name string Concierge authenticator name (default: autodiscover)
|
||||
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt') (default: autodiscover)
|
||||
--concierge-ca-bundle path Path to TLS certificate authority bundle (PEM format, optional, can be repeated) to use when connecting to the Concierge
|
||||
--concierge-credential-issuer string Concierge CredentialIssuer object to use for autodiscovery (default: autodiscover)
|
||||
--concierge-endpoint string API base for the Concierge endpoint
|
||||
--concierge-mode mode Concierge mode of operation (default TokenCredentialRequestAPI)
|
||||
--concierge-skip-wait Skip waiting for any pending Concierge strategies to become ready (default: false)
|
||||
--credential-cache string Path to cluster-specific credentials cache
|
||||
--generated-name-suffix string Suffix to append to generated cluster, context, user kubeconfig entries (default "-pinniped")
|
||||
-h, --help help for kubeconfig
|
||||
--install-hint string This text is shown to the user when the pinniped CLI is not installed. (default "The pinniped CLI does not appear to be installed. See https://get.pinniped.dev/cli for more details")
|
||||
--kubeconfig string Path to kubeconfig file%s
|
||||
--kubeconfig-context string Kubeconfig context name (default: current active context)
|
||||
--no-concierge Generate a configuration which does not use the Concierge, but sends the credential to the cluster directly
|
||||
--oidc-ca-bundle path Path to TLS certificate authority bundle (PEM format, optional, can be repeated)
|
||||
--oidc-client-id string OpenID Connect client ID (default: autodiscover) (default "pinniped-cli")
|
||||
--oidc-issuer string OpenID Connect issuer URL (default: autodiscover)
|
||||
--oidc-listen-port uint16 TCP port for localhost listener (authorization code flow only)
|
||||
--oidc-request-audience string Request a token with an alternate audience using RFC8693 token exchange
|
||||
--oidc-scopes strings OpenID Connect scopes to request during login (default [offline_access,openid,pinniped:request-audience,username,groups])
|
||||
--oidc-session-cache string Path to OpenID Connect session cache file
|
||||
--oidc-skip-browser During OpenID Connect login, skip opening the browser (just print the URL)
|
||||
-o, --output string Output file path (default: stdout)
|
||||
--pinniped-cli-path string Full path or executable name for the Pinniped CLI binary to be embedded in the resulting kubeconfig output (e.g. 'pinniped') (default: full path of the binary used to execute this command)
|
||||
--skip-validation Skip final validation of the kubeconfig (default: false)
|
||||
--static-token string Instead of doing an OIDC-based login, specify a static token
|
||||
--static-token-env string Instead of doing an OIDC-based login, read a static token from the environment
|
||||
--timeout duration Timeout for autodiscovery and validation (default 10m0s)
|
||||
--upstream-identity-provider-flow string The type of client flow to use with the upstream identity provider during login with a Supervisor (e.g. 'cli_password', 'browser_authcode')
|
||||
--upstream-identity-provider-name string The name of the upstream identity provider used during login with a Supervisor
|
||||
--upstream-identity-provider-type string The type of the upstream identity provider used during login with a Supervisor (e.g. 'oidc', 'ldap', 'activedirectory', 'github')
|
||||
`)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args func(string, string) []string
|
||||
@@ -120,46 +161,17 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
name: "help flag passed",
|
||||
args: func(issuerCABundle string, issuerURL string) []string { return []string{"--help"} },
|
||||
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
||||
return here.Doc(`
|
||||
Generate a Pinniped-based kubeconfig for a cluster
|
||||
|
||||
Usage:
|
||||
kubeconfig [flags]
|
||||
|
||||
Flags:
|
||||
--concierge-api-group-suffix string Concierge API group suffix (default "pinniped.dev")
|
||||
--concierge-authenticator-name string Concierge authenticator name (default: autodiscover)
|
||||
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt') (default: autodiscover)
|
||||
--concierge-ca-bundle path Path to TLS certificate authority bundle (PEM format, optional, can be repeated) to use when connecting to the Concierge
|
||||
--concierge-credential-issuer string Concierge CredentialIssuer object to use for autodiscovery (default: autodiscover)
|
||||
--concierge-endpoint string API base for the Concierge endpoint
|
||||
--concierge-mode mode Concierge mode of operation (default TokenCredentialRequestAPI)
|
||||
--concierge-skip-wait Skip waiting for any pending Concierge strategies to become ready (default: false)
|
||||
--credential-cache string Path to cluster-specific credentials cache
|
||||
--generated-name-suffix string Suffix to append to generated cluster, context, user kubeconfig entries (default "-pinniped")
|
||||
-h, --help help for kubeconfig
|
||||
--install-hint string This text is shown to the user when the pinniped CLI is not installed. (default "The pinniped CLI does not appear to be installed. See https://get.pinniped.dev/cli for more details")
|
||||
--kubeconfig string Path to kubeconfig file
|
||||
--kubeconfig-context string Kubeconfig context name (default: current active context)
|
||||
--no-concierge Generate a configuration which does not use the Concierge, but sends the credential to the cluster directly
|
||||
--oidc-ca-bundle path Path to TLS certificate authority bundle (PEM format, optional, can be repeated)
|
||||
--oidc-client-id string OpenID Connect client ID (default: autodiscover) (default "pinniped-cli")
|
||||
--oidc-issuer string OpenID Connect issuer URL (default: autodiscover)
|
||||
--oidc-listen-port uint16 TCP port for localhost listener (authorization code flow only)
|
||||
--oidc-request-audience string Request a token with an alternate audience using RFC8693 token exchange
|
||||
--oidc-scopes strings OpenID Connect scopes to request during login (default [offline_access,openid,pinniped:request-audience,username,groups])
|
||||
--oidc-session-cache string Path to OpenID Connect session cache file
|
||||
--oidc-skip-browser During OpenID Connect login, skip opening the browser (just print the URL)
|
||||
-o, --output string Output file path (default: stdout)
|
||||
--pinniped-cli-path string Full path or executable name for the Pinniped CLI binary to be embedded in the resulting kubeconfig output (e.g. 'pinniped') (default: full path of the binary used to execute this command)
|
||||
--skip-validation Skip final validation of the kubeconfig (default: false)
|
||||
--static-token string Instead of doing an OIDC-based login, specify a static token
|
||||
--static-token-env string Instead of doing an OIDC-based login, read a static token from the environment
|
||||
--timeout duration Timeout for autodiscovery and validation (default 10m0s)
|
||||
--upstream-identity-provider-flow string The type of client flow to use with the upstream identity provider during login with a Supervisor (e.g. 'cli_password', 'browser_authcode')
|
||||
--upstream-identity-provider-name string The name of the upstream identity provider used during login with a Supervisor
|
||||
--upstream-identity-provider-type string The type of the upstream identity provider used during login with a Supervisor (e.g. 'oidc', 'ldap', 'activedirectory', 'github')
|
||||
`)
|
||||
return fmt.Sprintf(helpOutputFormatString, "")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "help flag passed with KUBECONFIG env var set",
|
||||
env: map[string]string{
|
||||
"KUBECONFIG": "/path/to/kubeconfig",
|
||||
},
|
||||
args: func(issuerCABundle string, issuerURL string) []string { return []string{"--help"} },
|
||||
wantStdout: func(issuerCABundle string, issuerURL string) string {
|
||||
return fmt.Sprintf(helpOutputFormatString, ` (default "/path/to/kubeconfig")`)
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -3237,6 +3249,9 @@ func TestGetKubeconfig(t *testing.T) {
|
||||
var log bytes.Buffer
|
||||
|
||||
cmd := kubeconfigCommand(kubeconfigDeps{
|
||||
getenv: func(key string) string {
|
||||
return tt.env[key]
|
||||
},
|
||||
getPathToSelf: func() (string, error) {
|
||||
if tt.getPathToSelfErr != nil {
|
||||
return "", tt.getPathToSelfErr
|
||||
|
||||
@@ -24,9 +24,21 @@ import (
|
||||
"go.pinniped.dev/internal/here"
|
||||
)
|
||||
|
||||
type whoamiDeps struct {
|
||||
getenv func(key string) string
|
||||
getClientset getConciergeClientsetFunc
|
||||
}
|
||||
|
||||
func whoamiRealDeps() whoamiDeps {
|
||||
return whoamiDeps{
|
||||
getenv: os.Getenv,
|
||||
getClientset: getRealConciergeClientset,
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gochecknoinits
|
||||
func init() {
|
||||
rootCmd.AddCommand(newWhoamiCommand(getRealConciergeClientset))
|
||||
rootCmd.AddCommand(newWhoamiCommand(whoamiRealDeps()))
|
||||
}
|
||||
|
||||
type whoamiFlags struct {
|
||||
@@ -44,7 +56,7 @@ type clusterInfo struct {
|
||||
url string
|
||||
}
|
||||
|
||||
func newWhoamiCommand(getClientset getConciergeClientsetFunc) *cobra.Command {
|
||||
func newWhoamiCommand(deps whoamiDeps) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Args: cobra.NoArgs, // do not accept positional arguments for this command
|
||||
Use: "whoami",
|
||||
@@ -56,21 +68,21 @@ func newWhoamiCommand(getClientset getConciergeClientsetFunc) *cobra.Command {
|
||||
// flags
|
||||
f := cmd.Flags()
|
||||
f.StringVarP(&flags.outputFormat, "output", "o", "text", "Output format (e.g., 'yaml', 'json', 'text')")
|
||||
f.StringVar(&flags.kubeconfigPath, "kubeconfig", os.Getenv("KUBECONFIG"), "Path to kubeconfig file")
|
||||
f.StringVar(&flags.kubeconfigPath, "kubeconfig", deps.getenv("KUBECONFIG"), "Path to kubeconfig file")
|
||||
f.StringVar(&flags.kubeconfigContextOverride, "kubeconfig-context", "", "Kubeconfig context name (default: current active context)")
|
||||
f.StringVar(&flags.apiGroupSuffix, "api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
||||
f.DurationVar(&flags.timeout, "timeout", 0, "Timeout for the WhoAmI API request (default: 0, meaning no timeout)")
|
||||
|
||||
cmd.RunE = func(cmd *cobra.Command, _ []string) error {
|
||||
return runWhoami(cmd.OutOrStdout(), getClientset, flags)
|
||||
return runWhoami(cmd.OutOrStdout(), deps, flags)
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runWhoami(output io.Writer, getClientset getConciergeClientsetFunc, flags *whoamiFlags) error {
|
||||
func runWhoami(output io.Writer, deps whoamiDeps, flags *whoamiFlags) error {
|
||||
clientConfig := newClientConfig(flags.kubeconfigPath, flags.kubeconfigContextOverride)
|
||||
clientset, err := getClientset(clientConfig, flags.apiGroupSuffix)
|
||||
clientset, err := deps.getClientset(clientConfig, flags.apiGroupSuffix)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not configure Kubernetes client: %w", err)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -21,9 +22,25 @@ import (
|
||||
)
|
||||
|
||||
func TestWhoami(t *testing.T) {
|
||||
helpOutputFormatString := here.Doc(`
|
||||
Print information about the current user
|
||||
|
||||
Usage:
|
||||
whoami [flags]
|
||||
|
||||
Flags:
|
||||
--api-group-suffix string Concierge API group suffix (default "pinniped.dev")
|
||||
-h, --help help for whoami
|
||||
--kubeconfig string Path to kubeconfig file%s
|
||||
--kubeconfig-context string Kubeconfig context name (default: current active context)
|
||||
-o, --output string Output format (e.g., 'yaml', 'json', 'text') (default "text")
|
||||
--timeout duration Timeout for the WhoAmI API request (default: 0, meaning no timeout)
|
||||
`)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
env map[string]string
|
||||
groupsOverride []string
|
||||
gettingClientsetErr error
|
||||
callingAPIErr error
|
||||
@@ -31,22 +48,17 @@ func TestWhoami(t *testing.T) {
|
||||
wantStdout, wantStderr string
|
||||
}{
|
||||
{
|
||||
name: "help flag",
|
||||
args: []string{"--help"},
|
||||
wantStdout: here.Doc(`
|
||||
Print information about the current user
|
||||
|
||||
Usage:
|
||||
whoami [flags]
|
||||
|
||||
Flags:
|
||||
--api-group-suffix string Concierge API group suffix (default "pinniped.dev")
|
||||
-h, --help help for whoami
|
||||
--kubeconfig string Path to kubeconfig file
|
||||
--kubeconfig-context string Kubeconfig context name (default: current active context)
|
||||
-o, --output string Output format (e.g., 'yaml', 'json', 'text') (default "text")
|
||||
--timeout duration Timeout for the WhoAmI API request (default: 0, meaning no timeout)
|
||||
`),
|
||||
name: "help flag passed",
|
||||
args: []string{"--help"},
|
||||
wantStdout: fmt.Sprintf(helpOutputFormatString, ""),
|
||||
},
|
||||
{
|
||||
name: "help flag passed with KUBECONFIG env var set",
|
||||
env: map[string]string{
|
||||
"KUBECONFIG": "/path/to/kubeconfig",
|
||||
},
|
||||
args: []string{"--help"},
|
||||
wantStdout: fmt.Sprintf(helpOutputFormatString, ` (default "/path/to/kubeconfig")`),
|
||||
},
|
||||
{
|
||||
name: "text output",
|
||||
@@ -306,7 +318,12 @@ func TestWhoami(t *testing.T) {
|
||||
})
|
||||
return clientset, nil
|
||||
}
|
||||
cmd := newWhoamiCommand(getClientset)
|
||||
cmd := newWhoamiCommand(whoamiDeps{
|
||||
getenv: func(key string) string {
|
||||
return test.env[key]
|
||||
},
|
||||
getClientset: getClientset,
|
||||
})
|
||||
|
||||
stdout, stderr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd.SetOut(stdout)
|
||||
|
||||
Reference in New Issue
Block a user