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
25 changes: 19 additions & 6 deletions DataGateway.Service.Tests/MetadataStoreProviderForTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ namespace Azure.DataGateway.Service.Tests
public class MetadataStoreProviderForTest : IMetadataStoreProvider
{
private string _graphQLSchema;
private IDictionary<string, MutationResolver> _mutationResolvers = new Dictionary<string, MutationResolver>();
private IDictionary<string, GraphQLQueryResolver> _queryResolvers = new Dictionary<string, GraphQLQueryResolver>();
public Dictionary<string, MutationResolver> MutationResolvers { get; set; } = new();
public Dictionary<string, GraphQLQueryResolver> QueryResolvers { get; set; } = new();
public Dictionary<string, TableDefinition> Tables { get; set; } = new();

public void StoreGraphQLSchema(string schema)
{
Expand All @@ -23,25 +24,37 @@ public string GetGraphQLSchema()
public MutationResolver GetMutationResolver(string name)
{
MutationResolver result;
_mutationResolvers.TryGetValue(name, out result);
MutationResolvers.TryGetValue(name, out result);
return result;
}

public GraphQLQueryResolver GetQueryResolver(string name)
{
GraphQLQueryResolver result;
_queryResolvers.TryGetValue(name, out result);
QueryResolvers.TryGetValue(name, out result);
return result;
}

public TableDefinition GetTableDefinition(string name)
{
TableDefinition result;
Tables.TryGetValue(name, out result);
return result;
}

public void StoreMutationResolver(MutationResolver mutationResolver)
{
_mutationResolvers.Add(mutationResolver.Id, mutationResolver);
MutationResolvers.Add(mutationResolver.Id, mutationResolver);
}

public void StoreQueryResolver(GraphQLQueryResolver queryResolver)
{
_queryResolvers.Add(queryResolver.Id, queryResolver);
QueryResolvers.Add(queryResolver.Id, queryResolver);
}

public GraphqlType GetGraphqlType(string name)
{
throw new System.NotImplementedException();
}
}
}
175 changes: 156 additions & 19 deletions DataGateway.Service.Tests/MsSqlTests/MsSqlGraphQLQueryTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.DataGateway.Service.Controllers;
using Azure.DataGateway.Services;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;

namespace Azure.DataGateway.Service.Tests.MsSql
{
Expand Down Expand Up @@ -33,29 +35,84 @@ public static void InitializeTestFixture(TestContext context)
_graphQLController = new GraphQLController(_graphQLService);
}

#endregion

#region Tests
/// <summary>
/// Cleans up querying table used for Tests in this class. Only to be run once at
/// conclusion of test run, as defined by MSTest decorator.
/// Gets array of results for querying more than one item.
/// </summary>
[ClassCleanup]
public static void CleanupTestFixture()
/// <returns></returns>
[TestMethod]
public async Task MultipleResultQuery()
{
CleanupTestFixture(_integrationTableName);
}
string graphQLQueryName = "getBooks";
string graphQLQuery = @"{
getBooks(first: 123) {
id
title
}
}";
string msSqlQuery = $"SELECT id, title FROM books ORDER BY id FOR JSON PATH, INCLUDE_NULL_VALUES";

#endregion
string actual = await GetGraphQLResultAsync(graphQLQuery, graphQLQueryName);
string expected = await GetDatabaseResultAsync(msSqlQuery);

Assert.AreEqual(actual, expected);
}

#region Tests
/// <summary>
/// Gets result of quering singular object
/// Gets array of results for querying more than one item.
/// </summary>
/// <returns></returns>
[TestMethod]
public async Task SingleResultQuery()
public async Task MultipleResultJoinQuery()
{
string graphQLQueryName = "characterById";
string graphQLQuery = "{\"query\":\"{\\n characterById(id:2){\\n name\\n primaryFunction\\n}\\n}\\n\"}";
string msSqlQuery = $"SELECT name, primaryFunction FROM { _integrationTableName } WHERE id = 2 FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER";
string graphQLQueryName = "getBooks";
string graphQLQuery = @"{
getBooks(first: 100) {
id
title
publisher_id
publisher {
id
name
}
reviews(first: 100) {
id
content
}
}
}";
string msSqlQuery = @"
SELECT TOP 100 [table0].[id] AS [id],
[table0].[title] AS [title],
[table0].[publisher_id] AS [publisher_id],
JSON_QUERY([table1_subq].[data]) AS [publisher],
JSON_QUERY(COALESCE([table2_subq].[data], '[]')) AS [reviews]
FROM [books] AS [table0]
OUTER APPLY (
SELECT TOP 1 [table1].[id] AS [id],
[table1].[name] AS [name]
FROM [publishers] AS [table1]
WHERE [table0].[publisher_id] = [table1].[id]
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES,
WITHOUT_ARRAY_WRAPPER
) AS [table1_subq]([data])
OUTER APPLY (
SELECT TOP 100 [table2].[id] AS [id],
[table2].[content] AS [content]
FROM [reviews] AS [table2]
WHERE [table0].[id] = [table2].[book_id]
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES
) AS [table2_subq]([data])
WHERE 1 = 1
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES";

string actual = await GetGraphQLResultAsync(graphQLQuery, graphQLQueryName);
string expected = await GetDatabaseResultAsync(msSqlQuery);
Expand All @@ -68,11 +125,85 @@ public async Task SingleResultQuery()
/// </summary>
/// <returns></returns>
[TestMethod]
public async Task MultipleResultQuery()
public async Task DeeplyNestedJoinQuery()
{
string graphQLQueryName = "characterList";
string graphQLQuery = "{\"query\":\"{\\n characterList {\\n name\\n primaryFunction\\n }\\n}\\n\"}";
string msSqlQuery = $"SELECT name, primaryFunction FROM character FOR JSON PATH, INCLUDE_NULL_VALUES";
string graphQLQueryName = "getBooks";
string graphQLQuery = @"{
getBooks(first: 100) {
title
publisher {
name
books(first: 100) {
title
publisher {
name
books(first: 100) {
title
publisher {
name
}
}
}
}
}
}
}";
string msSqlQuery = @"
SELECT TOP 100 [table0].[title] AS [title],
JSON_QUERY([table1_subq].[data]) AS [publisher]
FROM [books] AS [table0]
OUTER APPLY (
SELECT TOP 1 [table1].[name] AS [name],
JSON_QUERY(COALESCE([table2_subq].[data], '[]')) AS [books]
FROM [publishers] AS [table1]
OUTER APPLY (
SELECT TOP 100 [table2].[title] AS [title],
JSON_QUERY([table3_subq].[data]) AS [publisher]
FROM [books] AS [table2]
OUTER APPLY (
SELECT TOP 1 [table3].[name] AS [name],
JSON_QUERY(COALESCE([table4_subq].[data], '[]')) AS [books]
FROM [publishers] AS [table3]
OUTER APPLY (
SELECT TOP 100 [table4].[title] AS [title],
JSON_QUERY([table5_subq].[data]) AS [publisher]
FROM [books] AS [table4]
OUTER APPLY (
SELECT TOP 1 [table5].[name] AS [name]
FROM [publishers] AS [table5]
WHERE [table4].[publisher_id] = [table5].[id]
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES,
WITHOUT_ARRAY_WRAPPER
) AS [table5_subq]([data])
WHERE [table3].[id] = [table4].[publisher_id]
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES
) AS [table4_subq]([data])
WHERE [table2].[publisher_id] = [table3].[id]
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES,
WITHOUT_ARRAY_WRAPPER
) AS [table3_subq]([data])
WHERE [table1].[id] = [table2].[publisher_id]
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES
) AS [table2_subq]([data])
WHERE [table0].[publisher_id] = [table1].[id]
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES,
WITHOUT_ARRAY_WRAPPER
) AS [table1_subq]([data])
WHERE 1 = 1
ORDER BY [id]
FOR JSON PATH,
INCLUDE_NULL_VALUES
";

string actual = await GetGraphQLResultAsync(graphQLQuery, graphQLQueryName);
string expected = await GetDatabaseResultAsync(msSqlQuery);
Expand All @@ -85,15 +216,21 @@ public async Task MultipleResultQuery()
#region Query Test Helper Functions
/// <summary>
/// Sends graphQL query through graphQL service, consisting of gql engine processing (resolvers, object serialization)
/// returning JSON formatted result from 'data' property.
/// returning JSON formatted result from 'data' property.
/// </summary>
/// <param name="graphQLQuery"></param>
/// <param name="graphQLQueryName"></param>
/// <returns>string in JSON format</returns>
public static async Task<string> GetGraphQLResultAsync(string graphQLQuery, string graphQLQueryName)
{
_graphQLController.ControllerContext.HttpContext = MsSqlTestBase.GetHttpContextWithBody(graphQLQuery);
string graphqlQueryJson = JObject.FromObject(new
{
query = graphQLQuery
}).ToString();
Console.WriteLine(graphqlQueryJson);
_graphQLController.ControllerContext.HttpContext = MsSqlTestBase.GetHttpContextWithBody(graphqlQueryJson);
JsonDocument graphQLResult = await _graphQLController.PostAsync();
Console.WriteLine(graphQLResult.RootElement.ToString());
JsonElement graphQLResultData = graphQLResult.RootElement.GetProperty("data").GetProperty(graphQLQueryName);
return graphQLResultData.ToString();
}
Expand Down
34 changes: 16 additions & 18 deletions DataGateway.Service.Tests/MsSqlTests/MsSqlRestApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class MsSqlRestApiTests : MsSqlTestBase
#region Test Fixture Setup
private static RestService _restService;
private static RestController _restController;
private static readonly string _integrationTableName = "characterTableForRestApi";
private static readonly string _integrationTableName = "books";

/// <summary>
/// Sets up test fixture for class, only to be run once per test run, as defined by
Expand All @@ -36,16 +36,6 @@ public static void InitializeTestFixture(TestContext context)
_restController = new RestController(_restService);
}

/// <summary>
/// Cleans up querying table used for Tests in this class. Only to be run once at
/// conclusion of test run, as defined by MSTest decorator.
/// </summary>
[ClassCleanup]
public static void CleanupTestFixture()
{
CleanupTestFixture(_integrationTableName);
}

#endregion

#region Positive Tests
Expand Down Expand Up @@ -74,8 +64,8 @@ await PerformTest(_restController.FindById,
public async Task FindByIdTestWithQueryStringFields()
{
string primaryKeyRoute = "id/1";
string queryStringWithFields = "?_f=id,name,type";
string msSqlQuery = $"SELECT [id], [name], [type] FROM { _integrationTableName } " +
string queryStringWithFields = "?_f=id,title";
string msSqlQuery = $"SELECT [id], [title] FROM { _integrationTableName } " +
$"WHERE id = 1 FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER";

await PerformTest(_restController.FindById,
Expand All @@ -97,7 +87,7 @@ await PerformTest(_restController.FindById,
public async Task FindByIdTestWithInvalidFields()
{
string primaryKeyRoute = "id/1";
string queryStringWithFields = "?_f=id,null,type";
string queryStringWithFields = "?_f=id,null";
string msSqlQuery = $"SELECT [id], [name], [type] FROM { _integrationTableName } " +
$"WHERE id = 1 FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER";

Expand Down Expand Up @@ -134,13 +124,21 @@ private static async Task PerformTest(Func<string, string, Task<JsonDocument>> a

try
{
JsonDocument actualJson = await api(entityName, primaryKeyRoute);
using JsonDocument actualJson = await api(entityName, primaryKeyRoute);
Assert.IsFalse(expectException);
string expected = await GetDatabaseResultAsync(msSqlQuery);
Assert.AreEqual(expected, ToJsonString(actualJson));
}
catch (Exception)
{
Assert.IsTrue(expectException);
if (expectException)
{
Assert.IsTrue(expectException);
}
else
{
throw;
}
}

}
Expand All @@ -151,8 +149,8 @@ private static async Task PerformTest(Func<string, string, Task<JsonDocument>> a
/// <param name="jdoc">The Json document.</param>
private static string ToJsonString(JsonDocument jdoc)
{
MemoryStream stream = new();
Utf8JsonWriter writer = new(stream, new JsonWriterOptions { Indented = false });
using MemoryStream stream = new();
using Utf8JsonWriter writer = new(stream, new JsonWriterOptions { Indented = false });
jdoc.WriteTo(writer);
writer.Flush();
return Encoding.UTF8.GetString(stream.ToArray());
Expand Down
Loading