diff --git a/central/graphql/resolvers/cluster_vulnerabilities_test.go b/central/graphql/resolvers/cluster_vulnerabilities_test.go new file mode 100644 index 0000000000000..62cf4adc9588f --- /dev/null +++ b/central/graphql/resolvers/cluster_vulnerabilities_test.go @@ -0,0 +1,25 @@ +package resolvers + +import ( + "reflect" + "testing" +) + +func TestClusterVulnerabilityResolverType(t *testing.T) { + // The implementation type has four more methods than the interface it implements. + // + // 17 - SnoozeExpiry + // 18 - SnoozeStart + // 19 - Snoozed + // 24 - Type + // + // This can break graphQL queries to the system until + // https://github.com/graph-gophers/graphql-go/issues/763 is fixed. + // + // TODO(ROX-35654): Unskip this tests. + t.Skip("Interface and implementation types do not have aligned method indices.") + resolverInterface := reflect.TypeOf((*ClusterVulnerabilityResolver)(nil)).Elem() + resolverImplType := reflect.TypeOf((*clusterCVEResolver)(nil)) + + validateAlignedMethodIndex(t, resolverInterface, resolverImplType) +} diff --git a/central/graphql/resolvers/image_components_test.go b/central/graphql/resolvers/image_components_test.go new file mode 100644 index 0000000000000..8f93bfd5b5039 --- /dev/null +++ b/central/graphql/resolvers/image_components_test.go @@ -0,0 +1,23 @@ +package resolvers + +import ( + "reflect" + "testing" +) + +func TestImageComponentResolverType(t *testing.T) { + // The implementation type has two more methods than the interface it implements. + // + // 0 - Architecture + // 7 - ImageId + // + // This can break graphQL queries to the system until + // https://github.com/graph-gophers/graphql-go/issues/763 is fixed. + // + // TODO(ROX-35654): Unskip this tests. + t.Skip("Interface and implementation types do not have aligned method indices.") + resolverInterface := reflect.TypeOf((*ImageComponentResolver)(nil)).Elem() + resolverImplType := reflect.TypeOf((*imageComponentV2Resolver)(nil)) + + validateAlignedMethodIndex(t, resolverInterface, resolverImplType) +} diff --git a/central/graphql/resolvers/image_resolver_test.go b/central/graphql/resolvers/image_resolver_test.go new file mode 100644 index 0000000000000..6d08c5d99b923 --- /dev/null +++ b/central/graphql/resolvers/image_resolver_test.go @@ -0,0 +1,20 @@ +package resolvers + +import ( + "reflect" + "testing" +) + +func TestImageResolverType(t *testing.T) { + resolverInterface := reflect.TypeOf((*ImageResolver)(nil)).Elem() + resolverImplType := reflect.TypeOf((*imageResolver)(nil)) + + validateAlignedMethodIndex(t, resolverInterface, resolverImplType) +} + +func TestImageV2ResolverType(t *testing.T) { + resolverInterface := reflect.TypeOf((*ImageResolver)(nil)).Elem() + resolverImplType := reflect.TypeOf((*imageV2Resolver)(nil)) + + validateAlignedMethodIndex(t, resolverInterface, resolverImplType) +} diff --git a/central/graphql/resolvers/image_vulnerabilities_test.go b/central/graphql/resolvers/image_vulnerabilities_test.go new file mode 100644 index 0000000000000..e76ce4fbd721a --- /dev/null +++ b/central/graphql/resolvers/image_vulnerabilities_test.go @@ -0,0 +1,26 @@ +package resolvers + +import ( + "reflect" + "testing" +) + +func TestImageVulnerabilityResolverType(t *testing.T) { + // The implementation type has five more methods than the interface it implements. + // + // 2 - ComponentId + // 12 - FirstImageOccurrence + // 14 - ID + // 19 - ImageId + // 32 - State + // + // This can break graphQL queries to the system until + // https://github.com/graph-gophers/graphql-go/issues/763 is fixed. + // + // TODO(ROX-35654): Unskip this tests. + t.Skip("Interface and implementation types do not have aligned method indices.") + resolverInterface := reflect.TypeOf((*ImageVulnerabilityResolver)(nil)).Elem() + resolverImplType := reflect.TypeOf((*imageCVEV2Resolver)(nil)) + + validateAlignedMethodIndex(t, resolverInterface, resolverImplType) +} diff --git a/central/graphql/resolvers/node_components_test.go b/central/graphql/resolvers/node_components_test.go new file mode 100644 index 0000000000000..bf86d8adbbbb2 --- /dev/null +++ b/central/graphql/resolvers/node_components_test.go @@ -0,0 +1,13 @@ +package resolvers + +import ( + "reflect" + "testing" +) + +func TestNodeComponentResolverType(t *testing.T) { + resolverInterface := reflect.TypeOf((*NodeComponentResolver)(nil)).Elem() + resolverImplType := reflect.TypeOf((*nodeComponentResolver)(nil)) + + validateAlignedMethodIndex(t, resolverInterface, resolverImplType) +} diff --git a/central/graphql/resolvers/node_vulnerabilities_test.go b/central/graphql/resolvers/node_vulnerabilities_test.go new file mode 100644 index 0000000000000..2dc1340d56742 --- /dev/null +++ b/central/graphql/resolvers/node_vulnerabilities_test.go @@ -0,0 +1,27 @@ +package resolvers + +import ( + "reflect" + "testing" +) + +func TestNodeVulnerabilityResolverType(t *testing.T) { + // The implementation type has six more methods than the interface it implements. + // + // 6 - ID + // 18 - Orphaned + // 19 - OrphanedTime + // 23 - SnoozeExpiry + // 24 - SnoozeStart + // 25 - Snoozed + // + // This can break graphQL queries to the system until + // https://github.com/graph-gophers/graphql-go/issues/763 is fixed. + // + // TODO(ROX-35654): Unskip this tests. + t.Skip("Interface and implementation types do not have aligned method indices.") + resolverInterface := reflect.TypeOf((*NodeVulnerabilityResolver)(nil)).Elem() + resolverImplType := reflect.TypeOf((*nodeCVEResolver)(nil)) + + validateAlignedMethodIndex(t, resolverInterface, resolverImplType) +} diff --git a/central/graphql/resolvers/test_utils_test.go b/central/graphql/resolvers/test_utils_test.go new file mode 100644 index 0000000000000..83451dd54dd78 --- /dev/null +++ b/central/graphql/resolvers/test_utils_test.go @@ -0,0 +1,80 @@ +package resolvers + +import ( + "reflect" + "testing" + + "github.com/stretchr/testify/assert" +) + +func validateAlignedMethodIndex(t testing.TB, type1 reflect.Type, type2 reflect.Type) { + t.Helper() + + if !assert.Equalf(t, type1.NumMethod(), type2.NumMethod(), + "Types %s and %s have should have the same number of methods", + type1.String(), type2.String(), + ) { + dumpTypeMethods(t, type1, type1.String(), false) + dumpTypeMethods(t, type2, type2.String(), false) + return + } + for i := range type1.NumMethod() { + m1 := type1.Method(i) + m2 := type2.Method(i) + assert.Equal(t, m1.Name, m2.Name) + } +} + +// dumpTypeMethods uses reflection to dump the index and names of methods for a given type. +// It accepts any resolver value and outputs method information to the test logger. +// +// Example usage: +// +// // After creating a resolver instance in a test: +// componentResolver, err := resolver.ImageComponent(ctx, struct{ ID *graphql.ID }{ID: &componentID}) +// require.NoError(t, err) +// dumpTypeMethods(t, reflect.TypeOf(componentResolver), "imageComponentV2Resolver") +// +// Output includes: +// - Index of each method (0-based) +// - Method name +// - Full method signature +// - Input parameter types +// - Output parameter types +func dumpTypeMethods(t testing.TB, typ reflect.Type, typeName string, verbose bool) { + t.Logf("\n=== Methods of %s ===", typeName) + t.Logf("Type: %s", typ.String()) + t.Logf("Kind: %s", typ.Kind()) + t.Logf("Number of methods: %d\n", typ.NumMethod()) + + for i := 0; i < typ.NumMethod(); i++ { + method := typ.Method(i) + t.Logf("[%d] %s", i, method.Name) + + if verbose { + // Also log the method signature + methodType := method.Type + t.Logf(" Signature: %s", methodType.String()) + + // Log input parameters + numIn := methodType.NumIn() + if numIn > 0 { + t.Logf(" Inputs (%d):", numIn) + for j := 0; j < numIn; j++ { + t.Logf(" [%d] %s", j, methodType.In(j).String()) + } + } + + // Log return parameters + numOut := methodType.NumOut() + if numOut > 0 { + t.Logf(" Outputs (%d):", numOut) + for j := 0; j < numOut; j++ { + t.Logf(" [%d] %s", j, methodType.Out(j).String()) + } + } + t.Logf("") + } + } + t.Logf("=== End of methods for %s ===\n", typeName) +}