From b6467b5bb14b3eda53313f02ffec0629b9e1a3ed Mon Sep 17 00:00:00 2001 From: Steven Barker Date: Mon, 16 Oct 2023 13:47:53 +1300 Subject: [PATCH] add enum logic and tests --- .../NadelHydrationArgumentValidation.kt | 16 +- .../validation/NadelSchemaValidationError.kt | 6 +- .../NadelHydrationArgumentValidationTest.kt | 195 ++++++++++++++++++ 3 files changed, 213 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/graphql/nadel/validation/NadelHydrationArgumentValidation.kt b/lib/src/main/java/graphql/nadel/validation/NadelHydrationArgumentValidation.kt index 47f93196f..5be90f28a 100644 --- a/lib/src/main/java/graphql/nadel/validation/NadelHydrationArgumentValidation.kt +++ b/lib/src/main/java/graphql/nadel/validation/NadelHydrationArgumentValidation.kt @@ -126,7 +126,7 @@ internal class NadelHydrationArgumentValidation private constructor() { else if (sourceType == ObjectField && unwrappedHydrationSourceFieldType is GraphQLObjectType && unwrappedActorFieldArgType is GraphQLInputObjectType) { return validateInputObjectArg(unwrappedHydrationSourceFieldType, unwrappedActorFieldArgType, parent, overallField, remoteArg, hydration, actorFieldName) } - // inputObject feed into inputObject (i.e. hydrating with a $argument object) + // inputObject feed into inputObject (i.e. hydrating with an $argument object) else if (sourceType == FieldArgument && unwrappedHydrationSourceFieldType is GraphQLInputObjectType && unwrappedActorFieldArgType is GraphQLInputObjectType) { if (unwrappedHydrationSourceFieldType.name != unwrappedActorFieldArgType.name) { return NadelSchemaValidationError.IncompatibleHydrationArgumentType( @@ -140,6 +140,20 @@ internal class NadelHydrationArgumentValidation private constructor() { } return null } + // if enums they must be the same + else if (unwrappedHydrationSourceFieldType is GraphQLEnumType && unwrappedActorFieldArgType is GraphQLEnumType){ + if (unwrappedHydrationSourceFieldType.name != unwrappedActorFieldArgType.name) { + return NadelSchemaValidationError.IncompatibleHydrationArgumentType( + parent, + overallField, + remoteArg, + hydrationSourceFieldType, + actorFieldArgType, + actorFieldName + ) + } + return null + } // Any other types are not assignable return NadelSchemaValidationError.IncompatibleHydrationArgumentType( parent, diff --git a/lib/src/main/java/graphql/nadel/validation/NadelSchemaValidationError.kt b/lib/src/main/java/graphql/nadel/validation/NadelSchemaValidationError.kt index 733bbc584..6fd239b34 100644 --- a/lib/src/main/java/graphql/nadel/validation/NadelSchemaValidationError.kt +++ b/lib/src/main/java/graphql/nadel/validation/NadelSchemaValidationError.kt @@ -378,7 +378,7 @@ sealed interface NadelSchemaValidationError { else "a supplied argument called \"${remoteArg.remoteArgumentSource.argumentName}\"" "Field \"$of\" tried to hydrate using the actor field \"$actorFieldName\" and argument \"$hydrationArgName\"." + - "However, you are supplying actor field argument with $argumentSuppliedFromSubString " + + " However, you are supplying actor field argument with $argumentSuppliedFromSubString " + "of type $ht which is not assignable to the expected type $at" } @@ -400,7 +400,7 @@ sealed interface NadelSchemaValidationError { val at = GraphQLTypeUtil.simplePrint(actorArgInputType) "Field $of tried to hydrate using actor field \"$actorFieldName\". " + - "However, the type of the static argument you are supplying actor field arg \"$hydrationArgName\" with " + + " However, the type of the static argument you are supplying actor field arg \"$hydrationArgName\" with " + "is not assignable to the expected type $at" } @@ -425,7 +425,7 @@ sealed interface NadelSchemaValidationError { "${parentType.underlying.name}.${remoteArg.remoteArgumentSource.pathToField?.joinToString(separator = ".")}" "Field \"$of\" tried to hydrate using the actor field \"$actorFieldName\" and argument \"$hydrationArgName\"." + - "However, you are supplying actor field argument with the value from $remoteArgSource " + + " However, you are supplying actor field argument with the value from $remoteArgSource " + "and the types are incompatible" } diff --git a/lib/src/test/kotlin/graphql/nadel/validation/NadelHydrationArgumentValidationTest.kt b/lib/src/test/kotlin/graphql/nadel/validation/NadelHydrationArgumentValidationTest.kt index 6284fb2c4..c2c72d193 100644 --- a/lib/src/test/kotlin/graphql/nadel/validation/NadelHydrationArgumentValidationTest.kt +++ b/lib/src/test/kotlin/graphql/nadel/validation/NadelHydrationArgumentValidationTest.kt @@ -1513,6 +1513,201 @@ class NadelHydrationArgumentValidationTest : DescribeSpec({ val errors = validate(fixture) assert(errors.isEmpty()) } + + it("passes a valid enum hydration argument") { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "issues" to """ + type Query { + issue: JiraIssue + } + type JiraIssue @renamed(from: "Issue") { + id: ID! + } + """.trimIndent(), + "users" to """ + type Query { + user( + id: ID! + providerType: ProviderType + ): User + } + type User { + id: ID! + name: String! + } + enum ProviderType { + DEV_INFO + BUILD + DEPLOYMENT + FEATURE_FLAG + REMOTE_LINKS + SECURITY + DOCUMENTATION + DESIGN + OPERATIONS + } + extend type JiraIssue { + creator: User @hydrated( + service: "users" + field: "user" + arguments: [ + {name: "id", value: "$source.creator"}, + { name: "providerType", value: "$source.providerType" }, + ] + ) + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "issues" to """ + type Query { + issue: Issue + } + type Issue { + id: ID! + creator: String! + providerType: ProviderType + } + enum ProviderType { + DEV_INFO + BUILD + DEPLOYMENT + FEATURE_FLAG + REMOTE_LINKS + SECURITY + DOCUMENTATION + DESIGN + OPERATIONS + } + """.trimIndent(), + "users" to """ + type Query { + user( + id: ID!, + providerType: ProviderType + ): User + } + type User { + id: ID! + name: String! + providerType: ProviderType + } + enum ProviderType { + DEV_INFO, + BUILD, + DEPLOYMENT, + FEATURE_FLAG, + REMOTE_LINKS, + SECURITY, + DOCUMENTATION, + DESIGN, + OPERATIONS + } + """.trimIndent(), + ), + ) + val errors = validate(fixture) + assert(errors.map { it.message }.isEmpty()) + } + + it("fails validation on mismatching enums hydration argument") { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "issues" to """ + type Query { + issue: JiraIssue + } + type JiraIssue @renamed(from: "Issue") { + id: ID! + } + """.trimIndent(), + "users" to """ + type Query { + user( + id: ID! + providerType: SomeOtherEnumType + ): User + } + type User { + id: ID! + name: String! + } + enum SomeOtherEnumType { + DEV_INFO + BUILD + } + extend type JiraIssue { + creator: User @hydrated( + service: "users" + field: "user" + arguments: [ + {name: "id", value: "$source.creator"}, + { name: "providerType", value: "$source.providerType" }, + ] + ) + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "issues" to """ + type Query { + issue: Issue + } + type Issue { + id: ID! + creator: String! + providerType: ProviderType + } + enum ProviderType { + DEV_INFO + BUILD + DEPLOYMENT + FEATURE_FLAG + REMOTE_LINKS + SECURITY + DOCUMENTATION + DESIGN + OPERATIONS + } + """.trimIndent(), + "users" to """ + type Query { + user( + id: ID! + name: String + providerType: SomeOtherEnumType + ): User + } + type User { + id: ID! + name: String! + } + enum SomeOtherEnumType { + DEV_INFO, + BUILD, + } + """.trimIndent(), + ), + ) + val errors = validate(fixture) + assert(errors.map { it.message }.isNotEmpty()) + + // Field "JiraIssue.creator" tried to hydrate using the actor field "user" and argument "providerType". + // However, you are supplying actor field argument with the value from field "Issue.providerType" from service "issues" of type ProviderType + // which is not assignable to the expected type SomeOtherEnumType + + val error = errors.assertSingleOfType() + //actor field arg: + assert(error.parentType.overall.name == "JiraIssue") + assert(error.overallField.name == "creator") + assert(error.remoteArg.name == "providerType") + assert(GraphQLTypeUtil.simplePrint(error.actorArgInputType) == "SomeOtherEnumType") + // supplied hydration for arg: + assert(error.parentType.underlying.name == "Issue") + assert(error.remoteArg.remoteArgumentSource.pathToField?.joinToString(separator = ".") == "providerType") + assert(GraphQLTypeUtil.simplePrint(error.hydrationType) == "ProviderType") + } } describe("Hydration static arg validation") { it("fails if the required actor field argument type does not match the supplied source field type") {