ContainerImage.Pinniped/cmd/placeholder-name/main_test.go
Matt Moyer 42616e7d8a Fix a bug in placeholder-name CLI (wrong API version).
This is kind of a subtle bug, but we were using the unversioned Kubernetes type package here, where we should have been using the v1beta1 version. They have the same fields, but they serialize to JSON differently.

Signed-off-by: Matt Moyer <moyerm@vmware.com>
2020-07-28 16:10:27 -05:00

162 lines
5.4 KiB
Go

/*
Copyright 2020 VMware, Inc.
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"bytes"
"context"
"fmt"
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
"github.com/stretchr/testify/require"
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
"github.com/suzerain-io/placeholder-name/test/library"
)
func TestRun(t *testing.T) {
spec.Run(t, "Run", func(t *testing.T, when spec.G, it spec.S) {
var buffer *bytes.Buffer
var tokenExchanger tokenExchanger
var fakeEnv map[string]string
var envGetter envGetter = func(envVarName string) (string, bool) {
value, present := fakeEnv[envVarName]
if !present {
return "", false
}
return value, true
}
it.Before(func() {
buffer = new(bytes.Buffer)
fakeEnv = map[string]string{
"PLACEHOLDER_NAME_TOKEN": "token from env",
"PLACEHOLDER_NAME_CA_BUNDLE": "ca bundle from env",
"PLACEHOLDER_NAME_K8S_API_ENDPOINT": "k8s api from env",
}
})
when("env vars are missing", func() {
it("returns an error when PLACEHOLDER_NAME_TOKEN is missing", func() {
fakeEnv = map[string]string{
"PLACEHOLDER_NAME_K8S_API_ENDPOINT": "a",
"PLACEHOLDER_NAME_CA_BUNDLE": "b",
}
err := run(envGetter, tokenExchanger, buffer, 30*time.Second)
require.EqualError(t, err, "failed to login: environment variable not set: PLACEHOLDER_NAME_TOKEN")
})
it("returns an error when PLACEHOLDER_NAME_CA_BUNDLE is missing", func() {
fakeEnv = map[string]string{
"PLACEHOLDER_NAME_K8S_API_ENDPOINT": "a",
"PLACEHOLDER_NAME_TOKEN": "b",
}
err := run(envGetter, tokenExchanger, buffer, 30*time.Second)
require.EqualError(t, err, "failed to login: environment variable not set: PLACEHOLDER_NAME_CA_BUNDLE")
})
it("returns an error when PLACEHOLDER_NAME_K8S_API_ENDPOINT is missing", func() {
fakeEnv = map[string]string{
"PLACEHOLDER_NAME_TOKEN": "a",
"PLACEHOLDER_NAME_CA_BUNDLE": "b",
}
err := run(envGetter, tokenExchanger, buffer, 30*time.Second)
require.EqualError(t, err, "failed to login: environment variable not set: PLACEHOLDER_NAME_K8S_API_ENDPOINT")
})
}, spec.Parallel())
when("the token exchange fails", func() {
it.Before(func() {
tokenExchanger = func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
return nil, fmt.Errorf("some error")
}
})
it("returns an error", func() {
err := run(envGetter, tokenExchanger, buffer, 30*time.Second)
require.EqualError(t, err, "failed to login: some error")
})
}, spec.Parallel())
when("the JSON encoder fails", func() {
it.Before(func() {
tokenExchanger = func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
return &clientauthenticationv1beta1.ExecCredential{
Status: &clientauthenticationv1beta1.ExecCredentialStatus{Token: "some token"},
}, nil
}
})
it("returns an error", func() {
err := run(envGetter, tokenExchanger, &library.ErrorWriter{ReturnError: fmt.Errorf("some IO error")}, 30*time.Second)
require.EqualError(t, err, "failed to marshal response to stdout: some IO error")
})
}, spec.Parallel())
when("the token exchange times out", func() {
it.Before(func() {
tokenExchanger = func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
select {
case <-time.After(100 * time.Millisecond):
return &clientauthenticationv1beta1.ExecCredential{
Status: &clientauthenticationv1beta1.ExecCredentialStatus{Token: "some token"},
}, nil
case <-ctx.Done():
return nil, ctx.Err()
}
}
})
it("returns an error", func() {
err := run(envGetter, tokenExchanger, buffer, 1*time.Millisecond)
require.EqualError(t, err, "failed to login: context deadline exceeded")
})
}, spec.Parallel())
when("the token exchange succeeds", func() {
var actualToken, actualCaBundle, actualAPIEndpoint string
it.Before(func() {
tokenExchanger = func(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
actualToken, actualCaBundle, actualAPIEndpoint = token, caBundle, apiEndpoint
return &clientauthenticationv1beta1.ExecCredential{
TypeMeta: metav1.TypeMeta{
Kind: "ExecCredential",
APIVersion: "client.authentication.k8s.io/v1beta1",
},
Status: &clientauthenticationv1beta1.ExecCredentialStatus{Token: "some token"},
}, nil
}
})
it("writes the execCredential to the given writer", func() {
err := run(envGetter, tokenExchanger, buffer, 30*time.Second)
require.NoError(t, err)
require.Equal(t, fakeEnv["PLACEHOLDER_NAME_TOKEN"], actualToken)
require.Equal(t, fakeEnv["PLACEHOLDER_NAME_CA_BUNDLE"], actualCaBundle)
require.Equal(t, fakeEnv["PLACEHOLDER_NAME_K8S_API_ENDPOINT"], actualAPIEndpoint)
expected := `
{
"kind": "ExecCredential",
"apiVersion": "client.authentication.k8s.io/v1beta1",
"spec": {},
"status": {
"token": "some token"
}
}
`
require.JSONEq(t, expected, buffer.String())
})
}, spec.Parallel())
}, spec.Report(report.Terminal{}))
}