-
Notifications
You must be signed in to change notification settings - Fork 326
Port compose.directiveArgumentMergeStrategies.test.ts to router
#8311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
6c559ad
Port test for directiveArgumentMergeStrategies
conwuegb d85bd32
Omit json to simplify test case struct
conwuegb 230b350
Make assert_composition_success() more in line with TS version
conwuegb 98eb302
Run formatter
conwuegb 60ec5b3
Minor comment updates
conwuegb ab98e85
Merge branch 'dev' into conwuegb/fed-686
conwuegb 05d5a99
Move assert_hints_equal() up to mod level
conwuegb a1dc015
Merge branch 'dev' into conwuegb/fed-686
conwuegb 3f6bd3b
Merge branch 'dev' of https://github.com/apollographql/router into co…
conwuegb e4fd7ce
Reset visibility of argument_composition_strategies mod
conwuegb da5c360
fix(composition): Give correct argument name to merger when merging d…
tninesling 21b883f
Update tests to use public-facing directives.
conwuegb d5da1fd
Remove test for mismatched composition strategy and argument type
conwuegb 7c414fa
Add test for nullable_max strategy
conwuegb 36961f6
Add test for nullable_and strategy
conwuegb cf8522d
Add test for nullable_union strategy
conwuegb 5ec1423
Merge branch 'dev' of https://github.com/apollographql/router into co…
conwuegb 25a5ec0
Fix incorrect error code in compose_validation test
conwuegb 5c168b5
Fix incorrect error code in compose_inacessible test
conwuegb 754cb69
Revert change in error code for compose_inaccessible test
conwuegb df90fe2
Merge branch 'dev' of https://github.com/apollographql/router into co…
conwuegb 85da655
Merge branch 'dev' of https://github.com/apollographql/router into co…
conwuegb e7b355e
Check error code before checking error msg
conwuegb db90254
Add useful context to composition errors
conwuegb 081019d
Fix lint errors
conwuegb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
358 changes: 358 additions & 0 deletions
358
apollo-federation/tests/composition/directive_argument_merge_strategies.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,358 @@ | ||
| use std::iter::zip; | ||
|
|
||
| use apollo_compiler::ast; | ||
| use apollo_compiler::schema; | ||
| use apollo_federation::schema::argument_composition_strategies::ArgumentCompositionStrategy; | ||
| use apollo_federation::supergraph::CompositionHint; | ||
|
|
||
| use super::ServiceDefinition; | ||
| use super::assert_composition_success; | ||
| use super::compose_as_fed2_subgraphs; | ||
| use super::errors; | ||
|
|
||
| // Helper function to create directive strings from applied directives using schema::DirectiveList | ||
| fn directive_strings_schema(directives: &schema::DirectiveList, target: &str) -> Vec<String> { | ||
conwuegb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| directives | ||
| .iter() | ||
| .map(|dir| dir.to_string()) | ||
| .filter(|s| s.contains(target)) | ||
| .collect() | ||
| } | ||
|
|
||
| // Helper function to create directive strings from applied directives using ast::DirectiveList | ||
| fn directive_strings_ast(directives: &ast::DirectiveList, target: &str) -> Vec<String> { | ||
| directives | ||
| .iter() | ||
| .map(|dir| dir.to_string()) | ||
| .filter(|s| s.contains(target)) | ||
| .collect() | ||
| } | ||
|
|
||
| fn assert_hints_equal(actual_hints: &Vec<CompositionHint>, expected_hints: &Vec<CompositionHint>) { | ||
conwuegb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if actual_hints.len() != expected_hints.len() { | ||
| panic!("Mismatched number of hints") | ||
conwuegb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| let zipped = zip(actual_hints, expected_hints); | ||
| zipped | ||
conwuegb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .for_each(|(ch1, ch2)| assert!(ch1.code() == ch2.code() && ch1.message() == ch2.message())); | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use core::str; | ||
| use std::collections::HashMap; | ||
| use std::sync::LazyLock; | ||
|
|
||
| use super::*; | ||
|
|
||
| // Test cases for different argument composition strategies | ||
| struct CompositionStrategyTestCase<'a> { | ||
conwuegb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| name: &'a str, | ||
| composition_strategy: ArgumentCompositionStrategy, | ||
| arg_values_s1: HashMap<&'a str, &'a str>, | ||
| arg_values_s2: HashMap<&'a str, &'a str>, | ||
| result_values: HashMap<&'a str, &'a str>, | ||
| } | ||
|
|
||
| static TEST_CASES: LazyLock<HashMap<&str, CompositionStrategyTestCase>> = LazyLock::new(|| { | ||
conwuegb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| HashMap::from([ | ||
| ( | ||
| "max", | ||
| CompositionStrategyTestCase { | ||
| name: "max", | ||
| composition_strategy: ArgumentCompositionStrategy::Max, | ||
| arg_values_s1: HashMap::from([("t", "3"), ("k", "1")]), | ||
| arg_values_s2: HashMap::from([("t", "2"), ("k", "5"), ("b", "4")]), | ||
| result_values: HashMap::from([("t", "3"), ("k", "5"), ("b", "4")]), | ||
| }, | ||
| ), | ||
| ( | ||
| "min", | ||
| CompositionStrategyTestCase { | ||
| name: "min", | ||
| composition_strategy: ArgumentCompositionStrategy::Min, | ||
| arg_values_s1: HashMap::from([("t", "3"), ("k", "1")]), | ||
| arg_values_s2: HashMap::from([("t", "2"), ("k", "5"), ("b", "4")]), | ||
| result_values: HashMap::from([("t", "2"), ("k", "1"), ("b", "4")]), | ||
| }, | ||
| ), | ||
| ( | ||
| "intersection", | ||
| CompositionStrategyTestCase { | ||
| name: "intersection", | ||
| composition_strategy: ArgumentCompositionStrategy::Intersection, | ||
| arg_values_s1: HashMap::from([("t", r#"["foo", "bar"]"#), ("k", r#"[]"#)]), | ||
| arg_values_s2: HashMap::from([ | ||
| ("t", r#"["foo"]"#), | ||
| ("k", r#"["v1", "v2"]"#), | ||
| ("b", r#"["x"]"#), | ||
| ]), | ||
| result_values: HashMap::from([ | ||
| ("t", r#"["foo"]"#), | ||
| ("k", r#"[]"#), | ||
| ("b", r#"["x"]"#), | ||
| ]), | ||
| }, | ||
| ), | ||
| ( | ||
| "union", | ||
| CompositionStrategyTestCase { | ||
| name: "union", | ||
| composition_strategy: ArgumentCompositionStrategy::Union, | ||
| arg_values_s1: HashMap::from([("t", r#"["foo", "bar"]"#), ("k", r#"[]"#)]), | ||
| arg_values_s2: HashMap::from([ | ||
| ("t", r#"["foo"]"#), | ||
| ("k", r#"["v1", "v2"]"#), | ||
| ("b", r#"["x"]"#), | ||
| ]), | ||
| result_values: HashMap::from([ | ||
| ("t", r#"["foo", "bar"]"#), | ||
| ("k", r#"["v1", "v2"]"#), | ||
| ("b", r#"["x"]"#), | ||
| ]), | ||
| }, | ||
| ), | ||
| ( | ||
| "nullable_and", | ||
| CompositionStrategyTestCase { | ||
| name: "nullable_and", | ||
| composition_strategy: ArgumentCompositionStrategy::NullableAnd, | ||
| arg_values_s1: HashMap::from([("t", "true"), ("k", "true")]), | ||
| arg_values_s2: HashMap::from([("t", "null"), ("k", "false"), ("b", "false")]), | ||
| result_values: HashMap::from([("t", "true"), ("k", "false"), ("b", "false")]), | ||
| }, | ||
| ), | ||
| ( | ||
| "nullable_max", | ||
| CompositionStrategyTestCase { | ||
| name: "nullable_max", | ||
| composition_strategy: ArgumentCompositionStrategy::NullableMax, | ||
| arg_values_s1: HashMap::from([("t", "3"), ("k", "1")]), | ||
| arg_values_s2: HashMap::from([("t", "2"), ("k", "null"), ("b", "null")]), | ||
| result_values: HashMap::from([("t", "3"), ("k", "1"), ("b", "null")]), | ||
| }, | ||
| ), | ||
| ( | ||
| "nullable_union", | ||
| CompositionStrategyTestCase { | ||
| name: "nullable_union", | ||
| composition_strategy: ArgumentCompositionStrategy::NullableUnion, | ||
| arg_values_s1: HashMap::from([("t", r#"["foo", "bar"]"#), ("k", r#"[]"#)]), | ||
| arg_values_s2: HashMap::from([ | ||
| ("t", r#"["foo"]"#), | ||
| ("k", r#"["v1", "v2"]"#), | ||
| ("b", r#"["x"]"#), | ||
| ]), | ||
| result_values: HashMap::from([ | ||
| ("t", r#"["foo", "bar"]"#), | ||
| ("k", r#"["v1", "v2"]"#), | ||
| ("b", r#"["x"]"#), | ||
| ]), | ||
| }, | ||
| ), | ||
| ]) | ||
| }); | ||
|
|
||
| fn test_composition_of_directive_with_non_trivial_argument_strategies( | ||
| test_case: &CompositionStrategyTestCase, | ||
| ) { | ||
| let subgraph1 = ServiceDefinition { | ||
| name: "Subgraph1", | ||
| type_defs: &format!( | ||
| r#" | ||
| extend schema @link(url: "https://specs.apollo.dev/{}/v0.1") | ||
| type Query {{ | ||
| t: T | ||
| }} | ||
| type T | ||
| @key(fields: "k") | ||
| @{}(value: {}) | ||
| {{ | ||
| k: ID @{}(value: {}) | ||
| }} | ||
| "#, | ||
| test_case.name, | ||
| test_case.name, | ||
| test_case.arg_values_s1["t"], | ||
| test_case.name, | ||
| test_case.arg_values_s1["k"] | ||
| ), | ||
| }; | ||
|
|
||
| let subgraph2 = ServiceDefinition { | ||
| name: "Subgraph2", | ||
| type_defs: &format!( | ||
| r#" | ||
| extend schema @link(url: "https://specs.apollo.dev/{}/v0.1") | ||
| type T | ||
| @key(fields: "k") | ||
| @{}(value: {}) | ||
| {{ | ||
| k: ID @{}(value: {}) | ||
| a: Int | ||
| b: String @{}(value: {}) | ||
| }} | ||
| "#, | ||
| test_case.name, | ||
| test_case.name, | ||
| test_case.arg_values_s2["t"], | ||
| test_case.name, | ||
| test_case.arg_values_s2["k"], | ||
| test_case.name, | ||
| test_case.arg_values_s2["b"] | ||
| ), | ||
| }; | ||
|
|
||
| let result = compose_as_fed2_subgraphs(&[subgraph1, subgraph2]); | ||
duckki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| let result_sg = assert_composition_success(result); | ||
|
|
||
| // Check expected hints | ||
| let expected_hints = vec![ | ||
| CompositionHint { | ||
| code: String::from("MERGED_NON_REPEATABLE_DIRECTIVE_ARGUMENTS"), | ||
| message: format!( | ||
| "Directive @{} is applied to \"T\" in multiple subgraphs with different arguments. Merging strategies used by arguments: {{ \"value\": {} }}", | ||
| test_case.name, | ||
| test_case.composition_strategy.name() | ||
| ), | ||
| locations: Vec::new(), | ||
| }, | ||
| CompositionHint { | ||
| code: String::from("MERGED_NON_REPEATABLE_DIRECTIVE_ARGUMENTS"), | ||
| message: format!( | ||
| "Directive @{} is applied to \"T.k\" in multiple subgraphs with different arguments. Merging strategies used by arguments: {{ \"value\": {} }}", | ||
| test_case.name, | ||
| test_case.composition_strategy.name() | ||
| ), | ||
| locations: Vec::new(), | ||
| }, | ||
| ]; | ||
| assert_hints_equal(result_sg.hints(), &expected_hints); | ||
|
|
||
| // Check expected directive strings | ||
| let schema = result_sg.schema().schema(); | ||
| assert_eq!( | ||
| directive_strings_schema(&schema.schema_definition.directives, test_case.name), | ||
| vec![format!( | ||
| r#"@link(url: "https://specs.apollo.dev/{}/v0.1")"#, | ||
| test_case.name | ||
| )] | ||
| ); | ||
|
|
||
| let t = schema.get_object("T").unwrap(); | ||
| assert_eq!( | ||
| directive_strings_schema(&t.directives, test_case.name), | ||
| [format!( | ||
| r#"@{}(value: {})"#, | ||
| test_case.name, test_case.result_values["t"] | ||
| )] | ||
| ); | ||
| assert_eq!( | ||
| directive_strings_ast(&t.fields.get("k").unwrap().directives, test_case.name), | ||
| [format!( | ||
| r#"@{}(value: {})"#, | ||
| test_case.name, test_case.result_values["k"] | ||
| )] | ||
| ); | ||
| assert_eq!( | ||
| directive_strings_ast(&t.fields.get("b").unwrap().directives, test_case.name), | ||
| [format!( | ||
| r#"@{}(value: {})"#, | ||
| test_case.name, test_case.result_values["b"] | ||
| )] | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| #[ignore = "Directive argument merge strategies not yet implemented"] | ||
| fn works_for_max() { | ||
| let test_case = TEST_CASES.get("max").expect("Test case not found"); | ||
| test_composition_of_directive_with_non_trivial_argument_strategies(test_case); | ||
| } | ||
|
|
||
| #[test] | ||
| #[ignore = "Directive argument merge strategies not yet implemented"] | ||
| fn works_for_min() { | ||
| let test_case = TEST_CASES.get("min").expect("Test case not found"); | ||
| test_composition_of_directive_with_non_trivial_argument_strategies(test_case); | ||
| } | ||
|
|
||
| #[test] | ||
| #[ignore = "Directive argument merge strategies not yet implemented"] | ||
| fn works_for_intersection() { | ||
| let test_case = TEST_CASES.get("intersection").expect("Test case not found"); | ||
| test_composition_of_directive_with_non_trivial_argument_strategies(test_case); | ||
| } | ||
|
|
||
| #[test] | ||
| #[ignore = "Directive argument merge strategies not yet implemented"] | ||
| fn works_for_union() { | ||
| let test_case = TEST_CASES.get("union").expect("Test case not found"); | ||
| test_composition_of_directive_with_non_trivial_argument_strategies(test_case); | ||
| } | ||
|
|
||
| #[test] | ||
| #[ignore = "Directive argument merge strategies not yet implemented"] | ||
| fn works_for_nullable_and() { | ||
| let test_case = TEST_CASES.get("nullable_and").expect("Test case not found"); | ||
| test_composition_of_directive_with_non_trivial_argument_strategies(test_case); | ||
| } | ||
|
|
||
| #[test] | ||
| #[ignore = "Directive argument merge strategies not yet implemented"] | ||
| fn works_for_nullable_max() { | ||
| let test_case = TEST_CASES.get("nullable_max").expect("Test case not found"); | ||
| test_composition_of_directive_with_non_trivial_argument_strategies(test_case); | ||
| } | ||
|
|
||
| #[test] | ||
| #[ignore = "Directive argument merge strategies not yet implemented"] | ||
| fn works_for_nullable_union() { | ||
| let test_case = TEST_CASES | ||
| .get("nullable_union") | ||
| .expect("Test case not found"); | ||
| test_composition_of_directive_with_non_trivial_argument_strategies(test_case); | ||
| } | ||
|
|
||
| #[test] | ||
| #[ignore = "Directive argument merge strategies not yet implemented"] | ||
| fn errors_when_declaring_strategy_that_does_not_match_the_argument_type() { | ||
| let subgraph1 = ServiceDefinition { | ||
| name: "Subgraph1", | ||
| type_defs: r#" | ||
| extend schema @link(url: "https://specs.apollo.dev/foo/v0.1") | ||
| type Query { | ||
| t: T | ||
| } | ||
| type T { | ||
| v: String @foo(value: "bar") | ||
| } | ||
| "#, | ||
| }; | ||
|
|
||
| let subgraph2 = ServiceDefinition { | ||
| name: "Subgraph2", | ||
| type_defs: r#" | ||
| extend schema @link(url: "https://specs.apollo.dev/foo/v0.1") | ||
| type T { | ||
| v: String @foo(value: "bar") | ||
| } | ||
| "#, | ||
| }; | ||
|
|
||
| let result = compose_as_fed2_subgraphs(&[subgraph1, subgraph2]); | ||
| let errs = errors(&result); | ||
| assert_eq!( | ||
| errs.iter().map(|(_, message)| message).collect::<Vec<_>>(), | ||
| [ | ||
| r#"Invalid composition strategy MAX for argument @foo(value:) of type String; MAX only supports type(s) Int!"# | ||
| ] | ||
| ); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.