Skip to content

Commit 9e75a2e

Browse files
smyrickdariuszkuc
andcommitted
Refactor federation validation unit tests (ExpediaGroup#540)
* Refactor federaion validation unit tests Create new unit tests that call the the federation validation functions directly so we don't have to create a entire schema. This will make it easier to clear out other areas now that we delete these tests * Add javadocs to unit test * Update graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/FederatedSchemaValidatorTest.kt Co-Authored-By: Dariusz Kuc <[email protected]> * Update unit test to valid key directive * Update requires directive tests * Add id field for proper @key * Update requires directive tests * Remove unused varialbe * Add federation directive tests with annotations * Fix ktlint * Update graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/FederatedSchemaValidatorTest.kt Co-Authored-By: Dariusz Kuc <[email protected]> * Update graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/FederatedSchemaValidatorTest.kt Co-Authored-By: Dariusz Kuc <[email protected]> * Update directive names * Update test description for key directive * Update test name * Update graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/validation/ValidateKeySetFieldKtTest.kt Co-Authored-By: Dariusz Kuc <[email protected]> Co-authored-by: Dariusz Kuc <[email protected]>
1 parent 9d2be3f commit 9e75a2e

27 files changed

+1314
-811
lines changed

graphql-kotlin-federation/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
<counter>INSTRUCTION</counter>
4343
<minimum>0.95</minimum>
4444
</limit>
45+
<limit>
46+
<counter>BRANCH</counter>
47+
<minimum>0.94</minimum>
48+
</limit>
4549
</limits>
4650
</rule>
4751
</rules>

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/FederatedSchemaGeneratorHooks.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.expediagroup.graphql.federation
1919
import com.expediagroup.graphql.annotations.GraphQLName
2020
import com.expediagroup.graphql.extensions.print
2121
import com.expediagroup.graphql.federation.directives.FieldSet
22+
import com.expediagroup.graphql.federation.directives.KEY_DIRECTIVE_NAME
2223
import com.expediagroup.graphql.federation.directives.extendsDirectiveType
2324
import com.expediagroup.graphql.federation.execution.EntityResolver
2425
import com.expediagroup.graphql.federation.execution.FederatedTypeRegistry
@@ -91,7 +92,7 @@ open class FederatedSchemaGeneratorHooks(private val federatedTypeRegistry: Fede
9192
val entityTypeNames = originalSchema.allTypesAsList
9293
.asSequence()
9394
.filterIsInstance<GraphQLObjectType>()
94-
.filter { type -> type.getDirective("key") != null }
95+
.filter { type -> type.getDirective(KEY_DIRECTIVE_NAME) != null }
9596
.map { it.name }
9697
.toSet()
9798

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/FederatedSchemaValidator.kt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
package com.expediagroup.graphql.federation
1818

19+
import com.expediagroup.graphql.federation.directives.EXTENDS_DIRECTIVE_NAME
20+
import com.expediagroup.graphql.federation.directives.EXTERNAL_DIRECTIVE_NAME
21+
import com.expediagroup.graphql.federation.directives.KEY_DIRECTIVE_NAME
22+
import com.expediagroup.graphql.federation.directives.PROVIDES_DIRECTIVE_NAME
23+
import com.expediagroup.graphql.federation.directives.REQUIRES_DIRECTIVE_NAME
1924
import com.expediagroup.graphql.federation.exception.InvalidFederatedSchema
2025
import com.expediagroup.graphql.federation.extensions.isFederatedType
2126
import com.expediagroup.graphql.federation.validation.validateDirective
@@ -55,29 +60,29 @@ class FederatedSchemaValidator {
5560
private fun validate(federatedType: String, fields: List<GraphQLFieldDefinition>, directives: Map<String, GraphQLDirective>) {
5661
val errors = mutableListOf<String>()
5762
val fieldMap = fields.associateBy { it.name }
58-
val extendedType = directives.containsKey("extends")
63+
val extendedType = directives.containsKey(EXTENDS_DIRECTIVE_NAME)
5964

6065
// [OK] @key directive is specified
6166
// [OK] @key references valid existing fields
6267
// [OK] @key on @extended type references @external fields
6368
// [ERROR] @key references fields resulting in list
6469
// [ERROR] @key references fields resulting in union
6570
// [ERROR] @key references fields resulting in interface
66-
errors.addAll(validateDirective(federatedType, "key", directives, fieldMap, extendedType))
71+
errors.addAll(validateDirective(federatedType, KEY_DIRECTIVE_NAME, directives, fieldMap, extendedType))
6772

6873
for (field in fields) {
69-
if (field.getDirective("requires") != null) {
74+
if (field.getDirective(REQUIRES_DIRECTIVE_NAME) != null) {
7075
errors.addAll(validateRequiresDirective(federatedType, field, fieldMap, extendedType))
7176
}
7277

73-
if (field.getDirective("provides") != null) {
78+
if (field.getDirective(PROVIDES_DIRECTIVE_NAME) != null) {
7479
errors.addAll(validateProvidesDirective(federatedType, field))
7580
}
7681
}
7782

7883
// [ERROR] federated base type references @external fields
7984
if (!extendedType) {
80-
val externalFields = fields.filter { it.getDirective("external") != null }.map { it.name }
85+
val externalFields = fields.filter { it.getDirective(EXTERNAL_DIRECTIVE_NAME) != null }.map { it.name }
8186
if (externalFields.isNotEmpty()) {
8287
errors.add("base $federatedType type has fields marked with @external directive, fields=$externalFields")
8388
}

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/directives/ExtendsDirective.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package com.expediagroup.graphql.federation.directives
1919
import com.expediagroup.graphql.annotations.GraphQLDirective
2020
import graphql.introspection.Introspection
2121

22-
private const val NAME = "extends"
22+
internal const val EXTENDS_DIRECTIVE_NAME = "extends"
2323
private const val DESCRIPTION = "Marks target object as extending part of the federated schema"
2424

2525
/**
@@ -53,14 +53,14 @@ private const val DESCRIPTION = "Marks target object as extending part of the fe
5353
* @see KeyDirective
5454
*/
5555
@GraphQLDirective(
56-
name = NAME,
56+
name = EXTENDS_DIRECTIVE_NAME,
5757
description = DESCRIPTION,
5858
locations = [Introspection.DirectiveLocation.OBJECT, Introspection.DirectiveLocation.INTERFACE]
5959
)
6060
annotation class ExtendsDirective
6161

62-
val extendsDirectiveType: graphql.schema.GraphQLDirective = graphql.schema.GraphQLDirective.newDirective()
63-
.name(NAME)
62+
internal val extendsDirectiveType: graphql.schema.GraphQLDirective = graphql.schema.GraphQLDirective.newDirective()
63+
.name(EXTENDS_DIRECTIVE_NAME)
6464
.description(DESCRIPTION)
6565
.validLocations(Introspection.DirectiveLocation.OBJECT, Introspection.DirectiveLocation.INTERFACE)
6666
.build()

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/directives/ExternalDirective.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ import graphql.introspection.Introspection
5252
* @see RequiresDirective
5353
*/
5454
@GraphQLDirective(
55-
name = "external",
55+
name = EXTERNAL_DIRECTIVE_NAME,
5656
description = "Marks target field as external meaning it will be resolved by federated schema",
5757
locations = [Introspection.DirectiveLocation.FIELD_DEFINITION]
5858
)
5959
annotation class ExternalDirective
60+
61+
internal const val EXTERNAL_DIRECTIVE_NAME = "external"

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/directives/KeyDirective.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ import graphql.introspection.Introspection
5555
* @see ExternalDirective
5656
*/
5757
@GraphQLDirective(
58-
name = "key",
58+
name = KEY_DIRECTIVE_NAME,
5959
description = "Space separated list of primary keys needed to access federated object",
6060
locations = [Introspection.DirectiveLocation.OBJECT, Introspection.DirectiveLocation.INTERFACE]
6161
)
6262
annotation class KeyDirective(val fields: FieldSet)
63+
64+
internal const val KEY_DIRECTIVE_NAME = "key"

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/directives/ProvidesDirective.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ import graphql.introspection.Introspection
6868
* @see ExtendsDirective
6969
*/
7070
@GraphQLDirective(
71-
name = "provides",
71+
name = PROVIDES_DIRECTIVE_NAME,
7272
description = "Specifies the base type field set that will be selectable by the gateway",
7373
locations = [Introspection.DirectiveLocation.FIELD_DEFINITION]
7474
)
7575
annotation class ProvidesDirective(val fields: FieldSet)
76+
77+
internal const val PROVIDES_DIRECTIVE_NAME = "provides"

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/directives/RequiresDirective.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,10 @@ import graphql.introspection.Introspection
7373
* @see kotlin.properties.Delegates.notNull
7474
*/
7575
@GraphQLDirective(
76-
name = "requires",
76+
name = REQUIRES_DIRECTIVE_NAME,
7777
description = "Specifies required input field set from the base type for a resolver",
7878
locations = [Introspection.DirectiveLocation.FIELD_DEFINITION]
7979
)
8080
annotation class RequiresDirective(val fields: FieldSet)
81+
82+
internal const val REQUIRES_DIRECTIVE_NAME = "requires"

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/extensions/GraphQLDirectiveContainerExtensions.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
package com.expediagroup.graphql.federation.extensions
1818

19+
import com.expediagroup.graphql.federation.directives.EXTENDS_DIRECTIVE_NAME
20+
import com.expediagroup.graphql.federation.directives.KEY_DIRECTIVE_NAME
1921
import graphql.schema.GraphQLDirectiveContainer
2022

21-
internal fun GraphQLDirectiveContainer.isFederatedType() = this.getDirective("key") != null || isExtendedType()
23+
internal fun GraphQLDirectiveContainer.isFederatedType() = this.getDirective(KEY_DIRECTIVE_NAME) != null || isExtendedType()
2224

23-
internal fun GraphQLDirectiveContainer.isExtendedType() = this.getDirective("extends") != null
25+
internal fun GraphQLDirectiveContainer.isExtendedType() = this.getDirective(EXTENDS_DIRECTIVE_NAME) != null

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/validation/validateKeySetField.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.expediagroup.graphql.federation.validation
1818

19+
import com.expediagroup.graphql.federation.directives.EXTERNAL_DIRECTIVE_NAME
1920
import graphql.schema.GraphQLFieldDefinition
2021
import graphql.schema.GraphQLInterfaceType
2122
import graphql.schema.GraphQLList
@@ -24,7 +25,7 @@ import graphql.schema.GraphQLUnionType
2425

2526
internal fun validateKeySetField(targetField: GraphQLFieldDefinition?, extendedType: Boolean, errors: MutableList<String>, validatedDirective: String) {
2627
if (null != targetField) {
27-
val externalField = targetField.getDirective("external") != null
28+
val externalField = targetField.getDirective(EXTERNAL_DIRECTIVE_NAME) != null
2829
if (extendedType && !externalField) {
2930
errors.add("$validatedDirective specifies invalid field set - extended type incorrectly references local field=${targetField.name}")
3031
} else if (!extendedType && externalField) {

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/validation/validateProvidesDirective.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.expediagroup.graphql.federation.validation
1818

19+
import com.expediagroup.graphql.federation.directives.PROVIDES_DIRECTIVE_NAME
1920
import com.expediagroup.graphql.federation.extensions.isExtendedType
2021
import graphql.schema.GraphQLFieldDefinition
2122
import graphql.schema.GraphQLObjectType
@@ -38,7 +39,7 @@ internal fun validateProvidesDirective(federatedType: String, field: GraphQLFiel
3839
// @provides is applicable on both base and federated types and always references @external fields
3940
validateDirective(
4041
"$federatedType.${field.name}",
41-
"provides",
42+
PROVIDES_DIRECTIVE_NAME,
4243
field.directivesByName,
4344
returnTypeFields,
4445
true)

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/validation/validateRequiresDirective.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.expediagroup.graphql.federation.validation
1818

19+
import com.expediagroup.graphql.federation.directives.REQUIRES_DIRECTIVE_NAME
1920
import graphql.schema.GraphQLFieldDefinition
2021

2122
// [OK] @requires references valid fields marked @external
@@ -24,7 +25,7 @@ import graphql.schema.GraphQLFieldDefinition
2425
internal fun validateRequiresDirective(validatedType: String, validatedField: GraphQLFieldDefinition, fieldMap: Map<String, GraphQLFieldDefinition>, extendedType: Boolean): List<String> {
2526
val errors = mutableListOf<String>()
2627
if (extendedType) {
27-
errors.addAll(validateDirective("$validatedType.${validatedField.name}", "requires", validatedField.directivesByName, fieldMap, extendedType))
28+
errors.addAll(validateDirective("$validatedType.${validatedField.name}", REQUIRES_DIRECTIVE_NAME, validatedField.directivesByName, fieldMap, extendedType))
2829
} else {
2930
errors.add("base $validatedType type has fields marked with @requires directive, validatedField=${validatedField.name}")
3031
}

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/FederatedSchemaGeneratorTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.expediagroup.graphql.TopLevelObject
2020
import com.expediagroup.graphql.extensions.print
2121
import com.expediagroup.graphql.federation.data.queries.simple.NestedQuery
2222
import com.expediagroup.graphql.federation.data.queries.simple.SimpleQuery
23+
import com.expediagroup.graphql.federation.directives.KEY_DIRECTIVE_NAME
2324
import com.expediagroup.graphql.federation.execution.FederatedTypeRegistry
2425
import graphql.schema.GraphQLUnionType
2526
import org.junit.jupiter.api.Assertions.assertEquals
@@ -112,7 +113,7 @@ class FederatedSchemaGeneratorTest {
112113
assertEquals(FEDERATED_SDL, schema.print().trim())
113114
val productType = schema.getObjectType("Book")
114115
assertNotNull(productType)
115-
assertNotNull(productType.getDirective("key"))
116+
assertNotNull(productType.getDirective(KEY_DIRECTIVE_NAME))
116117

117118
val entityUnion = schema.getType("_Entity") as? GraphQLUnionType
118119
assertNotNull(entityUnion)

0 commit comments

Comments
 (0)