Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 74 additions & 20 deletions DataGateway.Service.Tests/CosmosTests/MutationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ public class MutationTests : TestBase
{
private static readonly string _containerName = Guid.NewGuid().ToString();
private static readonly string _mutationStringFormat = @"
mutation
{{
addPlanet (id: ""{0}"", name: ""{1}"")
{{
mutation ($id: String, $name: String)
{
addPlanet (id: $id, name: $name)
{
id
name
}}
}}";
}
}";
private static readonly string _mutationDeleteItemStringFormat = @"
mutation
{{
deletePlanet (id: ""{0}"")
{{
mutation ($id: String)
{
deletePlanet (id: $id)
{
id
name
}}
}}";
}
}";

/// <summary>
/// Executes once for the test class.
Expand All @@ -44,22 +44,76 @@ public static void TestFixtureSetup(TestContext context)
}

[TestMethod]
public async Task TestMutationRun()
public async Task CanCreateItemWithVariables()
{
// Run mutation Add planet;
String id = Guid.NewGuid().ToString();
string mutation = String.Format(_mutationStringFormat, id, "test_name");
JsonElement response = await ExecuteGraphQLRequestAsync("addPlanet", mutation);
string id = Guid.NewGuid().ToString();
JsonElement response = await ExecuteGraphQLRequestAsync("addPlanet", _mutationStringFormat, new() { { "id", id }, { "name", "test_name" } });

// Validate results
Assert.IsFalse(response.ToString().Contains("Error"));
Assert.AreEqual(id, response.GetProperty("id").GetString());
}

[TestMethod]
public async Task CanDeleteItemWithVariables()
{
// Pop an item in to delete
string id = Guid.NewGuid().ToString();
_ = await ExecuteGraphQLRequestAsync("addPlanet", _mutationStringFormat, new() { { "id", id }, { "name", "test_name" } });

// Run mutation delete item;
JsonElement response = await ExecuteGraphQLRequestAsync("deletePlanet", _mutationDeleteItemStringFormat, new() { { "id", id } });

// Validate results
Assert.IsNull(response.GetProperty("id").GetString());
}

[TestMethod]
public async Task CanCreateItemWithoutVariables()
{
// Run mutation Add planet;
string id = Guid.NewGuid().ToString();
const string name = "test_name";
string mutation = $@"
mutation {{
addPlanet (id: ""{id}"", name: ""{name}"") {{
id
name
}}
}}";
JsonElement response = await ExecuteGraphQLRequestAsync("addPlanet", mutation, new());

// Validate results
Assert.AreEqual(id, response.GetProperty("id").GetString());
}

[TestMethod]
public async Task CanDeleteItemWithoutVariables()
{
// Pop an item in to delete
string id = Guid.NewGuid().ToString();
const string name = "test_name";
string addMutation = $@"
mutation {{
addPlanet (id: ""{id}"", name: ""{name}"") {{
id
name
}}
}}";
_ = await ExecuteGraphQLRequestAsync("addPlanet", addMutation, new());

// Run mutation delete item;
mutation = String.Format(_mutationDeleteItemStringFormat, id);
response = await ExecuteGraphQLRequestAsync("deletePlanet", mutation);
string deleteMutation = $@"
mutation {{
deletePlanet (id: ""{id}"") {{
id
name
}}
}}";
JsonElement response = await ExecuteGraphQLRequestAsync("deletePlanet", deleteMutation, new());

// Validate results
Assert.IsFalse(response.ToString().Contains("Error"));
Assert.IsNull(response.GetProperty("id").GetString());
}

/// <summary>
Expand Down
99 changes: 77 additions & 22 deletions DataGateway.Service.Tests/CosmosTests/QueryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,25 @@ public class QueryTests : TestBase
{
private static readonly string _containerName = Guid.NewGuid().ToString();

public static readonly string PlanetByIdQueryFormat = @"{{planetById (id: {0}){{ id, name}} }}";
public static readonly string PlanetByIdQueryFormat = @"
query ($id: ID) {
planetById (id: $id) {
id
name
}
}";
public static readonly string PlanetListQuery = @"{planetList{ id, name}}";
public static readonly string PlanetConnectionQueryStringFormat = @"
{{planets (first: {0}, after: {1}){{
items{{ id name }}
endCursor
hasNextPage
}}
}}";
query ($first: Int!, $after: String) {
planets (first: $first, after: $after) {
items {
id
name
}
endCursor
hasNextPage
}
}";

private static List<string> _idList;

Expand All @@ -39,42 +49,87 @@ public static void TestFixtureSetup(TestContext context)
}

[TestMethod]
public async Task TestSimpleQuery()
public async Task GetByPrimaryKeyWithVariables()
{
// Run query
string query = string.Format(PlanetByIdQueryFormat, arg0: "\"" + _idList[0] + "\"");
JsonElement response = await ExecuteGraphQLRequestAsync("planetById", query);
string id = _idList[0];
JsonElement response = await ExecuteGraphQLRequestAsync("planetById", PlanetByIdQueryFormat, new() { { "id", id } });

// Validate results
Assert.IsFalse(response.ToString().Contains("Error"));
Assert.AreEqual(id, response.GetProperty("id").GetString());
}

/// <summary>
/// This test runs a query to list all the items in a container. Then, gets all the items by
/// running a paginated query that gets n items per page. We then make sure the number of documents match
/// </summary>
[TestMethod]
public async Task TestPaginatedQuery()
public async Task GetPaginatedWithVariables()
{
// Run query
JsonElement response = await ExecuteGraphQLRequestAsync("planetList", PlanetListQuery);
int actualElements = response.GetArrayLength();
// Run paginated query
int totalElementsFromPaginatedQuery = 0;
string continuationToken = "null";
string continuationToken = null;
const int pagesize = 5;

do
{
if (continuationToken != "null")
{
// We need to append an escape quote to continuation token because of the way we are using string.format
// for generating the graphql paginated query stringformat for this test.
continuationToken = "\"" + continuationToken + "\"";
}

string paginatedQuery = string.Format(PlanetConnectionQueryStringFormat, arg0: pagesize, arg1: continuationToken);
JsonElement page = await ExecuteGraphQLRequestAsync("planets", paginatedQuery);
JsonElement page = await ExecuteGraphQLRequestAsync("planets", PlanetConnectionQueryStringFormat, new() { { "first", pagesize }, { "after", continuationToken } });
JsonElement continuation = page.GetProperty("endCursor");
continuationToken = continuation.ToString();
totalElementsFromPaginatedQuery += page.GetProperty("items").GetArrayLength();
} while (!string.IsNullOrEmpty(continuationToken));

// Validate results
Assert.AreEqual(actualElements, totalElementsFromPaginatedQuery);
}

[TestMethod]
public async Task GetByPrimaryKeyWithoutVariables()
{
// Run query
string id = _idList[0];
string query = @$"
query {{
planetById (id: ""{id}"") {{
id
name
}}
}}";
JsonElement response = await ExecuteGraphQLRequestAsync("planetById", query);

// Validate results
Assert.AreEqual(id, response.GetProperty("id").GetString());
}

[TestMethod]
public async Task GetPaginatedWithoutVariables()
{
// Run query
JsonElement response = await ExecuteGraphQLRequestAsync("planetList", PlanetListQuery);
int actualElements = response.GetArrayLength();
// Run paginated query
int totalElementsFromPaginatedQuery = 0;
string continuationToken = null;
const int pagesize = 5;

do
{
string planetConnectionQueryStringFormat = @$"
query {{
planets (first: {pagesize}, after: {(continuationToken == null ? "null" : "\"" + continuationToken + "\"")}) {{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any functional reason to define this inline? Better readability? instead of using PlanetConnectionQueryStringFormat?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find string interpolation more readable than using string.Format. After all, it's really just doing string.Format with syntactic sugar.

items {{
id
name
}}
endCursor
hasNextPage
}}
}}";

JsonElement page = await ExecuteGraphQLRequestAsync("planets", planetConnectionQueryStringFormat, new());
JsonElement continuation = page.GetProperty("endCursor");
continuationToken = continuation.ToString();
totalElementsFromPaginatedQuery += page.GetProperty("items").GetArrayLength();
Expand Down
57 changes: 49 additions & 8 deletions DataGateway.Service.Tests/CosmosTests/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,39 @@ public static void Init(TestContext context)
{
_clientProvider = new CosmosClientProvider(TestHelper.DataGatewayConfig);
_metadataStoreProvider = new MetadataStoreProviderForTest();
string jsonString = File.ReadAllText("schema.gql");
string jsonString = @"
type Query {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same any reason for defining it inline?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reduces a reliance on external files. I've been testing with different GraphQL schemas but in doing so the tests will start failing as they are using the same file that the runtime uses (unless you go and create a new config).

By having the schema inline it's clear looking at the tests what schema is being loaded.

characterList: [Character]
characterById (id : ID!): Character
planetById (id: ID! = 1): Planet
getPlanet(id: ID, name: String): Planet
planetList: [Planet]
planets(first: Int, after: String): PlanetConnection
}

type Mutation {
addPlanet(id: String, name: String): Planet
deletePlanet(id: String): Planet
}

type PlanetConnection {
items: [Planet]
endCursor: String
hasNextPage: Boolean
}

type Character {
id : ID,
name : String,
type: String,
homePlanet: Int,
primaryFunction: String
}

type Planet {
id : ID,
name : String
}";
_metadataStoreProvider.GraphQLSchema = jsonString;
_queryEngine = new CosmosQueryEngine(_clientProvider, _metadataStoreProvider);
_mutationEngine = new CosmosMutationEngine(_clientProvider, _metadataStoreProvider);
Expand Down Expand Up @@ -125,18 +157,27 @@ internal static void RegisterGraphQLType(string id,
/// Executes the GraphQL request and returns the results
/// </summary>
/// <param name="queryName"> Name of the GraphQL query/mutation</param>
/// <param name="graphQLQuery"> The GraphQL query/mutation</param>
/// <param name="query"> The GraphQL query/mutation</param>
/// <param name="variables">Variables to be included in the GraphQL request. If null, no variables property is included in the request, to pass an empty object provide an empty dictionary</param>
/// <returns></returns>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add the param variables description

internal static async Task<JsonElement> ExecuteGraphQLRequestAsync(string queryName, string graphQLQuery)
internal static async Task<JsonElement> ExecuteGraphQLRequestAsync(string queryName, string query, Dictionary<string, object> variables = null)
{
string queryJson = JObject.FromObject(new
{
query = graphQLQuery
}).ToString();
string queryJson = variables == null ?
JObject.FromObject(new { query }).ToString() :
JObject.FromObject(new
{
query,
variables
}).ToString();
_controller.ControllerContext.HttpContext = GetHttpContextWithBody(queryJson);
JsonElement graphQLResult = await _controller.PostAsync();

if (graphQLResult.TryGetProperty("errors", out JsonElement errors))
{
Assert.Fail(errors.GetRawText());
}

return graphQLResult.GetProperty("data").GetProperty(queryName);
}

}
}
Loading