Skip to content

Unit Tests: Field Ordering, AddGraphQL #146

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 1 commit into from
Dec 20, 2023
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
48 changes: 28 additions & 20 deletions src/graphql-aspnet/Configuration/GraphQLSchemaBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,16 @@ static GraphQLSchemaBuilderExtensions()
/// <param name="serviceCollection">The service collection to clear.</param>
public static void Clear(IServiceCollection serviceCollection)
{
if (!SCHEMA_REGISTRATIONS.TryGetValue(serviceCollection, out var value))
lock (SCHEMA_REGISTRATIONS)
{
return;
}
if (!SCHEMA_REGISTRATIONS.TryGetValue(serviceCollection, out var value))
{
return;
}

value.Clear();
SCHEMA_REGISTRATIONS.Remove(serviceCollection);
value.Clear();
SCHEMA_REGISTRATIONS.Remove(serviceCollection);
}
}

/// <summary>
Expand All @@ -60,12 +63,15 @@ public static void Clear(IServiceCollection serviceCollection)
/// </summary>
public static void Clear()
{
foreach (var collection in SCHEMA_REGISTRATIONS.Values)
lock (SCHEMA_REGISTRATIONS)
{
collection.Clear();
}
foreach (var injectorCollection in SCHEMA_REGISTRATIONS.Values)
{
injectorCollection.Clear();
}

SCHEMA_REGISTRATIONS.Clear();
SCHEMA_REGISTRATIONS.Clear();
}
}

/// <summary>
Expand Down Expand Up @@ -96,7 +102,7 @@ public static ISchemaBuilder<TSchema> AddGraphQL<TSchema>(
where TSchema : class, ISchema
{
Validation.ThrowIfNull(serviceCollection, nameof(serviceCollection));
var injectorCollection = GetSchemaInjectorCollection(serviceCollection);
var injectorCollection = GetOrAddSchemaInjectorCollection(serviceCollection);
if (injectorCollection.ContainsKey(typeof(TSchema)))
{
throw new GraphTypeDeclarationException(
Expand Down Expand Up @@ -166,24 +172,26 @@ public static void UseGraphQL(this IServiceProvider serviceProvider)
}

/// <summary>
/// Get or create schema injector collection for the service collection.
/// Get or create a schema injector collection for the service collection being harnessed.
/// </summary>
/// <param name="serviceCollection">The service collection to create schema injector collection for</param>
/// <returns>Existing or new schema injector collection</returns>
private static ISchemaInjectorCollection GetSchemaInjectorCollection(IServiceCollection serviceCollection)
private static ISchemaInjectorCollection GetOrAddSchemaInjectorCollection(IServiceCollection serviceCollection)
{
if (SCHEMA_REGISTRATIONS.TryGetValue(serviceCollection, out var value))
{
return value;
}

var injectorCollection = new SchemaInjectorCollection()
lock (SCHEMA_REGISTRATIONS)
{
ServiceCollection = serviceCollection,
};
serviceCollection.AddSingleton<ISchemaInjectorCollection>(injectorCollection);
value = injectorCollection;
SCHEMA_REGISTRATIONS.Add(serviceCollection, value);
if (SCHEMA_REGISTRATIONS.TryGetValue(serviceCollection, out value))
return value;

var injectorCollection = new SchemaInjectorCollection(serviceCollection);

serviceCollection.AddSingleton<ISchemaInjectorCollection>(injectorCollection);
value = injectorCollection;
SCHEMA_REGISTRATIONS.Add(serviceCollection, value);
}

return value;
}
Expand Down
12 changes: 11 additions & 1 deletion src/graphql-aspnet/Configuration/SchemaInjectorCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace GraphQL.AspNet.Configuration
{
using System;
using System.Collections.Generic;
using GraphQL.AspNet.Common;
using GraphQL.AspNet.Interfaces.Configuration;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -19,7 +20,16 @@ namespace GraphQL.AspNet.Configuration
/// </summary>
public class SchemaInjectorCollection : Dictionary<Type, ISchemaInjector>, ISchemaInjectorCollection
{
/// <summary>
/// Initializes a new instance of the <see cref="SchemaInjectorCollection"/> class.
/// </summary>
/// <param name="serviceCollection">The service collection this set is tracking against.</param>
public SchemaInjectorCollection(IServiceCollection serviceCollection)
{
this.ServiceCollection = Validation.ThrowIfNullOrReturn(serviceCollection, nameof(serviceCollection));
}

/// <inheritdoc />
public IServiceCollection ServiceCollection { get; set; }
public IServiceCollection ServiceCollection { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -353,5 +353,25 @@ public void AddGraphQL_UseGraphQL_SameSchema()
Assert.IsTrue(schema1.KnownTypes.Contains(typeof(Candle)));
Assert.IsTrue(schema2.KnownTypes.Contains(typeof(Candle)));
}

[Test]
public void AddGraphQL_AttemptingToInitializeSchemaASecondTime_ThrowsException()
{
var service1Collection = new ServiceCollection();
var service2Collection = new ServiceCollection();

service1Collection.AddGraphQL<CandleSchema>(options =>
{
options.AddGraphType<Candle>();
});

Assert.Throws<GraphTypeDeclarationException>(() =>
{
service1Collection.AddGraphQL<CandleSchema>(options =>
{
options.AddGraphType<Candle>();
});
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// *************************************************************
// project: graphql-aspnet
// --
// repo: https://github.com/graphql-aspnet
// docs: https://graphql-aspnet.github.io
// --
// License: MIT
// *************************************************************

namespace GraphQL.AspNet.Tests.Execution
{
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using GraphQL.AspNet.Tests.Execution.FieldExecutionorderTestData;
using GraphQL.AspNet.Tests.Framework;
using NUnit.Framework;

[TestFixture]
public class FieldExecutionOrderTests
{
private static readonly Regex _whitespace = new Regex(@"\s+");

[Test]
public async Task OrderTest()
{
var server = new TestServerBuilder()
.AddGraphQL(o =>
{
o.AddType<HamburgerController>();
o.AddType<ChickenController>();
o.ResponseOptions.ExposeExceptions = true;
})
.Build();

var builder = server.CreateQueryContextBuilder()
.AddQueryText("query { " +
" retrieveDefaultChickenMeal {" +
" description " +
" name " +
" id" +
" }" +
" hamburger { " +
" retrieveOtherHamburgerMeal {" +
" weight " +
" name " +
" id" +
" description " +
" }" +
" }" +
" chicken { " +
" retrieveOtherChickenMeal {" +
" id" +
" description " +
" name " +
" }" +
" }" +
" retrieveDefaultHamburgerMeal {" +
" id" +
" description " +
" name " +
" weight " +
" }" +
"}");

var expectedOutput =
@"{
""data"": {
""retrieveDefaultChickenMeal"": {
""description"": ""a top level chicken sandwich"",
""name"": ""Chicken Bacon Ranch"",
""id"": 5
},
""hamburger"": {
""retrieveOtherHamburgerMeal"": {
""weight"": 1.3,
""name"": ""Tiny Hamburger"",
""id"": 5,
""description"": ""a nested Hamburger""
}
},
""chicken"": {
""retrieveOtherChickenMeal"": {
""id"": 5,
""description"": ""a nested chicken sandwich"",
""name"": ""Chicken Lettuce Tomato""
}
},
""retrieveDefaultHamburgerMeal"": {
""id"": 5,
""description"": ""a top level hamburger"",
""name"": ""Hamburger Supreme"",
""weight"": 2.5
}
}
}";

var result = await server.RenderResult(builder);

// must be an exact string with the exact character order for the data
// dont use json matching just to be sure
result = _whitespace.Replace(result, string.Empty);
expectedOutput = _whitespace.Replace(expectedOutput, string.Empty);

Assert.AreEqual(expectedOutput, result);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// *************************************************************
// project: graphql-aspnet
// --
// repo: https://github.com/graphql-aspnet
// docs: https://graphql-aspnet.github.io
// --
// License: MIT
// *************************************************************

namespace GraphQL.AspNet.Tests.Execution.FieldExecutionorderTestData
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GraphQL.AspNet.Attributes;
using GraphQL.AspNet.Controllers;

public class ChickenController : GraphController
{
[QueryRoot]
public ChickenMeal RetrieveDefaultChickenMeal()
{
return new ChickenMeal()
{
Id = 5,
Name = "Chicken Bacon Ranch",
Description = "a top level chicken sandwich",
};
}

[Query]
public ChickenMeal RetrieveOtherChickenMeal()
{
return new ChickenMeal()
{
Id = 5,
Name = "Chicken Lettuce Tomato",
Description = "a nested chicken sandwich",
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// *************************************************************
// project: graphql-aspnet
// --
// repo: https://github.com/graphql-aspnet
// docs: https://graphql-aspnet.github.io
// --
// License: MIT
// *************************************************************

namespace GraphQL.AspNet.Tests.Execution.FieldExecutionorderTestData
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class ChickenMeal
{
public int Id { get; set; }

public string Name { get; set; }

public string Description { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// *************************************************************
// project: graphql-aspnet
// --
// repo: https://github.com/graphql-aspnet
// docs: https://graphql-aspnet.github.io
// --
// License: MIT
// *************************************************************

namespace GraphQL.AspNet.Tests.Execution.FieldExecutionorderTestData
{
using GraphQL.AspNet.Attributes;
using GraphQL.AspNet.Controllers;

public class HamburgerController : GraphController
{
[QueryRoot]
public HamburgerMeal RetrieveDefaultHamburgerMeal()
{
return new HamburgerMeal()
{
Id = 5,
Name = "Hamburger Supreme",
Weight = 2.5f,
Description = "a top level hamburger",
};
}

[Query]
public HamburgerMeal RetrieveOtherHamburgerMeal()
{
return new HamburgerMeal()
{
Id = 5,
Name = "Tiny Hamburger",
Weight = 1.3f,
Description = "a nested Hamburger",
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// *************************************************************
// project: graphql-aspnet
// --
// repo: https://github.com/graphql-aspnet
// docs: https://graphql-aspnet.github.io
// --
// License: MIT
// *************************************************************

namespace GraphQL.AspNet.Tests.Execution.FieldExecutionorderTestData
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class HamburgerMeal
{
public int Id { get; set; }

public string Name { get; set; }

public float Weight { get; set; }

public string Description { get; set; }
}
}