client-go/openapi3/root_test.go
Antoine Pelisse 12beb34ceb openapi: Make file client more easy to re-use
A few notes about the change:
1. I need to initialize the fileclient once, in an init function, so I
don't have access to `testing.T` yet.
2. I want to be able to configure the openapi files that I use
3. We already have a "cache" client that wraps another client, we don't
need to re-implement caching here, one can just do:
`cache.NewClient(openapitest.NewFileClient("some/path"))` to do a cached
client. Or initialize it in an init/global var.

Since there is still some value to use the embedded file, make an
alternative constructor while using fs.FS interface to be able to
manipulate both virtual and disk-based filesystems.

Kubernetes-commit: 29503fd8d45bc2c9438e92936bf4111162529b40
2023-03-28 13:40:28 -07:00

319 lines
8.4 KiB
Go

/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package openapi3
import (
"fmt"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/openapi"
"k8s.io/client-go/openapi/openapitest"
)
func TestOpenAPIV3Root_GroupVersions(t *testing.T) {
tests := []struct {
name string
paths map[string]openapi.GroupVersion
expectedGVs []schema.GroupVersion
forcedErr error
}{
{
name: "OpenAPI V3 Root: No openapi.Paths() equals no GroupVersions.",
expectedGVs: []schema.GroupVersion{},
},
{
name: "OpenAPI V3 Root: Single openapi.Path equals one GroupVersion.",
paths: map[string]openapi.GroupVersion{
"apis/apps/v1": nil,
},
expectedGVs: []schema.GroupVersion{
{Group: "apps", Version: "v1"},
},
},
{
name: "OpenAPI V3 Root: Multiple openapi.Paths equals multiple GroupVersions.",
paths: map[string]openapi.GroupVersion{
"apis/apps/v1": nil,
"api/v1": nil,
"apis/batch/v1beta1": nil,
},
// Alphabetical ordering, since GV's are returned sorted.
expectedGVs: []schema.GroupVersion{
{Group: "apps", Version: "v1"},
{Group: "batch", Version: "v1beta1"},
{Group: "", Version: "v1"},
},
},
{
name: "Multiple GroupVersions, some invalid",
paths: map[string]openapi.GroupVersion{
"apis/batch/v1beta1": nil,
"api/v1": nil,
"foo/apps/v1": nil, // bad prefix
"apis/networking.k8s.io/v1alpha1": nil,
"api": nil, // No version
"apis/apps": nil, // Missing Version
"apis/apps/v1": nil,
},
// Alphabetical ordering, since GV's are returned sorted.
expectedGVs: []schema.GroupVersion{
{Group: "apps", Version: "v1"},
{Group: "batch", Version: "v1beta1"},
{Group: "networking.k8s.io", Version: "v1alpha1"},
{Group: "", Version: "v1"},
},
},
{
name: "OpenAPI V3 Root: Forced error returns error.",
forcedErr: fmt.Errorf("openapi client error"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fakeClient := openapitest.FakeClient{
PathsMap: test.paths,
ForcedErr: test.forcedErr,
}
root := NewRoot(fakeClient)
actualGVs, err := root.GroupVersions()
if test.forcedErr != nil {
require.Error(t, err)
} else {
require.NoError(t, err)
}
if !reflect.DeepEqual(test.expectedGVs, actualGVs) {
t.Errorf("expected GroupVersions (%s), got (%s): (%s)\n",
test.expectedGVs, actualGVs, err)
}
})
}
}
func TestOpenAPIV3Root_GVSpec(t *testing.T) {
tests := []struct {
name string
gv schema.GroupVersion
expectedPaths []string
err error
}{
{
name: "OpenAPI V3 for apps/v1 works",
gv: schema.GroupVersion{Group: "apps", Version: "v1"},
expectedPaths: []string{
"/apis/apps/v1/",
"/apis/apps/v1/deployments",
"/apis/apps/v1/replicasets",
"/apis/apps/v1/daemonsets",
},
},
{
name: "OpenAPI V3 for networking/v1alpha1 works",
gv: schema.GroupVersion{Group: "networking.k8s.io", Version: "v1alpha1"},
expectedPaths: []string{
"/apis/networking.k8s.io/v1alpha1/",
},
},
{
name: "OpenAPI V3 for batch/v1 works",
gv: schema.GroupVersion{Group: "batch", Version: "v1"},
expectedPaths: []string{
"/apis/batch/v1/",
"/apis/batch/v1/jobs",
"/apis/batch/v1/cronjobs",
},
},
{
name: "OpenAPI V3 spec not found",
gv: schema.GroupVersion{Group: "not", Version: "found"},
err: &GroupVersionNotFoundError{gv: schema.GroupVersion{Group: "not", Version: "found"}},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
client := openapitest.NewEmbeddedFileClient()
root := NewRoot(client)
gvSpec, err := root.GVSpec(test.gv)
if test.err != nil {
assert.True(t, reflect.DeepEqual(test.err, err))
return
}
require.NoError(t, err)
for _, path := range test.expectedPaths {
if _, found := gvSpec.Paths.Paths[path]; !found {
assert.True(t, found, "expected path not found (%s)\n", path)
}
}
})
}
}
func TestOpenAPIV3Root_GVSpecAsMap(t *testing.T) {
tests := []struct {
name string
gv schema.GroupVersion
expectedPaths []string
err error
}{
{
name: "OpenAPI V3 for apps/v1 works",
gv: schema.GroupVersion{Group: "apps", Version: "v1"},
expectedPaths: []string{
"/apis/apps/v1/",
"/apis/apps/v1/deployments",
"/apis/apps/v1/replicasets",
"/apis/apps/v1/daemonsets",
},
},
{
name: "OpenAPI V3 for networking/v1alpha1 works",
gv: schema.GroupVersion{Group: "networking.k8s.io", Version: "v1alpha1"},
expectedPaths: []string{
"/apis/networking.k8s.io/v1alpha1/",
},
},
{
name: "OpenAPI V3 for batch/v1 works",
gv: schema.GroupVersion{Group: "batch", Version: "v1"},
expectedPaths: []string{
"/apis/batch/v1/",
"/apis/batch/v1/jobs",
"/apis/batch/v1/cronjobs",
},
},
{
name: "OpenAPI V3 spec not found",
gv: schema.GroupVersion{Group: "not", Version: "found"},
err: &GroupVersionNotFoundError{gv: schema.GroupVersion{Group: "not", Version: "found"}},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
root := NewRoot(openapitest.NewEmbeddedFileClient())
gvSpecAsMap, err := root.GVSpecAsMap(test.gv)
if test.err != nil {
assert.True(t, reflect.DeepEqual(test.err, err))
return
}
require.NoError(t, err)
for _, path := range test.expectedPaths {
pathsMap := gvSpecAsMap["paths"]
if _, found := pathsMap.(map[string]interface{})[path]; !found {
assert.True(t, found, "expected path not found (%s)\n", path)
}
}
})
}
}
func TestOpenAPIV3Root_GroupVersionToPath(t *testing.T) {
tests := []struct {
name string
groupVersion schema.GroupVersion
expectedPath string
}{
{
name: "OpenAPI V3 Root: Path to GroupVersion apps group",
groupVersion: schema.GroupVersion{
Group: "apps",
Version: "v1",
},
expectedPath: "apis/apps/v1",
},
{
name: "OpenAPI V3 Root: Path to GroupVersion batch group",
groupVersion: schema.GroupVersion{
Group: "batch",
Version: "v1beta1",
},
expectedPath: "apis/batch/v1beta1",
},
{
name: "OpenAPI V3 Root: Path to GroupVersion core group",
groupVersion: schema.GroupVersion{
Version: "v1",
},
expectedPath: "api/v1",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actualPath := gvToAPIPath(test.groupVersion)
assert.Equal(t, test.expectedPath, actualPath, "expected API path (%s), got (%s)",
test.expectedPath, actualPath)
})
}
}
func TestOpenAPIV3Root_PathToGroupVersion(t *testing.T) {
tests := []struct {
name string
path string
expectedGV schema.GroupVersion
expectedErr bool
}{
{
name: "OpenAPI V3 Root: Path to GroupVersion apps/v1 group",
path: "apis/apps/v1",
expectedGV: schema.GroupVersion{
Group: "apps",
Version: "v1",
},
},
{
name: "Group without Version throws error",
path: "apis/apps",
expectedErr: true,
},
{
name: "OpenAPI V3 Root: Path to GroupVersion batch group",
path: "apis/batch/v1beta1",
expectedGV: schema.GroupVersion{
Group: "batch",
Version: "v1beta1",
},
},
{
name: "OpenAPI V3 Root: Path to GroupVersion core group",
path: "api/v1",
expectedGV: schema.GroupVersion{
Version: "v1",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actualGV, err := pathToGroupVersion(test.path)
if test.expectedErr {
require.Error(t, err, "should have received error for path: %s", test.path)
} else {
require.NoError(t, err, "expected no error, got (%v)", err)
assert.Equal(t, test.expectedGV, actualGV, "expected GroupVersion (%s), got (%s)",
test.expectedGV, actualGV)
}
})
}
}