Skip to content
This repository was archived by the owner on Aug 28, 2025. It is now read-only.

Commit a9a360c

Browse files
committed
add test with preferred resource
On-behalf-of: @SAP [email protected] Signed-off-by: Artem Shcherbatiuk <[email protected]>
1 parent 5cd1b84 commit a9a360c

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

listener/pkg/apischema/builder.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,52 @@ func (b *SchemaBuilder) buildKindRegistry() {
292292
}
293293

294294
// No sorting needed - each GVK is now uniquely indexed
295+
// Check for kinds with multiple resources but no preferred versions
296+
b.warnAboutMissingPreferredVersions()
297+
295298
b.log.Debug().Int("gvkCount", len(b.kindRegistry)).Msg("built kind registry for relationships")
296299
}
297300

301+
// warnAboutMissingPreferredVersions checks for kinds with multiple resources but no preferred versions
302+
func (b *SchemaBuilder) warnAboutMissingPreferredVersions() {
303+
// Group resources by kind name to find potential conflicts
304+
kindGroups := make(map[string][]ResourceInfo)
305+
306+
for _, resourceInfo := range b.kindRegistry {
307+
kindKey := strings.ToLower(resourceInfo.Kind)
308+
kindGroups[kindKey] = append(kindGroups[kindKey], resourceInfo)
309+
}
310+
311+
// Check each kind that has multiple resources
312+
for kindName, resources := range kindGroups {
313+
if len(resources) <= 1 {
314+
continue // No conflict possible
315+
}
316+
317+
// Check if any of the resources has a preferred version
318+
hasPreferred := false
319+
for _, resource := range resources {
320+
key := fmt.Sprintf("%s/%s", resource.Group, resource.Kind)
321+
if b.preferredVersions[key] == resource.Version {
322+
hasPreferred = true
323+
break
324+
}
325+
}
326+
327+
// Warn if no preferred version found
328+
if !hasPreferred {
329+
groups := make([]string, 0, len(resources))
330+
for _, resource := range resources {
331+
groups = append(groups, fmt.Sprintf("%s/%s", resource.Group, resource.Version))
332+
}
333+
b.log.Warn().
334+
Str("kind", kindName).
335+
Strs("availableResources", groups).
336+
Msg("Multiple resources found for kind with no preferred version - using fallback resolution. Consider setting preferred versions for better API governance.")
337+
}
338+
}
339+
}
340+
298341
// findBestResourceForKind finds the best matching resource for a given kind name
299342
// using preferred version logic and group prioritization
300343
func (b *SchemaBuilder) findBestResourceForKind(kindName string) *ResourceInfo {

listener/pkg/apischema/relationships_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
apischema "github.com/openmfp/kubernetes-graphql-gateway/listener/pkg/apischema"
88
apimocks "github.com/openmfp/kubernetes-graphql-gateway/listener/pkg/apischema/mocks"
99
"github.com/stretchr/testify/assert"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1011
"k8s.io/client-go/openapi"
1112
"k8s.io/kube-openapi/pkg/validation/spec"
1213
)
@@ -82,3 +83,47 @@ func Test_build_kind_registry_lowercases_keys_and_picks_first(t *testing.T) {
8283
// ensure it referenced the first group
8384
assert.Contains(t, added.Ref.String(), "#/definitions/a.example.v1.Thing")
8485
}
86+
87+
func Test_preferred_version_takes_priority_over_fallback(t *testing.T) {
88+
mock := apimocks.NewMockClient(t)
89+
mock.EXPECT().Paths().Return(map[string]openapi.GroupVersion{}, nil)
90+
b := apischema.NewSchemaBuilder(mock, nil, testlogger.New().Logger)
91+
92+
// Multiple schemas with same Kind - a.example would win alphabetically,
93+
// but we'll set z.last as preferred to verify it takes priority
94+
childA := schemaWithGVK("a.example", "v1", "Child")
95+
childB := schemaWithGVK("b.example", "v1", "Child")
96+
childZ := schemaWithGVK("z.last", "v1", "Child") // would be last alphabetically
97+
98+
b.SetSchemas(map[string]*spec.Schema{
99+
"a.example.v1.Child": childA,
100+
"b.example.v1.Child": childB,
101+
"z.last.v1.Child": childZ,
102+
})
103+
104+
// Set z.last as preferred (even though it would be last alphabetically)
105+
b.WithPreferredVersions([]*metav1.APIResourceList{
106+
{
107+
GroupVersion: "z.last/v1",
108+
APIResources: []metav1.APIResource{
109+
{Kind: "Child"},
110+
},
111+
},
112+
})
113+
114+
b.WithRelationships()
115+
116+
// Add a parent schema that references childRef
117+
parentSchema := &spec.Schema{SchemaProps: spec.SchemaProps{Properties: map[string]spec.Schema{
118+
"childRef": {SchemaProps: spec.SchemaProps{Type: spec.StringOrArray{"object"}}},
119+
}}}
120+
b.GetSchemas()["x.v1.Parent"] = parentSchema
121+
122+
b.WithRelationships()
123+
added, ok := b.GetSchemas()["x.v1.Parent"].Properties["child"]
124+
assert.True(t, ok, "expected relationship field 'child'")
125+
126+
// Should reference z.last because it's the preferred version, not a.example (alphabetical first)
127+
assert.Contains(t, added.Ref.String(), "#/definitions/z.last.v1.Child",
128+
"expected preferred version z.last to be chosen over alphabetically first a.example")
129+
}

0 commit comments

Comments
 (0)