Skip to content

Commit

Permalink
verify that deferred fragment acts as a boundary for nullability rules (
Browse files Browse the repository at this point in the history
#2183)

fixes: #2169

Add a new test to confirm this is the case.
  • Loading branch information
garypen authored and Geoffroy Couprie committed Dec 2, 2022
1 parent a4d0d0e commit 1f43ad3
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 2 deletions.
10 changes: 8 additions & 2 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ By [@USERNAME](https://github.com/USERNAME) in https://github.com/apollographql/
# [x.x.x] (unreleased) - 2022-mm-dd
## ❗ BREAKING ❗

### Router debug Docker images now run under the control of heaptrack ([Issue #2135](https://github.com/apollographql/router/pull/2142))
### Router debug Docker images now run under the control of heaptrack ([Issue #2135](https://github.com/apollographql/router/issues/2135))

From the next release, our debug Docker image will invoke the router under the control of heaptrack. We are making this change to make it simple for users to investigate potential memory issues with the router.

Expand Down Expand Up @@ -115,7 +115,7 @@ telemetry:
headers: true
```

### Provide multi-arch (amd64/arm64) Docker images for the Router ([Issue #1932](https://github.com/apollographql/router/pull/2138))
### Provide multi-arch (amd64/arm64) Docker images for the Router ([Issue #1932](https://github.com/apollographql/router/issues/1932))

From the next release, our Docker images will be multi-arch.

Expand Down Expand Up @@ -267,6 +267,12 @@ By [@Geal](https://github.com/Geal) in https://github.com/apollographql/router/p

## 🛠 Maintenance

### Verify that deferred fragment acts as a boundary for nullability rules ([Issue #2169](https://github.com/apollographql/router/issues/2169))

Add a test to ensure that deferred fragments act as a boundary for nullability rules.

By [@garypen](https://github.com/garypen) in https://github.com/apollographql/router/pull/2183

### Refactor APQ ([PR #2129](https://github.com/apollographql/router/pull/2129))

Remove duplicated code.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
source: apollo-router/src/services/supergraph_service.rs
expression: stream.next_response().await.unwrap()
---
{
"hasNext": false,
"incremental": [
{
"data": null,
"path": [
"currentUser",
"activeOrganization",
"suborga",
0
],
"extensions": {
"valueCompletion": [
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
0
]
},
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
1
]
},
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
2
]
}
]
}
},
{
"data": null,
"path": [
"currentUser",
"activeOrganization",
"suborga",
1
],
"extensions": {
"valueCompletion": [
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
0
]
},
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
1
]
},
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
2
]
}
]
}
},
{
"data": null,
"path": [
"currentUser",
"activeOrganization",
"suborga",
2
],
"extensions": {
"valueCompletion": [
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
0
]
},
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
1
]
},
{
"message": "Cannot return null for non-nullable field Organization.nonNullId",
"path": [
"currentUser",
"activeOrganization",
"suborga",
2
]
}
]
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
source: apollo-router/src/services/supergraph_service.rs
expression: stream.next_response().await.unwrap()
---
{
"data": {
"currentUser": {
"activeOrganization": {
"id": "0",
"suborga": [
{
"id": "1"
},
{
"id": "2"
},
{
"id": "3"
}
]
}
}
},
"hasNext": true
}
82 changes: 82 additions & 0 deletions apollo-router/src/services/supergraph_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,88 @@ mod tests {
insta::assert_json_snapshot!(stream.next_response().await.unwrap());
}

#[tokio::test]
async fn deferred_fragment_bounds_nullability() {
let subgraphs = MockedSubgraphs([
("user", MockSubgraph::builder().with_json(
serde_json::json!{{"query":"{currentUser{activeOrganization{__typename id}}}"}},
serde_json::json!{{"data": {"currentUser": { "activeOrganization": { "__typename": "Organization", "id": "0" } }}}}
).build()),
("orga", MockSubgraph::builder().with_json(
serde_json::json!{{
"query":"query($representations:[_Any!]!){_entities(representations:$representations){...on Organization{suborga{__typename id}}}}",
"variables": {
"representations":[{"__typename": "Organization", "id":"0"}]
}
}},
serde_json::json!{{
"data": {
"_entities": [{ "suborga": [
{ "__typename": "Organization", "id": "1"},
{ "__typename": "Organization", "id": "2"},
{ "__typename": "Organization", "id": "3"},
] }]
},
}}
)
.with_json(
serde_json::json!{{
"query":"query($representations:[_Any!]!){_entities(representations:$representations){...on Organization{name}}}",
"variables": {
"representations":[
{"__typename": "Organization", "id":"1"},
{"__typename": "Organization", "id":"2"},
{"__typename": "Organization", "id":"3"}

]
}
}},
serde_json::json!{{
"data": {
"_entities": [
{ "__typename": "Organization", "id": "1"},
{ "__typename": "Organization", "id": "2", "name": "A"},
{ "__typename": "Organization", "id": "3"},
]
},
"errors": [
{
"message": "error orga 1",
"path": ["_entities", 0],
},
{
"message": "error orga 3",
"path": ["_entities", 2],
}
]
}}
).build())
].into_iter().collect());

let service = TestHarness::builder()
.configuration_json(serde_json::json!({"include_subgraph_errors": { "all": true } }))
.unwrap()
.schema(SCHEMA)
.extra_plugin(subgraphs)
.build()
.await
.unwrap();

let request = supergraph::Request::fake_builder()
.header("Accept", "multipart/mixed; deferSpec=20220824")
.query(
"query { currentUser { activeOrganization { id suborga { id ...@defer { nonNullId } } } } }",
)
.build()
.unwrap();

let mut stream = service.oneshot(request).await.unwrap();

insta::assert_json_snapshot!(stream.next_response().await.unwrap());

insta::assert_json_snapshot!(stream.next_response().await.unwrap());
}

#[tokio::test]
async fn errors_on_incremental_responses() {
let subgraphs = MockedSubgraphs([
Expand Down

0 comments on commit 1f43ad3

Please sign in to comment.