Skip to content

Commit

Permalink
more integration tests (#90)
Browse files Browse the repository at this point in the history
I'm working on expanding test coverage to cover some cases that I think could use more testing

Ticket: [MDB-170](https://hasurahq.atlassian.net/browse/MDB-170)
  • Loading branch information
hallettj committed Aug 2, 2024
1 parent 9662c96 commit bc31238
Show file tree
Hide file tree
Showing 25 changed files with 802 additions and 36 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions arion-compose/integration-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@

{ pkgs, config, ... }:
let
connector-port = "7130";
connector-chinook-port = "7131";
engine-port = "7100";

services = import ./integration-test-services.nix {
inherit pkgs engine-port;
inherit pkgs connector-port connector-chinook-port engine-port;
map-host-ports = false;
};

connector-port = "7130";
engine-port = "7100";
in
{
project.name = "mongodb-connector-integration-tests";
Expand All @@ -24,6 +25,7 @@ in
test = import ./services/integration-tests.nix {
inherit pkgs;
connector-url = "http://connector:${connector-port}/";
connector-chinook-url = "http://connector-chinook:${connector-chinook-port}/";
engine-graphql-url = "http://engine:${engine-port}/graphql";
service.depends_on = {
connector.condition = "service_healthy";
Expand Down
2 changes: 2 additions & 0 deletions arion-compose/services/integration-tests.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{ pkgs
, connector-url
, connector-chinook-url
, engine-graphql-url
, service ? { } # additional options to customize this service configuration
}:
Expand All @@ -14,6 +15,7 @@ let
];
environment = {
CONNECTOR_URL = connector-url;
CONNECTOR_CHINOOK_URL = connector-chinook-url;
ENGINE_GRAPHQL_URL = engine-graphql-url;
INSTA_WORKSPACE_ROOT = repo-source-mount-point;
MONGODB_IMAGE = builtins.getEnv "MONGODB_IMAGE";
Expand Down
44 changes: 26 additions & 18 deletions crates/integration-tests/src/connector.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
use ndc_models::{ErrorResponse, QueryRequest, QueryResponse};
use ndc_test_helpers::QueryRequestBuilder;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use url::Url;

use crate::get_connector_url;
use crate::{get_connector_chinook_url, get_connector_url};

#[derive(Clone, Debug, Serialize)]
#[serde(transparent)]
pub struct ConnectorQueryRequest {
#[serde(skip)]
connector: Connector,
query_request: QueryRequest,
}

#[derive(Clone, Copy, Debug)]
pub enum Connector {
Chinook,
SampleMflix,
}

impl Connector {
fn url(self) -> anyhow::Result<Url> {
match self {
Connector::Chinook => get_connector_chinook_url(),
Connector::SampleMflix => get_connector_url(),
}
}
}

impl ConnectorQueryRequest {
pub async fn run(&self) -> anyhow::Result<ConnectorQueryResponse> {
let connector_url = get_connector_url()?;
let connector_url = self.connector.url()?;
let client = Client::new();
let response = client
.post(connector_url.join("query")?)
Expand All @@ -26,23 +43,14 @@ impl ConnectorQueryRequest {
}
}

impl From<QueryRequest> for ConnectorQueryRequest {
fn from(query_request: QueryRequest) -> Self {
ConnectorQueryRequest { query_request }
}
}

impl From<QueryRequestBuilder> for ConnectorQueryRequest {
fn from(builder: QueryRequestBuilder) -> Self {
let request: QueryRequest = builder.into();
request.into()
}
}

pub async fn run_connector_query(
request: impl Into<ConnectorQueryRequest>,
connector: Connector,
request: impl Into<QueryRequest>,
) -> anyhow::Result<ConnectorQueryResponse> {
let request: ConnectorQueryRequest = request.into();
let request = ConnectorQueryRequest {
connector,
query_request: request.into(),
};
request.run().await
}

Expand Down
7 changes: 7 additions & 0 deletions crates/integration-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub use self::connector::{run_connector_query, ConnectorQueryRequest};
pub use self::graphql::{graphql_query, GraphQLRequest, GraphQLResponse};

const CONNECTOR_URL: &str = "CONNECTOR_URL";
const CONNECTOR_CHINOOK_URL: &str = "CONNECTOR_CHINOOK_URL";
const ENGINE_GRAPHQL_URL: &str = "ENGINE_GRAPHQL_URL";

fn get_connector_url() -> anyhow::Result<Url> {
Expand All @@ -26,6 +27,12 @@ fn get_connector_url() -> anyhow::Result<Url> {
Ok(url)
}

fn get_connector_chinook_url() -> anyhow::Result<Url> {
let input = env::var(CONNECTOR_CHINOOK_URL).map_err(|_| anyhow!("please set {CONNECTOR_CHINOOK_URL} to the the base URL of a running MongoDB connector instance"))?;
let url = Url::parse(&input)?;
Ok(url)
}

fn get_graphql_url() -> anyhow::Result<String> {
env::var(ENGINE_GRAPHQL_URL).map_err(|_| anyhow!("please set {ENGINE_GRAPHQL_URL} to the GraphQL endpoint of a running GraphQL Engine server"))
}
48 changes: 48 additions & 0 deletions crates/integration-tests/src/tests/basic.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::graphql_query;
use insta::assert_yaml_snapshot;
use serde_json::json;

#[tokio::test]
async fn runs_a_query() -> anyhow::Result<()> {
Expand All @@ -22,3 +23,50 @@ async fn runs_a_query() -> anyhow::Result<()> {
);
Ok(())
}

#[tokio::test]
async fn filters_by_date() -> anyhow::Result<()> {
assert_yaml_snapshot!(
graphql_query(
r#"
query ($dateInput: Date) {
movies(
order_by: {id: Asc},
where: {released: {_gt: $dateInput}}
) {
title
released
}
}
"#
)
.variables(json!({ "dateInput": "2016-03-01T00:00Z" }))
.run()
.await?
);
Ok(())
}

#[tokio::test]
async fn selects_array_within_array() -> anyhow::Result<()> {
assert_yaml_snapshot!(
graphql_query(
r#"
query {
artistsWithAlbumsAndTracks(limit: 1, order_by: {id: Asc}) {
name
albums {
title
tracks {
name
}
}
}
}
"#
)
.run()
.await?
);
Ok(())
}
47 changes: 47 additions & 0 deletions crates/integration-tests/src/tests/local_relationship.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,50 @@ async fn sorts_by_field_of_related_collection() -> anyhow::Result<()> {
);
Ok(())
}

#[tokio::test]
async fn looks_up_the_same_relation_twice_with_different_fields() -> anyhow::Result<()> {
assert_yaml_snapshot!(
graphql_query(
r#"
query {
artist(limit: 2, order_by: {id: Asc}) {
albums1: albums(order_by: {title: Asc}) {
title
}
albums2: albums(order_by: {title: Asc}) {
tracks(order_by: {name: Asc}) {
name
}
}
}
}
"#
)
.run()
.await?
);
Ok(())
}

#[tokio::test]
async fn queries_through_relationship_with_null_value() -> anyhow::Result<()> {
assert_yaml_snapshot!(
graphql_query(
r#"
query {
comments(where: {id: {_eq: "5a9427648b0beebeb69579cc"}}) { # this comment does not have a matching movie
movie {
comments {
email
}
}
}
}
"#
)
.run()
.await?
);
Ok(())
}
35 changes: 34 additions & 1 deletion crates/integration-tests/src/tests/native_query.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::graphql_query;
use crate::{connector::Connector, graphql_query, run_connector_query};
use insta::assert_yaml_snapshot;
use ndc_test_helpers::{asc, binop, field, query, query_request, target, variable};

#[tokio::test]
async fn runs_native_query_with_function_representation() -> anyhow::Result<()> {
Expand Down Expand Up @@ -51,3 +52,35 @@ async fn runs_native_query_with_collection_representation() -> anyhow::Result<()
);
Ok(())
}

#[tokio::test]
async fn runs_native_query_with_variable_sets() -> anyhow::Result<()> {
// Skip this test in MongoDB 5 because the example fails there. We're getting an error:
//
// > Kind: Command failed: Error code 5491300 (Location5491300): $documents' is not allowed in user requests, labels: {}
//
// This means that remote joins are not working in MongoDB 5
if let Ok(image) = std::env::var("MONGODB_IMAGE") {
if image == "mongo:5" {
return Ok(());
}
}

assert_yaml_snapshot!(
run_connector_query(
Connector::SampleMflix,
query_request()
.variables([[("count", 1)], [("count", 2)], [("count", 3)]])
.collection("title_word_frequency")
.query(
query()
.predicate(binop("_eq", target!("count"), variable!(count)))
.order_by([asc!("_id")])
.limit(20)
.fields([field!("_id"), field!("count")]),
)
)
.await?
);
Ok(())
}
45 changes: 43 additions & 2 deletions crates/integration-tests/src/tests/remote_relationship.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{graphql_query, run_connector_query};
use crate::{connector::Connector, graphql_query, run_connector_query};
use insta::assert_yaml_snapshot;
use ndc_test_helpers::{binop, field, query, query_request, target, variable};
use ndc_test_helpers::{and, asc, binop, field, query, query_request, target, variable};
use serde_json::json;

#[tokio::test]
Expand Down Expand Up @@ -53,6 +53,7 @@ async fn handles_request_with_single_variable_set() -> anyhow::Result<()> {

assert_yaml_snapshot!(
run_connector_query(
Connector::SampleMflix,
query_request()
.collection("movies")
.variables([[("id", json!("573a1390f29313caabcd50e5"))]])
Expand All @@ -66,3 +67,43 @@ async fn handles_request_with_single_variable_set() -> anyhow::Result<()> {
);
Ok(())
}

#[tokio::test]
async fn variable_used_in_multiple_type_contexts() -> anyhow::Result<()> {
// Skip this test in MongoDB 5 because the example fails there. We're getting an error:
//
// > Kind: Command failed: Error code 5491300 (Location5491300): $documents' is not allowed in user requests, labels: {}
//
// This means that remote joins are not working in MongoDB 5
if let Ok(image) = std::env::var("MONGODB_IMAGE") {
if image == "mongo:5" {
return Ok(());
}
}

assert_yaml_snapshot!(
run_connector_query(
Connector::SampleMflix,
query_request()
.variables([[("dateInput", "2015-09-15T00:00Z")]])
.collection("movies")
.query(
query()
.predicate(and([
binop("_gt", target!("released"), variable!(dateInput)), // type is date
binop("_gt", target!("lastupdated"), variable!(dateInput)), // type is string
]))
.order_by([asc!("_id")])
.limit(20)
.fields([
field!("_id"),
field!("title"),
field!("released"),
field!("lastupdated")
]),
)
)
.await?
);
Ok(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
source: crates/integration-tests/src/tests/basic.rs
expression: "graphql_query(r#\"\n query ($dateInput: Date) {\n movies(\n order_by: {id: Asc},\n where: {released: {_gt: $dateInput}}\n ) {\n title\n released\n }\n }\n \"#).variables(json!({\n \"dateInput\": \"2016-03-01T00:00Z\"\n })).run().await?"
---
data:
movies:
- title: Knight of Cups
released: "2016-03-04T00:00:00.000000000Z"
- title: The Treasure
released: "2016-03-23T00:00:00.000000000Z"
errors: ~
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
source: crates/integration-tests/src/tests/basic.rs
expression: "graphql_query(r#\"\n query {\n artistsWithAlbumsAndTracks(limit: 1, order_by: {id: Asc}) {\n name\n albums {\n title\n tracks {\n name\n }\n }\n }\n }\n \"#).run().await?"
---
data:
artistsWithAlbumsAndTracks:
- name: AC/DC
albums:
- title: For Those About To Rock We Salute You
tracks:
- name: Breaking The Rules
- name: C.O.D.
- name: Evil Walks
- name: For Those About To Rock (We Salute You)
- name: Inject The Venom
- name: "Let's Get It Up"
- name: Night Of The Long Knives
- name: Put The Finger On You
- name: Snowballed
- name: Spellbound
- title: Let There Be Rock
tracks:
- name: Bad Boy Boogie
- name: Dog Eat Dog
- name: Go Down
- name: "Hell Ain't A Bad Place To Be"
- name: Let There Be Rock
- name: Overdose
- name: Problem Child
- name: Whole Lotta Rosie
errors: ~
Loading

0 comments on commit bc31238

Please sign in to comment.