1
16
17 package openapi
18
19 import (
20 "context"
21 "encoding/json"
22 "strings"
23 "testing"
24 "time"
25
26 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
27 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
28 "k8s.io/apiextensions-apiserver/test/integration/fixtures"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/apimachinery/pkg/util/wait"
31 "k8s.io/client-go/dynamic"
32 kubernetes "k8s.io/client-go/kubernetes"
33 "k8s.io/kube-openapi/pkg/validation/spec"
34 apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
35 "k8s.io/kubernetes/test/integration/framework"
36 )
37
38 func TestOpenAPIV2CRDMergeNoDuplicateTypes(t *testing.T) {
39 server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, framework.SharedEtcd())
40 if err != nil {
41 t.Fatal(err)
42 }
43 defer server.TearDownFn()
44 config := server.ClientConfig
45
46 apiExtensionClient, err := clientset.NewForConfig(config)
47 if err != nil {
48 t.Fatal(err)
49 }
50 dynamicClient, err := dynamic.NewForConfig(config)
51 if err != nil {
52 t.Fatal(err)
53 }
54 clientset, err := kubernetes.NewForConfig(config)
55 if err != nil {
56 t.Fatal(err)
57 }
58
59 foo := &apiextensionsv1.CustomResourceDefinition{
60 ObjectMeta: metav1.ObjectMeta{
61 Name: "foosubs.cr.bar.com",
62 },
63 Spec: apiextensionsv1.CustomResourceDefinitionSpec{
64 Group: "cr.bar.com",
65 Scope: apiextensionsv1.NamespaceScoped,
66 Names: apiextensionsv1.CustomResourceDefinitionNames{
67 Plural: "foosubs",
68 Kind: "FooSub",
69 },
70 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
71 {
72 Name: "v1",
73 Served: true,
74 Storage: true,
75 Schema: &apiextensionsv1.CustomResourceValidation{
76 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
77 Type: "object",
78 Properties: map[string]apiextensionsv1.JSONSchemaProps{
79 "spec": {
80 Type: "object",
81 Properties: map[string]apiextensionsv1.JSONSchemaProps{
82 "replicas": {
83 Type: "integer",
84 },
85 },
86 },
87 "status": {
88 Type: "object",
89 Properties: map[string]apiextensionsv1.JSONSchemaProps{
90 "replicas": {
91 Type: "integer",
92 },
93 },
94 },
95 },
96 },
97 },
98 Subresources: &apiextensionsv1.CustomResourceSubresources{
99 Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
100 Scale: &apiextensionsv1.CustomResourceSubresourceScale{
101 SpecReplicasPath: ".spec.replicas",
102 StatusReplicasPath: ".status.replicas",
103 },
104 },
105 },
106 },
107 },
108 }
109
110 baz := &apiextensionsv1.CustomResourceDefinition{
111 ObjectMeta: metav1.ObjectMeta{
112 Name: "bazsubs.cr.bar.com",
113 },
114 Spec: apiextensionsv1.CustomResourceDefinitionSpec{
115 Group: "cr.bar.com",
116 Scope: apiextensionsv1.NamespaceScoped,
117 Names: apiextensionsv1.CustomResourceDefinitionNames{
118 Plural: "bazsubs",
119 Kind: "BazSub",
120 },
121 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
122 {
123 Name: "v1",
124 Served: true,
125 Storage: true,
126 Schema: &apiextensionsv1.CustomResourceValidation{
127 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
128 Type: "object",
129 Properties: map[string]apiextensionsv1.JSONSchemaProps{
130 "spec": {
131 Type: "object",
132 Properties: map[string]apiextensionsv1.JSONSchemaProps{
133 "replicas": {
134 Type: "integer",
135 },
136 },
137 },
138 "status": {
139 Type: "object",
140 Properties: map[string]apiextensionsv1.JSONSchemaProps{
141 "replicas": {
142 Type: "integer",
143 },
144 },
145 },
146 },
147 },
148 },
149 Subresources: &apiextensionsv1.CustomResourceSubresources{
150 Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
151 Scale: &apiextensionsv1.CustomResourceSubresourceScale{
152 SpecReplicasPath: ".spec.replicas",
153 StatusReplicasPath: ".status.replicas",
154 },
155 },
156 },
157 },
158 },
159 }
160
161 _, err = fixtures.CreateNewV1CustomResourceDefinition(foo, apiExtensionClient, dynamicClient)
162 if err != nil {
163 t.Fatal(err)
164 }
165
166 _, err = fixtures.CreateNewV1CustomResourceDefinition(baz, apiExtensionClient, dynamicClient)
167 if err != nil {
168 t.Fatal(err)
169 }
170
171 var openAPISpec spec.Swagger
172
173 wait.Poll(time.Second*1, wait.ForeverTestTimeout, func() (bool, error) {
174 jsonData, err := clientset.RESTClient().Get().AbsPath("/openapi/v2").Do(context.TODO()).Raw()
175 if err != nil {
176 t.Fatal(err)
177 }
178 openAPISpec = spec.Swagger{}
179 err = json.Unmarshal(jsonData, &openAPISpec)
180 if err != nil {
181 t.Fatal(err)
182 }
183 for schemaName := range openAPISpec.Definitions {
184 if strings.HasPrefix(schemaName, "com.bar.cr.v1.BazSub") {
185 return true, nil
186 }
187 }
188 return false, nil
189 })
190
191 for schemaName := range openAPISpec.Definitions {
192 if strings.HasSuffix(schemaName, "_v2") {
193 t.Errorf("Error: Expected no _v2 types, got %s", schemaName)
194 }
195 }
196 }
197
View as plain text