- 
                Notifications
    
You must be signed in to change notification settings  - Fork 324
 
          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.