Skip to content

Commit 0a6a626

Browse files
committed
Initial commit of ASB Local Emulator Builder
1 parent 9215d71 commit 0a6a626

28 files changed

+1039
-0
lines changed

.github/workflows/ci.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# This workflow will build a .NET project
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3+
4+
name: .NET
5+
6+
on:
7+
push:
8+
branches: [ "main" ]
9+
pull_request:
10+
branches: [ "main" ]
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
- name: Setup .NET
20+
uses: actions/setup-dotnet@v4
21+
with:
22+
dotnet-version: 8.0.x
23+
- name: Restore dependencies
24+
run: dotnet restore
25+
- name: Build
26+
run: dotnet build --no-restore
27+
- name: Test
28+
run: dotnet test --no-build --verbosity normal
29+
- name: Upload packages as artifacts
30+
uses: actions/upload-artifact@v4
31+
with:
32+
name: nuget packages
33+
path: "**/*.nupkg"
34+
- name: Push to GitHub Feed
35+
if: ${{ github.event_name != 'pull_request' }}
36+
run: dotnet nuget push **/*.nupkg --source https://nuget.pkg.github.com/${REPOSITORY_OWNER}/index.json --api-key ${GITHUB_TOKEN} --skip-duplicate
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
REPOSITORY_OWNER: ${{ github.repository_owner }}
40+
41+
release:
42+
if: startsWith(github.ref, 'refs/tags')
43+
runs-on: ubuntu-latest
44+
timeout-minutes: 5
45+
needs: [build]
46+
steps:
47+
- uses: actions/download-artifact@v4
48+
with:
49+
name: nuget packages
50+
- name: Push generated package to NuGet
51+
run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_KEY }} --skip-duplicate

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ bld/
3131
[Oo]bj/
3232
[Ll]og/
3333
[Ll]ogs/
34+
.idea/
3435

3536
# Visual Studio 2015/2017 cache/options directory
3637
.vs/
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureServiceBusEmulator.Configuration", "src\AzureServiceBusEmulator.Configuration\AzureServiceBusEmulator.Configuration.csproj", "{62644D2A-04E2-4D5F-B1CF-AF745D90714F}"
4+
EndProject
5+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureServiceBusEmulator.Configuration.UnitTest", "tests\AzureServiceBusEmulator.Configuration.UnitTest\AzureServiceBusEmulator.Configuration.UnitTest.csproj", "{CE614359-858B-4DEC-AF5A-1C244740AD16}"
6+
EndProject
7+
Global
8+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
9+
Debug|Any CPU = Debug|Any CPU
10+
Release|Any CPU = Release|Any CPU
11+
EndGlobalSection
12+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
13+
{62644D2A-04E2-4D5F-B1CF-AF745D90714F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14+
{62644D2A-04E2-4D5F-B1CF-AF745D90714F}.Debug|Any CPU.Build.0 = Debug|Any CPU
15+
{62644D2A-04E2-4D5F-B1CF-AF745D90714F}.Release|Any CPU.ActiveCfg = Release|Any CPU
16+
{62644D2A-04E2-4D5F-B1CF-AF745D90714F}.Release|Any CPU.Build.0 = Release|Any CPU
17+
{CE614359-858B-4DEC-AF5A-1C244740AD16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18+
{CE614359-858B-4DEC-AF5A-1C244740AD16}.Debug|Any CPU.Build.0 = Debug|Any CPU
19+
{CE614359-858B-4DEC-AF5A-1C244740AD16}.Release|Any CPU.ActiveCfg = Release|Any CPU
20+
{CE614359-858B-4DEC-AF5A-1C244740AD16}.Release|Any CPU.Build.0 = Release|Any CPU
21+
EndGlobalSection
22+
EndGlobal

Directory.Build.props

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project>
2+
<PropertyGroup>
3+
<TargetFramework>net8.0</TargetFramework>
4+
<ImplicitUsings>enable</ImplicitUsings>
5+
<Nullable>enable</Nullable>
6+
<Authors>Paul Reardon</Authors>
7+
<RepositoryUrl>https://github.com/preardon/AzureServiceBusEmulator.Configuration</RepositoryUrl>
8+
<RepositoryType>git</RepositoryType>
9+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
10+
</PropertyGroup>
11+
</Project>

Directory.Packages.props

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project>
2+
<PropertyGroup>
3+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<PackageVersion Include="coverlet.collector" Version="6.0.2">
7+
<PrivateAssets>all</PrivateAssets>
8+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
9+
</PackageVersion>
10+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
11+
<PackageVersion Include="NUnit" Version="3.14.0"/>
12+
<PackageVersion Include="NUnit.Analyzers" Version="4.4.0">
13+
<PrivateAssets>all</PrivateAssets>
14+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
15+
</PackageVersion>
16+
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
17+
</ItemGroup>
18+
</Project>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using ReardonTech.AzureServiceBusEmulator.Configuration.Builders;
2+
using ReardonTech.AzureServiceBusEmulator.Configuration.Model;
3+
4+
namespace ReardonTech.AzureServiceBusEmulator.Configuration;
5+
6+
public class AsbEmulatorConfigurationBuilder()
7+
{
8+
private string _loggingType = "File";
9+
10+
private List<AsbNamespace> _namespaces = new List<AsbNamespace>();
11+
12+
/// <summary>
13+
/// Include configuration for A ASB Namepsace
14+
/// </summary>
15+
/// <param name="asbNamespace"></param>
16+
/// <returns></returns>
17+
private AsbEmulatorConfigurationBuilder WithNameSpace(AsbNamespaceBuilder asbNamespace)
18+
{
19+
_namespaces.Add(asbNamespace.Build());
20+
return this;
21+
}
22+
23+
/// <summary>
24+
/// Add a Namespace to the configuration.
25+
/// </summary>
26+
/// <param name="name">The name of the namepsace</param>
27+
/// <param name="namespaceOptions"></param>
28+
/// <returns>ASB Emulator Configuration Builder</returns>
29+
public static AsbEmulatorConfigurationBuilder WithNamespace(string name, Action<AsbNamespaceBuilder> namespaceOptions)
30+
{
31+
var asbNamespaceBuilder = new AsbNamespaceBuilder(name);
32+
namespaceOptions.Invoke(asbNamespaceBuilder);
33+
return new AsbEmulatorConfigurationBuilder().WithNameSpace(asbNamespaceBuilder);
34+
}
35+
36+
/// <summary>
37+
/// Configure the Logging for this ASB Emulator
38+
/// </summary>
39+
/// <param name="loggingType">What type of logging to use (default: 'File')</param>
40+
/// <returns>ASB Emulator Configuration Builder</returns>
41+
public AsbEmulatorConfigurationBuilder WithLogging(string loggingType)
42+
{
43+
_loggingType = loggingType;
44+
return this;
45+
}
46+
47+
/// <summary>
48+
/// Build the Configuration
49+
/// </summary>
50+
/// <returns>Azure Service Bus Emulator Configuration</returns>
51+
public AsbConfig Build()
52+
=> new AsbConfig(new UserConfig(_namespaces.ToArray(), new AsbLogging(_loggingType)));
53+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<AssemblyName>ReardonTech.AzureServiceBusEmulator.Configuration</AssemblyName>
5+
<RootNamespace>ReardonTech.AzureServiceBusEmulator.Configuration</RootNamespace>
6+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
7+
<PackageId>ReardonTech.AzureServiceBusEmulator.Configuration</PackageId>
8+
<Title>Azure Service Bus Emulator Configuration Builder</Title>
9+
</PropertyGroup>
10+
11+
</Project>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using ReardonTech.AzureServiceBusEmulator.Configuration.Model;
2+
3+
namespace ReardonTech.AzureServiceBusEmulator.Configuration.Builders;
4+
5+
/// <summary>
6+
/// The Namespace Builder
7+
/// </summary>
8+
/// <param name="name">The name of the namespace</param>
9+
public class AsbNamespaceBuilder(string name)
10+
{
11+
private readonly List<AsbQueue> _queues = [];
12+
private readonly List<AsbTopic> _topics = [];
13+
14+
public static AsbNamespaceBuilder WithName(string name) => new AsbNamespaceBuilder(name);
15+
16+
/// <summary>
17+
/// Add a queue to the configuration
18+
/// </summary>
19+
/// <param name="queueName"></param>
20+
/// <param name="queueOptions"></param>
21+
/// <returns></returns>
22+
public AsbNamespaceBuilder WithQueue(string queueName, Action<AsbQueueBuilder>? queueOptions = null)
23+
{
24+
var builder = new AsbQueueBuilder(queueName);
25+
queueOptions?.Invoke(builder);
26+
_queues.Add(builder.Build());
27+
return this;
28+
}
29+
30+
/// <summary>
31+
/// Add a Topic to the configuration
32+
/// </summary>
33+
/// <param name="topicName"></param>
34+
/// <param name="topicOptions"></param>
35+
/// <returns></returns>
36+
public AsbNamespaceBuilder WithTopic(string topicName, Action<AsbTopicBuilder>? topicOptions = null)
37+
{
38+
var builder = new AsbTopicBuilder(topicName);
39+
topicOptions?.Invoke(builder);
40+
_topics.Add(builder.Build());
41+
return this;
42+
}
43+
public AsbNamespace Build() => new AsbNamespace(name, _queues.ToArray(), _topics.ToArray());
44+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using ReardonTech.AzureServiceBusEmulator.Configuration.Model;
2+
3+
namespace ReardonTech.AzureServiceBusEmulator.Configuration.Builders;
4+
5+
/// <summary>
6+
/// Builder for an ASB Queue
7+
/// </summary>
8+
/// <param name="name"></param>
9+
public class AsbQueueBuilder(string name)
10+
{
11+
private bool _deadLetteringOnMessageExpiration = false;
12+
private string _defaultMessageTimeToLive = "PT1H";
13+
private string _duplicateDetectionHistoryTimeWindow = "PT20S";
14+
private string _forwardDeadLetteredMessagesTo = "";
15+
private string _forwardTo = "";
16+
private string _lockDuration = "PT1M";
17+
private int _maxDeliveryCount = 3;
18+
private bool _requiresDuplicateDetection = false;
19+
private bool _requiresSession = false;
20+
21+
/// <summary>
22+
/// Enable Dead lettering on Message Expiration
23+
/// </summary>
24+
/// <returns>ASB Queue Builder</returns>
25+
public AsbQueueBuilder DeadLetteringOnMessageExpiration(bool deadLetteringOnMessageExpiration = true)
26+
{
27+
_deadLetteringOnMessageExpiration = deadLetteringOnMessageExpiration;
28+
return this;
29+
}
30+
31+
/// <summary>
32+
/// Require the use of AsbSessions
33+
/// </summary>
34+
/// <returns>ASB Queue Builder</returns>
35+
public AsbQueueBuilder RequireSessions(bool requireSession = true)
36+
{
37+
_requiresSession = requireSession;
38+
return this;
39+
}
40+
41+
/// <summary>
42+
/// The default amount of time before the message is removed from the queue
43+
/// </summary>
44+
/// <param name="defaultMessageTimeToLive">The default amount of time before the message is removed from the queue.</param>
45+
/// <returns>ASB Queue Builder</returns>
46+
public AsbQueueBuilder DefaultMessageTimeToLive(string defaultMessageTimeToLive = "PT1H")
47+
{
48+
_defaultMessageTimeToLive = defaultMessageTimeToLive;
49+
return this;
50+
}
51+
52+
/// <summary>
53+
/// Detect duplicate messages inside of this time window
54+
/// </summary>
55+
/// <param name="duplicateDetectionHistoryTimeWindow"></param>
56+
/// <returns>ASB Queue Builder</returns>
57+
public AsbQueueBuilder DuplicateDetectionHistoryTimeWindow(string duplicateDetectionHistoryTimeWindow = "PT20S")
58+
{
59+
_duplicateDetectionHistoryTimeWindow = duplicateDetectionHistoryTimeWindow;
60+
return this;
61+
}
62+
63+
/// <summary>
64+
/// Set a queue to forward dead letters to
65+
/// </summary>
66+
/// <param name="forwardDeadLetteredMessagesTo">Queue to forward dead letters to</param>
67+
/// <returns>ASB Queue Builder</returns>
68+
public AsbQueueBuilder ForwardDeadLetteredMessagesTo(string forwardDeadLetteredMessagesTo)
69+
{
70+
_forwardDeadLetteredMessagesTo = forwardDeadLetteredMessagesTo;
71+
return this;
72+
}
73+
74+
/// <summary>
75+
/// Queue to forward messags to
76+
/// </summary>
77+
/// <param name="forwardTo"></param>
78+
/// <returns>ASB Queue Builder</returns>
79+
public AsbQueueBuilder ForwardTo(string forwardTo)
80+
{
81+
_forwardTo = forwardTo;
82+
return this;
83+
}
84+
85+
/// <summary>
86+
/// The amount of time before a lock expires
87+
/// </summary>
88+
/// <param name="lockDuration"></param>
89+
/// <returns>ASB Queue Builder</returns>
90+
public AsbQueueBuilder LockDuration(string lockDuration = "PT1M")
91+
{
92+
_lockDuration = lockDuration;
93+
return this;
94+
}
95+
96+
/// <summary>
97+
/// The maximum redelivers before the message is removed form the queue
98+
/// </summary>
99+
/// <param name="maxDeliveryCount"></param>
100+
/// <returns>ASB Queue Builder</returns>
101+
public AsbQueueBuilder MaxDeliveryCount(int maxDeliveryCount)
102+
{
103+
_maxDeliveryCount = maxDeliveryCount;
104+
return this;
105+
}
106+
107+
/// <summary>
108+
/// Does the queue require duplication detection
109+
/// </summary>
110+
/// <param name="requiresDuplicateDetection">does the queue require duplication detection</param>
111+
/// <returns>ASB Queue Builder</returns>
112+
public AsbQueueBuilder RequiresDuplicateDetection(bool requiresDuplicateDetection = true)
113+
{
114+
_requiresDuplicateDetection = requiresDuplicateDetection;
115+
return this;
116+
}
117+
118+
/// <summary>
119+
/// Build the Queue
120+
/// </summary>
121+
/// <returns>ASB Queue Configuration</returns>
122+
public AsbQueue Build() => new AsbQueue(name,
123+
new AsbChannelProperties(_deadLetteringOnMessageExpiration, _defaultMessageTimeToLive,
124+
_duplicateDetectionHistoryTimeWindow, _forwardDeadLetteredMessagesTo, _forwardTo, _lockDuration,
125+
_maxDeliveryCount, _requiresDuplicateDetection, _requiresSession));
126+
}

0 commit comments

Comments
 (0)