Skip to content

Commit 43b45f3

Browse files
authored
Fix: relations nil pointer check (#68)
* added nil checks in relation resovling On-behalf-of: @SAP [email protected] Signed-off-by: Artem Shcherbatiuk <[email protected]>
1 parent 4a879fa commit 43b45f3

File tree

4 files changed

+403
-21
lines changed

4 files changed

+403
-21
lines changed

gateway/schema/recursion_test.go

Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
package schema_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/go-openapi/spec"
7+
"github.com/graphql-go/graphql"
8+
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
9+
"k8s.io/apimachinery/pkg/runtime/schema"
10+
11+
"github.com/platform-mesh/golang-commons/logger/testlogger"
12+
"github.com/platform-mesh/kubernetes-graphql-gateway/gateway/resolver"
13+
gatewaySchema "github.com/platform-mesh/kubernetes-graphql-gateway/gateway/schema"
14+
)
15+
16+
func TestConvertSwaggerTypeToGraphQL_WithNilInCache(t *testing.T) {
17+
log := testlogger.New().Logger
18+
mockResolver := &mockResolverProvider{}
19+
20+
tests := []struct {
21+
name string
22+
definitions spec.Definitions
23+
setupCache func(*gatewaySchema.Gateway)
24+
expectedNoPanic bool
25+
expectedReturnType bool
26+
}{
27+
{
28+
name: "handles_nil_in_cache_for_recursive_ref",
29+
definitions: spec.Definitions{
30+
"io.test.v1.RecursiveType": spec.Schema{
31+
SchemaProps: spec.SchemaProps{
32+
Type: []string{"object"},
33+
Properties: map[string]spec.Schema{
34+
"name": {
35+
SchemaProps: spec.SchemaProps{
36+
Type: []string{"string"},
37+
},
38+
},
39+
"parent": {
40+
SchemaProps: spec.SchemaProps{
41+
Ref: spec.MustCreateRef("#/definitions/io.test.v1.RecursiveType"),
42+
},
43+
},
44+
},
45+
},
46+
VendorExtensible: spec.VendorExtensible{
47+
Extensions: map[string]interface{}{
48+
"x-kubernetes-group-version-kind": []interface{}{
49+
map[string]interface{}{
50+
"group": "test",
51+
"version": "v1",
52+
"kind": "RecursiveType",
53+
},
54+
},
55+
},
56+
},
57+
},
58+
},
59+
expectedNoPanic: true,
60+
expectedReturnType: true,
61+
},
62+
{
63+
name: "handles_nested_object_with_nil_in_cache",
64+
definitions: spec.Definitions{
65+
"io.test.v1.NestedType": spec.Schema{
66+
SchemaProps: spec.SchemaProps{
67+
Type: []string{"object"},
68+
Properties: map[string]spec.Schema{
69+
"spec": {
70+
SchemaProps: spec.SchemaProps{
71+
Type: []string{"object"},
72+
Properties: map[string]spec.Schema{
73+
"nested": {
74+
SchemaProps: spec.SchemaProps{
75+
Type: []string{"object"},
76+
Properties: map[string]spec.Schema{
77+
"field": {
78+
SchemaProps: spec.SchemaProps{
79+
Type: []string{"string"},
80+
},
81+
},
82+
},
83+
},
84+
},
85+
},
86+
},
87+
},
88+
},
89+
},
90+
VendorExtensible: spec.VendorExtensible{
91+
Extensions: map[string]interface{}{
92+
"x-kubernetes-group-version-kind": []interface{}{
93+
map[string]interface{}{
94+
"group": "test",
95+
"version": "v1",
96+
"kind": "NestedType",
97+
},
98+
},
99+
},
100+
},
101+
},
102+
},
103+
expectedNoPanic: true,
104+
expectedReturnType: true,
105+
},
106+
}
107+
108+
for _, tt := range tests {
109+
t.Run(tt.name, func(t *testing.T) {
110+
defer func() {
111+
if r := recover(); r != nil {
112+
if tt.expectedNoPanic {
113+
t.Errorf("Test panicked when it shouldn't: %v", r)
114+
}
115+
}
116+
}()
117+
118+
gateway, err := gatewaySchema.New(log, tt.definitions, mockResolver)
119+
if err != nil && tt.expectedNoPanic {
120+
t.Errorf("Schema creation failed: %v", err)
121+
return
122+
}
123+
124+
if gateway != nil && tt.expectedReturnType {
125+
schemaObj := gateway.GetSchema()
126+
if schemaObj == nil {
127+
t.Error("Expected schema to be created but got nil")
128+
}
129+
}
130+
})
131+
}
132+
}
133+
134+
func TestHandleObjectFieldSpecType_WithNilInCache(t *testing.T) {
135+
log := testlogger.New().Logger
136+
mockResolver := &mockResolverProvider{}
137+
138+
definitions := spec.Definitions{
139+
"io.test.v1.SelfReferencing": spec.Schema{
140+
SchemaProps: spec.SchemaProps{
141+
Type: []string{"object"},
142+
Properties: map[string]spec.Schema{
143+
"metadata": {
144+
SchemaProps: spec.SchemaProps{
145+
Type: []string{"object"},
146+
Properties: map[string]spec.Schema{
147+
"name": {
148+
SchemaProps: spec.SchemaProps{
149+
Type: []string{"string"},
150+
},
151+
},
152+
"labels": {
153+
SchemaProps: spec.SchemaProps{
154+
Type: []string{"object"},
155+
AdditionalProperties: &spec.SchemaOrBool{
156+
Schema: &spec.Schema{
157+
SchemaProps: spec.SchemaProps{
158+
Type: []string{"string"},
159+
},
160+
},
161+
},
162+
},
163+
},
164+
},
165+
},
166+
},
167+
"spec": {
168+
SchemaProps: spec.SchemaProps{
169+
Type: []string{"object"},
170+
Properties: map[string]spec.Schema{
171+
"template": {
172+
SchemaProps: spec.SchemaProps{
173+
Ref: spec.MustCreateRef("#/definitions/io.test.v1.SelfReferencing"),
174+
},
175+
},
176+
},
177+
},
178+
},
179+
},
180+
},
181+
VendorExtensible: spec.VendorExtensible{
182+
Extensions: map[string]interface{}{
183+
"x-kubernetes-group-version-kind": []interface{}{
184+
map[string]interface{}{
185+
"group": "test",
186+
"version": "v1",
187+
"kind": "SelfReferencing",
188+
},
189+
},
190+
},
191+
},
192+
},
193+
}
194+
195+
t.Run("no_panic_with_self_referencing_object", func(t *testing.T) {
196+
defer func() {
197+
if r := recover(); r != nil {
198+
t.Errorf("Test panicked: %v", r)
199+
}
200+
}()
201+
202+
gateway, err := gatewaySchema.New(log, definitions, mockResolver)
203+
if err != nil {
204+
t.Errorf("Schema creation failed: %v", err)
205+
return
206+
}
207+
208+
if gateway == nil {
209+
t.Error("Expected gateway to be created but got nil")
210+
return
211+
}
212+
213+
schemaObj := gateway.GetSchema()
214+
if schemaObj == nil {
215+
t.Error("Expected schema to be created but got nil")
216+
}
217+
})
218+
}
219+
220+
func TestFindRelationTarget_WithNilInCache(t *testing.T) {
221+
log := testlogger.New().Logger
222+
mockResolver := &mockResolverProvider{}
223+
224+
definitions := spec.Definitions{
225+
"io.test.v1.Parent": spec.Schema{
226+
SchemaProps: spec.SchemaProps{
227+
Type: []string{"object"},
228+
Properties: map[string]spec.Schema{
229+
"childRef": {
230+
SchemaProps: spec.SchemaProps{
231+
Type: []string{"object"},
232+
Properties: map[string]spec.Schema{
233+
"name": {
234+
SchemaProps: spec.SchemaProps{
235+
Type: []string{"string"},
236+
},
237+
},
238+
},
239+
},
240+
},
241+
},
242+
},
243+
VendorExtensible: spec.VendorExtensible{
244+
Extensions: map[string]interface{}{
245+
"x-kubernetes-group-version-kind": []interface{}{
246+
map[string]interface{}{
247+
"group": "test",
248+
"version": "v1",
249+
"kind": "Parent",
250+
},
251+
},
252+
"x-kubernetes-resource-scope": "Namespaced",
253+
},
254+
},
255+
},
256+
"io.test.v1.Child": spec.Schema{
257+
SchemaProps: spec.SchemaProps{
258+
Type: []string{"object"},
259+
Properties: map[string]spec.Schema{
260+
"parentRef": {
261+
SchemaProps: spec.SchemaProps{
262+
Type: []string{"object"},
263+
Properties: map[string]spec.Schema{
264+
"name": {
265+
SchemaProps: spec.SchemaProps{
266+
Type: []string{"string"},
267+
},
268+
},
269+
},
270+
},
271+
},
272+
},
273+
},
274+
VendorExtensible: spec.VendorExtensible{
275+
Extensions: map[string]interface{}{
276+
"x-kubernetes-group-version-kind": []interface{}{
277+
map[string]interface{}{
278+
"group": "test",
279+
"version": "v1",
280+
"kind": "Child",
281+
},
282+
},
283+
"x-kubernetes-resource-scope": "Namespaced",
284+
},
285+
},
286+
},
287+
}
288+
289+
t.Run("no_panic_with_cross_references", func(t *testing.T) {
290+
defer func() {
291+
if r := recover(); r != nil {
292+
t.Errorf("Test panicked: %v", r)
293+
}
294+
}()
295+
296+
gateway, err := gatewaySchema.New(log, definitions, mockResolver)
297+
if err != nil {
298+
t.Errorf("Schema creation failed: %v", err)
299+
return
300+
}
301+
302+
if gateway == nil {
303+
t.Error("Expected gateway to be created but got nil")
304+
return
305+
}
306+
307+
schemaObj := gateway.GetSchema()
308+
if schemaObj == nil {
309+
t.Error("Expected schema to be created but got nil")
310+
}
311+
})
312+
}
313+
314+
type mockResolverProvider struct{}
315+
316+
func (m *mockResolverProvider) CommonResolver() graphql.FieldResolveFn {
317+
return func(p graphql.ResolveParams) (interface{}, error) {
318+
return nil, nil
319+
}
320+
}
321+
322+
func (m *mockResolverProvider) ListItems(gvk schema.GroupVersionKind, scope v1.ResourceScope) graphql.FieldResolveFn {
323+
return func(p graphql.ResolveParams) (interface{}, error) {
324+
return []interface{}{}, nil
325+
}
326+
}
327+
328+
func (m *mockResolverProvider) GetItem(gvk schema.GroupVersionKind, scope v1.ResourceScope) graphql.FieldResolveFn {
329+
return func(p graphql.ResolveParams) (interface{}, error) {
330+
return map[string]interface{}{}, nil
331+
}
332+
}
333+
334+
func (m *mockResolverProvider) GetItemAsYAML(gvk schema.GroupVersionKind, scope v1.ResourceScope) graphql.FieldResolveFn {
335+
return func(p graphql.ResolveParams) (interface{}, error) {
336+
return "", nil
337+
}
338+
}
339+
340+
func (m *mockResolverProvider) CreateItem(gvk schema.GroupVersionKind, scope v1.ResourceScope) graphql.FieldResolveFn {
341+
return func(p graphql.ResolveParams) (interface{}, error) {
342+
return map[string]interface{}{}, nil
343+
}
344+
}
345+
346+
func (m *mockResolverProvider) UpdateItem(gvk schema.GroupVersionKind, scope v1.ResourceScope) graphql.FieldResolveFn {
347+
return func(p graphql.ResolveParams) (interface{}, error) {
348+
return map[string]interface{}{}, nil
349+
}
350+
}
351+
352+
func (m *mockResolverProvider) DeleteItem(gvk schema.GroupVersionKind, scope v1.ResourceScope) graphql.FieldResolveFn {
353+
return func(p graphql.ResolveParams) (interface{}, error) {
354+
return true, nil
355+
}
356+
}
357+
358+
func (m *mockResolverProvider) SubscribeItem(gvk schema.GroupVersionKind, scope v1.ResourceScope) graphql.FieldResolveFn {
359+
return func(p graphql.ResolveParams) (interface{}, error) {
360+
return nil, nil
361+
}
362+
}
363+
364+
func (m *mockResolverProvider) SubscribeItems(gvk schema.GroupVersionKind, scope v1.ResourceScope) graphql.FieldResolveFn {
365+
return func(p graphql.ResolveParams) (interface{}, error) {
366+
return nil, nil
367+
}
368+
}
369+
370+
func (m *mockResolverProvider) RelationResolver(baseName string, gvk schema.GroupVersionKind) graphql.FieldResolveFn {
371+
return func(p graphql.ResolveParams) (interface{}, error) {
372+
return map[string]interface{}{}, nil
373+
}
374+
}
375+
376+
func (m *mockResolverProvider) TypeByCategory(typeByCategory map[string][]resolver.TypeByCategory) graphql.FieldResolveFn {
377+
return func(p graphql.ResolveParams) (interface{}, error) {
378+
return []interface{}{}, nil
379+
}
380+
}
381+
382+
func (m *mockResolverProvider) SanitizeGroupName(group string) string {
383+
return group
384+
}
385+
386+
var _ resolver.Provider = (*mockResolverProvider)(nil)

0 commit comments

Comments
 (0)