ContainerImage.Pinniped/internal/kubeclient/path_test.go
Monis Khan efe1fa89fe Allow multiple Pinnipeds to work on same cluster
Yes, this is a huge commit.

The middleware allows you to customize the API groups of all of the
*.pinniped.dev API groups.

Some notes about other small things in this commit:
- We removed the internal/client package in favor of pkg/conciergeclient. The
  two packages do basically the same thing. I don't think we use the former
  anymore.
- We re-enabled cluster-scoped owner assertions in the integration tests.
  This code was added in internal/ownerref. See a0546942 for when this
  assertion was removed.
- Note: the middlware code is in charge of restoring the GV of a request object,
  so we should never need to write mutations that do that.
- We updated the supervisor secret generation to no longer manually set an owner
  reference to the deployment since the middleware code now does this. I think we
  still need some way to make an initial event for the secret generator
  controller, which involves knowing the namespace and the name of the generated
  secret, so I still wired the deployment through. We could use a namespace/name
  tuple here, but I was lazy.

Signed-off-by: Andrew Keesler <akeesler@vmware.com>
Co-authored-by: Ryan Richard <richardry@vmware.com>
2021-02-02 15:18:41 -08:00

232 lines
6.7 KiB
Go

// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package kubeclient
import (
"bytes"
"context"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"testing"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/runtime/schema"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
configv1alpha1 "go.pinniped.dev/generated/1.20/apis/supervisor/config/v1alpha1"
)
func Test_updatePathNewGVK(t *testing.T) {
type args struct {
reqURL *url.URL
result *mutationResult
apiPathPrefix string
reqInfo *genericapirequest.RequestInfo
}
tests := []struct {
name string
args args
want *url.URL
wantErr bool
}{
{
name: "no gvk change",
args: args{
reqURL: mustParse(t, "https://walrus.tld/api/v1/pods"),
result: &mutationResult{},
},
want: mustParse(t, "https://walrus.tld/api/v1/pods"),
},
{
name: "no original gvk group",
args: args{
result: &mutationResult{
origGVK: schema.GroupVersionKind{
Group: "",
},
gvkChanged: true,
},
},
wantErr: true,
},
{
name: "cluster-scoped list path",
args: args{
reqURL: mustParse(t, "https://walrus.tld/apis/"+loginv1alpha1.SchemeGroupVersion.String()+"/tokencredentialrequests"),
result: &mutationResult{
origGVK: loginv1alpha1.SchemeGroupVersion.WithKind("TokenCredentialRequest"),
newGVK: schema.GroupVersionKind{
Group: "login.concierge.tuna.io",
Version: loginv1alpha1.SchemeGroupVersion.Version,
Kind: "TokenCredentialRequest",
},
gvkChanged: true,
},
apiPathPrefix: "/apis",
reqInfo: &genericapirequest.RequestInfo{},
},
want: mustParse(t, "https://walrus.tld/apis/login.concierge.tuna.io/v1alpha1/tokencredentialrequests"),
},
{
name: "cluster-scoped get path",
args: args{
reqURL: mustParse(t, "https://walrus.tld/apis/"+loginv1alpha1.SchemeGroupVersion.String()+"/tokencredentialrequests/some-name"),
result: &mutationResult{
origGVK: loginv1alpha1.SchemeGroupVersion.WithKind("TokenCredentialRequest"),
newGVK: schema.GroupVersionKind{
Group: "login.concierge.tuna.io",
Version: loginv1alpha1.SchemeGroupVersion.Version,
Kind: "TokenCredentialRequest",
},
gvkChanged: true,
},
apiPathPrefix: "/apis",
reqInfo: &genericapirequest.RequestInfo{},
},
want: mustParse(t, "https://walrus.tld/apis/login.concierge.tuna.io/v1alpha1/tokencredentialrequests/some-name"),
},
{
name: "namespace-scoped list path",
args: args{
reqURL: mustParse(t, "https://walrus.tld/apis/"+configv1alpha1.SchemeGroupVersion.String()+"/namespaces/default/federationdomains"),
result: &mutationResult{
origGVK: configv1alpha1.SchemeGroupVersion.WithKind("FederationDomain"),
newGVK: schema.GroupVersionKind{
Group: "config.supervisor.tuna.io",
Version: configv1alpha1.SchemeGroupVersion.Version,
Kind: "FederationDomain",
},
gvkChanged: true,
},
apiPathPrefix: "/apis",
reqInfo: &genericapirequest.RequestInfo{},
},
want: mustParse(t, "https://walrus.tld/apis/config.supervisor.tuna.io/v1alpha1/namespaces/default/federationdomains"),
},
{
name: "namespace-scoped get path",
args: args{
reqURL: mustParse(t, "https://walrus.tld/apis/"+configv1alpha1.SchemeGroupVersion.String()+"/namespaces/default/federationdomains/some-name"),
result: &mutationResult{
origGVK: configv1alpha1.SchemeGroupVersion.WithKind("FederationDomain"),
newGVK: schema.GroupVersionKind{
Group: "config.supervisor.tuna.io",
Version: configv1alpha1.SchemeGroupVersion.Version,
Kind: "FederationDomain",
},
gvkChanged: true,
},
apiPathPrefix: "/apis",
reqInfo: &genericapirequest.RequestInfo{},
},
want: mustParse(t, "https://walrus.tld/apis/config.supervisor.tuna.io/v1alpha1/namespaces/default/federationdomains/some-name"),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
got, err := updatePathNewGVK(tt.args.reqURL, tt.args.result, tt.args.apiPathPrefix, tt.args.reqInfo)
if (err != nil) != tt.wantErr {
t.Errorf("updatePathNewGVK() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("updatePathNewGVK() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_reqWithoutPrefix(t *testing.T) {
body := ioutil.NopCloser(bytes.NewBuffer([]byte("some body")))
newReq := func(rawurl string) *http.Request {
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, rawurl, body)
require.NoError(t, err)
return req
}
type args struct {
req *http.Request
hostURL string
apiPathPrefix string
}
tests := []struct {
name string
args args
want *http.Request
}{
{
name: "happy path",
args: args{
req: newReq("https://walrus.tld/apis/some/path"),
hostURL: "https://walrus.tld",
apiPathPrefix: "/apis",
},
want: newReq("https://walrus.tld/some/path"),
},
{
name: "host url already has slash suffix",
args: args{
req: newReq("https://walrus.tld/apis/some/path"),
hostURL: "https://walrus.tld/",
apiPathPrefix: "/apis",
},
want: newReq("https://walrus.tld/some/path"),
},
{
name: "api prefix already has slash prefix",
args: args{
req: newReq("https://walrus.tld/apis/some/path"),
hostURL: "https://walrus.tld",
apiPathPrefix: "apis",
},
want: newReq("https://walrus.tld/some/path"),
},
{
name: "api prefix already has slash suffix",
args: args{
req: newReq("https://walrus.tld/apis/some/path"),
hostURL: "https://walrus.tld",
apiPathPrefix: "/apis/",
},
want: newReq("https://walrus.tld/some/path"),
},
{
name: "no api path prefix",
args: args{
req: newReq("https://walrus.tld"),
},
want: newReq("https://walrus.tld"),
},
{
name: "hostURL and req URL mismatch",
args: args{
req: newReq("https://walrus.tld.some-other-url/some/path"),
hostURL: "https://walrus.tld",
apiPathPrefix: "/apis",
},
want: newReq("https://walrus.tld.some-other-url/some/path"),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
req := *tt.args.req
if got := reqWithoutPrefix(&req, tt.args.hostURL, tt.args.apiPathPrefix); !reflect.DeepEqual(got, tt.want) {
t.Errorf("reqWithoutPrefix() = %v, want %v", got, tt.want)
}
})
}
}
func mustParse(t *testing.T, rawurl string) *url.URL {
t.Helper()
url, err := url.Parse(rawurl)
require.NoError(t, err)
return url
}