Skip to content

Commit

Permalink
Created Testing library for the CDK assertion template. Defined first…
Browse files Browse the repository at this point in the history
… assertion resource.
  • Loading branch information
JZechy committed Feb 5, 2024
1 parent 7be8253 commit f3029d6
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 7 deletions.
17 changes: 17 additions & 0 deletions CDK.Framework.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sagittaras.CDK.Tests.Route5
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sagittaras.CDK.Tests", "Sagittaras.CDK.Tests\Sagittaras.CDK.Tests.csproj", "{E42AD3AD-DBF2-4A25-98CF-E8DA76B356AF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3. Testing", "3. Testing", "{3A01C380-5151-4039-A00C-A33687E00861}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sagittaras.CDK.Testing", "Sagittaras.CDK.Testing\Sagittaras.CDK.Testing.csproj", "{D753C559-6F75-4493-A5A3-00CD0727A2DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sagittaras.CDK.Testing.Route53", "Sagittaras.CDK.Testing.Route53\Sagittaras.CDK.Testing.Route53.csproj", "{2C4B4454-A145-405E-85BC-F54B56EAC39B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -57,6 +63,9 @@ Global
{C8F37959-BCB7-43DC-9812-A5623E420923} = {506BD5FC-1E9D-47D4-A609-F977EDF69184}
{64D45D92-6955-42FC-87CD-E1419FB1EA17} = {F2C4D978-97A6-4451-AAD2-16EDCA158D97}
{E42AD3AD-DBF2-4A25-98CF-E8DA76B356AF} = {F2C4D978-97A6-4451-AAD2-16EDCA158D97}
{3A01C380-5151-4039-A00C-A33687E00861} = {AEF441A3-E5F9-46D2-82B9-8EE105CC3274}
{D753C559-6F75-4493-A5A3-00CD0727A2DC} = {3A01C380-5151-4039-A00C-A33687E00861}
{2C4B4454-A145-405E-85BC-F54B56EAC39B} = {3A01C380-5151-4039-A00C-A33687E00861}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{940EEEA3-A068-4793-A44A-D2FCE1143E49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -95,5 +104,13 @@ Global
{E42AD3AD-DBF2-4A25-98CF-E8DA76B356AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E42AD3AD-DBF2-4A25-98CF-E8DA76B356AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E42AD3AD-DBF2-4A25-98CF-E8DA76B356AF}.Release|Any CPU.Build.0 = Release|Any CPU
{D753C559-6F75-4493-A5A3-00CD0727A2DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D753C559-6F75-4493-A5A3-00CD0727A2DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D753C559-6F75-4493-A5A3-00CD0727A2DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D753C559-6F75-4493-A5A3-00CD0727A2DC}.Release|Any CPU.Build.0 = Release|Any CPU
{2C4B4454-A145-405E-85BC-F54B56EAC39B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C4B4454-A145-405E-85BC-F54B56EAC39B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C4B4454-A145-405E-85BC-F54B56EAC39B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C4B4454-A145-405E-85BC-F54B56EAC39B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
12 changes: 12 additions & 0 deletions Sagittaras.CDK.Testing.Route53/HostedZoneAssertion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Sagittaras.CDK.Testing.Resources;

namespace Sagittaras.CDK.Testing.Route53;

/// <summary>
/// Assertion for AWS::Route53::HostedZone.
/// </summary>
public class HostedZoneAssertion : ResourceAssertion<HostedZoneProperties>
{
/// <inheritdoc />
public override string Type => "AWS::Route53::HostedZone";
}
23 changes: 23 additions & 0 deletions Sagittaras.CDK.Testing.Route53/HostedZoneProperties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Sagittaras.CDK.Testing.Resources;

namespace Sagittaras.CDK.Testing.Route53;

/// <summary>
/// Properties describing the Hosted Zone in the CloudFormation template.
/// </summary>
public class HostedZoneProperties : ResourceProperties
{
private string? _name;

/// <summary>
/// Name of the hosted zone.
/// </summary>
/// <remarks>
/// Automatically appends the trailing dot that is generated for CloudFormation template.
/// </remarks>
public string? Name
{
get => _name;
set => _name = value?.TrimEnd('.') + ".";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Sagittaras.CDK.Testing\Sagittaras.CDK.Testing.csproj" />
</ItemGroup>

</Project>
22 changes: 22 additions & 0 deletions Sagittaras.CDK.Testing/Extensions/TemplateAssertionExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Amazon.CDK.Assertions;
using Sagittaras.CDK.Testing.Resources;

namespace Sagittaras.CDK.Testing.Extensions;

/// <summary>
/// Extends the assertion template from the CDK by custom assertion methods.
/// </summary>
public static class TemplateAssertionExtension
{
/// <summary>
/// Asserts that the template has a resource with the given description.
/// </summary>
/// <param name="template"></param>
/// <param name="assertion"></param>
/// <typeparam name="TResourceAssertion"></typeparam>
public static void Assert<TResourceAssertion>(this Template template, TResourceAssertion assertion)
where TResourceAssertion : IResourceAssertion
{
template.HasResource(assertion.Type, assertion.GetResourceDescription());
}
}
31 changes: 31 additions & 0 deletions Sagittaras.CDK.Testing/Resources/IResourceAssertion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Sagittaras.CDK.Testing.Resources;

/// <summary>
/// Basic interface describing the assertion for AWS resource.
/// </summary>
public interface IResourceAssertion
{
/// <summary>
/// AWS Resource type.
/// </summary>
string Type { get; }

/// <summary>
/// Converts the resource description to a dictionary suitable for template assertion.
/// </summary>
/// <returns></returns>
IDictionary<string, object> GetResourceDescription();
}

/// <summary>
/// Extends the basic resource assertion with properties.
/// </summary>
/// <typeparam name="TProperties">Type of the properties used for the resource.</typeparam>
public interface IResourceAssertion<TProperties> : IResourceAssertion
where TProperties : IResourceProperties, new()
{
/// <summary>
/// Properties that helps to identify the resource.
/// </summary>
TProperties Properties { get; set; }
}
13 changes: 13 additions & 0 deletions Sagittaras.CDK.Testing/Resources/IResourceProperties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Sagittaras.CDK.Testing.Resources;

/// <summary>
/// Describes the properties of a resource.
/// </summary>
public interface IResourceProperties
{
/// <summary>
/// Converts the properties to a dictionary suitable for template assertion.
/// </summary>
/// <returns></returns>
IDictionary<string, object> ToDictionary();
}
43 changes: 43 additions & 0 deletions Sagittaras.CDK.Testing/Resources/ResourceAssertion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Reflection;

namespace Sagittaras.CDK.Testing.Resources;

/// <summary>
/// Abstract implementation of <see cref="IResourceAssertion{TProperties}"/>.
/// </summary>
public abstract class ResourceAssertion<TProperties> : IResourceAssertion<TProperties>
where TProperties : IResourceProperties, new()
{
/// <inheritdoc />
public abstract string Type { get; }

/// <inheritdoc />
public TProperties Properties { get; set; } = new();

/// <summary>
/// Gets the property members of the derived class.
/// </summary>
private IEnumerable<PropertyInfo> PropertyMembers => GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);

/// <inheritdoc />
public IDictionary<string, object> GetResourceDescription()
{
Dictionary<string, object> description = new();
foreach (PropertyInfo member in PropertyMembers)
{
object? value = member.GetValue(this);
switch (value)
{
case null:
continue;
case IResourceProperties properties:
value = properties.ToDictionary();
break;
}

description.Add(member.Name, value);
}

return description;
}
}
35 changes: 35 additions & 0 deletions Sagittaras.CDK.Testing/Resources/ResourceProperties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Reflection;

namespace Sagittaras.CDK.Testing.Resources;

/// <summary>
/// Abstract implementation of <see cref="IResourceProperties"/> that provides a default implementation of <see cref="IResourceProperties.ToDictionary"/>.
/// </summary>
/// <remarks>
/// The resource properties should be nullable types to exclude them from the dictionary.
/// </remarks>
public abstract class ResourceProperties : IResourceProperties
{
/// <summary>
/// Gets all properties members of the class.
/// </summary>
private IEnumerable<PropertyInfo> Properties => GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

/// <inheritdoc />
public IDictionary<string, object> ToDictionary()
{
Dictionary<string, object> dict = new();
foreach (PropertyInfo property in Properties)
{
object? value = property.GetValue(this);
if (value is null)
{
continue;
}

dict[property.Name] = value;
}

return dict;
}
}
13 changes: 13 additions & 0 deletions Sagittaras.CDK.Testing/Sagittaras.CDK.Testing.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Sagittaras.CDK.Framework\Sagittaras.CDK.Framework.csproj" />
</ItemGroup>

</Project>
10 changes: 7 additions & 3 deletions Sagittaras.CDK.Tests.Route53/PublicHostedZoneTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Amazon.CDK;
using Amazon.CDK.Assertions;
using Sagittaras.CDK.Framework.Route53;
using Sagittaras.CDK.Testing.Extensions;
using Sagittaras.CDK.Testing.Route53;
using Xunit;

namespace Sagittaras.CDK.Tests.Route53;
Expand All @@ -23,10 +25,12 @@ public void Test_BaseFactoryUsage()
.Construct();

Template template = StackTemplate;
template.HasResourceProperties("AWS::Route53::HostedZone", new Dictionary<string, object>
template.Assert(new HostedZoneAssertion
{
// Name has trailing dot in the CloudFormation template.
{ "Name", $"{Domain}." }
Properties = new HostedZoneProperties
{
Name = Domain
}
});
template.ResourceCountIs("AWS::Route53::HostedZone", 1);
template.ResourceCountIs("AWS::Route53::RecordSet", 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

<ItemGroup>
<ProjectReference Include="..\Sagittaras.CDK.Framework.Route53\Sagittaras.CDK.Framework.Route53.csproj" />
<ProjectReference Include="..\Sagittaras.CDK.Testing.Route53\Sagittaras.CDK.Testing.Route53.csproj" />
<ProjectReference Include="..\Sagittaras.CDK.Tests\Sagittaras.CDK.Tests.csproj" />
</ItemGroup>

Expand Down
8 changes: 4 additions & 4 deletions Sagittaras.CDK.Tests/ConstructTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ protected ConstructTest()
App = new App();
Stack = new Stack(App);
}

/// <summary>
/// Instance of App under which the stack is defined.
/// </summary>
protected App App { get; }

/// <summary>
/// Instance of stack to which the constructs within the test can be assigned.
/// </summary>
protected Stack Stack { get; }
protected Stack Stack { get; }

/// <summary>
/// Creates a new instance of Assertion Template from current stack state.
/// </summary>
Expand Down

0 comments on commit f3029d6

Please sign in to comment.