diff --git a/src/main/java/com/intuit/graphql/orchestrator/authorization/ValidateMultipleDirectivesCoexist.java b/src/main/java/com/intuit/graphql/orchestrator/authorization/ValidateMultipleDirectivesCoexist.java new file mode 100644 index 00000000..4b0319a1 --- /dev/null +++ b/src/main/java/com/intuit/graphql/orchestrator/authorization/ValidateMultipleDirectivesCoexist.java @@ -0,0 +1,35 @@ +package com.intuit.graphql.orchestrator.authorization; + +import com.intuit.graphql.graphQL.Directive; +import com.intuit.graphql.orchestrator.stitching.InvalidDirectivePairingException; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class ValidateMultipleDirectivesCoexist { + + public ValidateMultipleDirectivesCoexist() { + } + + public void validate(List directives) { + List directiveNames = directives.stream() + .map(d -> d.getDefinition().getName()) + .collect(Collectors.toList()); + + if (CollectionUtils.containsAll(directiveNames, Arrays.asList("resolver", "external"))) { + throw new InvalidDirectivePairingException(Arrays.asList("resolver", "external")); + } + + if (CollectionUtils.containsAll(directiveNames, Arrays.asList("resolver", "provides"))) { + throw new InvalidDirectivePairingException(Arrays.asList("resolver", "external")); + } + + if (CollectionUtils.containsAll(directiveNames, Arrays.asList("resolver", "requires"))) { + throw new InvalidDirectivePairingException(Arrays.asList("resolver", "external")); + } + + } + +} diff --git a/src/main/java/com/intuit/graphql/orchestrator/stitching/InvalidDirectivePairingException.java b/src/main/java/com/intuit/graphql/orchestrator/stitching/InvalidDirectivePairingException.java new file mode 100644 index 00000000..ed9996a0 --- /dev/null +++ b/src/main/java/com/intuit/graphql/orchestrator/stitching/InvalidDirectivePairingException.java @@ -0,0 +1,14 @@ +package com.intuit.graphql.orchestrator.stitching; + + +import java.util.List; + +public class InvalidDirectivePairingException extends StitchingException { + + private static final String ERR_MSG = "Field %s in container type %s with resolver directive not allowed " + + "to have argument definitions."; + + public InvalidDirectivePairingException(List directiveNames) { + super(String.format(ERR_MSG, directiveNames.get(0), directiveNames.get(1))); + } +} diff --git a/src/test/groovy/com/intuit/graphql/orchestrator/authorization/ValidateMultipleDirectiveCoexistSpec.groovy b/src/test/groovy/com/intuit/graphql/orchestrator/authorization/ValidateMultipleDirectiveCoexistSpec.groovy new file mode 100644 index 00000000..5d78158e --- /dev/null +++ b/src/test/groovy/com/intuit/graphql/orchestrator/authorization/ValidateMultipleDirectiveCoexistSpec.groovy @@ -0,0 +1,99 @@ +package com.intuit.graphql.orchestrator.authorization + +import com.intuit.graphql.orchestrator.stitching.InvalidDirectivePairingException +import spock.lang.Specification; +import com.intuit.graphql.graphQL.Directive + +import com.intuit.graphql.graphQL.DirectiveDefinition +import static com.intuit.graphql.orchestrator.XtextObjectCreationUtil.buildDirective +import static com.intuit.graphql.orchestrator.XtextObjectCreationUtil.buildDirectiveDefinition; + +class ValidateMultipleDirectiveCoexistSpec extends Specification { + private Directive resolverDirective + + private Directive providesDirective + + private Directive externalDirective + + private Directive requiresDirective + + private Directive skipDirective + + private Directive includesDirective + + + + def setup() { + DirectiveDefinition resolverDirectiveDefinition = buildDirectiveDefinition("resolver") + DirectiveDefinition externalDirectiveDefinition = buildDirectiveDefinition("external") + DirectiveDefinition requiresDirectiveDefinition = buildDirectiveDefinition("requires") + DirectiveDefinition providesDirectiveDefinition = buildDirectiveDefinition("provides") + DirectiveDefinition skipDirectiveDefinition = buildDirectiveDefinition("skip") + DirectiveDefinition includesDirectiveDefinition = buildDirectiveDefinition("include") + resolverDirective = buildDirective(resolverDirectiveDefinition, Collections.emptyList()) + providesDirective = buildDirective(providesDirectiveDefinition, Collections.emptyList()) + externalDirective = buildDirective(externalDirectiveDefinition, Collections.emptyList()) + requiresDirective = buildDirective(requiresDirectiveDefinition, Collections.emptyList()) + skipDirective = buildDirective(skipDirectiveDefinition, Collections.emptyList()) + includesDirective = buildDirective(includesDirectiveDefinition, Collections.emptyList()) + } + + def "should throw exception for invalid directive pairing: resolver and external"() { + given: + def directives = [ + resolverDirective, + externalDirective + ] + + when: + new ValidateMultipleDirectivesCoexist().validate(directives) + + then: + thrown InvalidDirectivePairingException.class + } + + def "should throw exception for invalid directive pairing: resolver and provides"() { + given: + def directives = [ + resolverDirective, + providesDirective + ] + + when: + new ValidateMultipleDirectivesCoexist().validate(directives) + + then: + thrown InvalidDirectivePairingException.class + } + + def "should throw exception for invalid directive pairing: resolver and requires"() { + given: + def directives = [ + resolverDirective, + requiresDirective + ] + + when: + new ValidateMultipleDirectivesCoexist().validate(directives) + + then: + thrown InvalidDirectivePairingException.class + } + + def "should not throw exception for valid directives"() { + given: + def directives = [ + requiresDirective, + skipDirective, + includesDirective + ] + + when: + new ValidateMultipleDirectivesCoexist().validate(directives) + + then: + noExceptionThrown() + } +} + +