Skip to content

Commit 66c6a82

Browse files
authored
RabbitMQ support (#144)
2 parents aec497d + f8b38a6 commit 66c6a82

18 files changed

+1309
-61
lines changed

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<PackageVersion Include="Moq" Version="4.20.70" />
2121
<PackageVersion Include="MSTest.TestAdapter" Version="3.5.2" />
2222
<PackageVersion Include="MSTest.TestFramework" Version="3.5.2" />
23+
<PackageVersion Include="RabbitMQ.Client" Version="6.8.1" />
2324
<PackageVersion Include="RichardSzalay.MockHttp" Version="7.0.0" />
2425
<PackageVersion Include="StackExchange.Redis" Version="2.8.0" />
2526
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />

PlanningPokerCore.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApplicationIntegrationSimul
4848
test\ApplicationIntegrationSimulator\README.md = test\ApplicationIntegrationSimulator\README.md
4949
EndProjectSection
5050
EndProject
51+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duracellko.PlanningPoker.RabbitMQ", "src\Duracellko.PlanningPoker.RabbitMQ\Duracellko.PlanningPoker.RabbitMQ.csproj", "{811F62DE-C15B-4A90-887C-22F68B17EE2A}"
52+
EndProject
53+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duracellko.PlanningPoker.RabbitMQ.Test", "test\Duracellko.PlanningPoker.RabbitMQ.Test\Duracellko.PlanningPoker.RabbitMQ.Test.csproj", "{9D21ABE1-B43C-4FD7-82D8-A4BA7AAF7991}"
54+
EndProject
5155
Global
5256
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5357
Debug|Any CPU = Debug|Any CPU
@@ -106,6 +110,14 @@ Global
106110
{EDD1B4E6-C1DE-45F6-A86A-ABEA17C30CEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
107111
{EDD1B4E6-C1DE-45F6-A86A-ABEA17C30CEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
108112
{EDD1B4E6-C1DE-45F6-A86A-ABEA17C30CEE}.Release|Any CPU.Build.0 = Release|Any CPU
113+
{811F62DE-C15B-4A90-887C-22F68B17EE2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
114+
{811F62DE-C15B-4A90-887C-22F68B17EE2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
115+
{811F62DE-C15B-4A90-887C-22F68B17EE2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
116+
{811F62DE-C15B-4A90-887C-22F68B17EE2A}.Release|Any CPU.Build.0 = Release|Any CPU
117+
{9D21ABE1-B43C-4FD7-82D8-A4BA7AAF7991}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
118+
{9D21ABE1-B43C-4FD7-82D8-A4BA7AAF7991}.Debug|Any CPU.Build.0 = Debug|Any CPU
119+
{9D21ABE1-B43C-4FD7-82D8-A4BA7AAF7991}.Release|Any CPU.ActiveCfg = Release|Any CPU
120+
{9D21ABE1-B43C-4FD7-82D8-A4BA7AAF7991}.Release|Any CPU.Build.0 = Release|Any CPU
109121
EndGlobalSection
110122
GlobalSection(SolutionProperties) = preSolution
111123
HideSolutionNode = FALSE
@@ -125,6 +137,8 @@ Global
125137
{B5F7A7A3-C1F5-4497-98FE-6659932DDBCF} = {9BE135A3-3D75-40BD-BA92-5961167FD719}
126138
{EDD1B4E6-C1DE-45F6-A86A-ABEA17C30CEE} = {6620FD4B-0154-46A5-A929-8326DB18769F}
127139
{11DAA9C8-F593-4B97-95DC-25341AC22E98} = {6620FD4B-0154-46A5-A929-8326DB18769F}
140+
{811F62DE-C15B-4A90-887C-22F68B17EE2A} = {9BE135A3-3D75-40BD-BA92-5961167FD719}
141+
{9D21ABE1-B43C-4FD7-82D8-A4BA7AAF7991} = {6620FD4B-0154-46A5-A929-8326DB18769F}
128142
EndGlobalSection
129143
GlobalSection(ExtensibilityGlobals) = postSolution
130144
SolutionGuid = {C22E21A9-E10B-4324-BD51-350342EA8627}

docker/test/RunTests.ps1

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@ Param (
55

66
$projectPath = $PSScriptRoot
77
$pesterVersion = '5.6.1'
8-
$redisVersion = '7.4'
8+
$rabbitmqVersion = '3.13'
99

1010
$imageTag = 'local-test'
1111
if (![string]::IsNullOrEmpty($PlanningPokerImageTag)) {
1212
$imageTag = $PlanningPokerImageTag
1313
}
1414

1515
$composeProjectName = 'planningpoker'
16-
$redisAppPassword = (New-Guid).ToString()
17-
$redisAdminPassword = (New-Guid).ToString()
16+
$rabbitmqPassword = (New-Guid).ToString()
1817
$applicationPorts = @(5001, 5002, 5003)
1918

2019
function RandomizeApplicationPorts() {
@@ -31,45 +30,15 @@ function SetupEnvironmentVariables() {
3130
[Parameter(Mandatory = $true)]
3231
[int[]] $ApplicationPorts,
3332
[Parameter(Mandatory = $true)]
34-
[string] $AppPassword
33+
[string] $RabbitMQPassword
3534
)
3635

3736
$env:PLANNINGPOKER_IMAGENAME = 'duracellko/planningpoker:' + $AppImageTag
3837
$env:PLANNINGPOKER_APP1_PORT = $ApplicationPorts[0]
3938
$env:PLANNINGPOKER_APP2_PORT = $ApplicationPorts[1]
4039
$env:PLANNINGPOKER_APP3_PORT = $ApplicationPorts[2]
41-
$env:PLANNINGPOKER_APP_REDIS_PASSWORD = $AppPassword
42-
$env:PLANNINGPOKER_REDIS_VERSION = $redisVersion
43-
}
44-
45-
function PrepareRedisConfiguration() {
46-
param (
47-
[Parameter(Mandatory = $true)]
48-
[string] $AppPassword,
49-
[Parameter(Mandatory = $true)]
50-
[string] $AdminPassword
51-
)
52-
53-
$configurationPath = Join-Path -Path $projectPath -ChildPath 'redis.conf'
54-
$configuration = Get-Content -Path $configurationPath -Raw
55-
$configuration = $configuration.Replace('${PLANNINGPOKER_ADMIN_PASSWORD}', $AdminPassword)
56-
$configuration = $configuration.Replace('${PLANNINGPOKER_APP_PASSWORD}', $AppPassword)
57-
Set-Content -Path $configurationPath -Value $configuration -NoNewline
58-
}
59-
60-
function RevertRedisConfiguration() {
61-
param (
62-
[Parameter(Mandatory = $true)]
63-
[string] $AppPassword,
64-
[Parameter(Mandatory = $true)]
65-
[string] $AdminPassword
66-
)
67-
68-
$configurationPath = Join-Path -Path $projectPath -ChildPath 'redis.conf'
69-
$configuration = Get-Content -Path $configurationPath -Raw
70-
$configuration = $configuration.Replace($AdminPassword, '${PLANNINGPOKER_ADMIN_PASSWORD}')
71-
$configuration = $configuration.Replace($AppPassword, '${PLANNINGPOKER_APP_PASSWORD}')
72-
Set-Content -Path $configurationPath -Value $configuration -NoNewline
40+
$env:PLANNINGPOKER_APP_RABBITMQ_PASSWORD = $RabbitMQPassword
41+
$env:PLANNINGPOKER_RABBITMQ_VERSION = $rabbitmqVersion
7342
}
7443

7544
function ComposeDockerUp() {
@@ -118,8 +87,7 @@ $composeFilePath = Join-Path -Path $projectPath -ChildPath 'compose.yml'
11887

11988
try {
12089
RandomizeApplicationPorts
121-
SetupEnvironmentVariables -AppImageTag $imageTag -ApplicationPorts $applicationPorts -AppPassword $redisAppPassword
122-
PrepareRedisConfiguration -AppPassword $redisAppPassword -AdminPassword $redisAdminPassword
90+
SetupEnvironmentVariables -AppImageTag $imageTag -ApplicationPorts $applicationPorts -RabbitMQPassword $rabbitmqPassword
12391

12492
ComposeDockerUp -ComposePath $composeFilePath -ProjectName $composeProjectName
12593

@@ -157,6 +125,5 @@ try {
157125
}
158126
}
159127
finally {
160-
RevertRedisConfiguration -AppPassword $redisAppPassword -AdminPassword $redisAdminPassword
161128
ComposeDockerDown -ComposePath $composeFilePath -ProjectName $composeProjectName
162129
}

docker/test/compose.yml

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ services:
22
planningpoker-r1:
33
image: ${PLANNINGPOKER_IMAGENAME:-duracellko/planningpoker:local-test}
44
depends_on:
5-
- redis
5+
rabbitmq:
6+
condition: service_healthy
67
environment:
7-
PlanningPoker__ServiceBusConnectionString: "REDIS:redis,user=planningpoker,password=${PLANNINGPOKER_APP_REDIS_PASSWORD}"
8+
PlanningPoker__ServiceBusConnectionString: "RABBITMQ:amqp://planningpoker:${PLANNINGPOKER_APP_RABBITMQ_PASSWORD}@rabbitmq/"
89
PlanningPoker__InitializationMessageTimeout: 3
910
PlanningPokerClient__UseHttpClient: true
1011
ports:
@@ -13,9 +14,10 @@ services:
1314
planningpoker-r2:
1415
image: ${PLANNINGPOKER_IMAGENAME:-duracellko/planningpoker:local-test}
1516
depends_on:
16-
- redis
17+
rabbitmq:
18+
condition: service_healthy
1719
environment:
18-
PlanningPoker__ServiceBusConnectionString: "REDIS:redis,user=planningpoker,password=${PLANNINGPOKER_APP_REDIS_PASSWORD}"
20+
PlanningPoker__ServiceBusConnectionString: "RABBITMQ:amqp://planningpoker:${PLANNINGPOKER_APP_RABBITMQ_PASSWORD}@rabbitmq/"
1921
PlanningPoker__InitializationMessageTimeout: 3
2022
PlanningPokerClient__UseHttpClient: true
2123
ports:
@@ -24,19 +26,24 @@ services:
2426
planningpoker-r3:
2527
image: ${PLANNINGPOKER_IMAGENAME:-duracellko/planningpoker:local-test}
2628
depends_on:
27-
- redis
29+
rabbitmq:
30+
condition: service_healthy
2831
environment:
29-
PlanningPoker__ServiceBusConnectionString: "REDIS:redis,user=planningpoker,password=${PLANNINGPOKER_APP_REDIS_PASSWORD}"
32+
PlanningPoker__ServiceBusConnectionString: "RABBITMQ:amqp://planningpoker:${PLANNINGPOKER_APP_RABBITMQ_PASSWORD}@rabbitmq/"
3033
PlanningPoker__InitializationMessageTimeout: 3
3134
PlanningPokerClient__UseHttpClient: true
3235
ports:
3336
- "${PLANNINGPOKER_APP3_PORT:-5003}:8080"
3437

35-
redis:
36-
image: redis:${PLANNINGPOKER_REDIS_VERSION:-latest}
37-
volumes:
38-
- type: bind
39-
source: ./redis.conf
40-
target: /usr/local/etc/redis/redis.conf
41-
read_only: true
42-
command: [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
38+
rabbitmq:
39+
image: rabbitmq:${PLANNINGPOKER_RABBITMQ_VERSION:-latest}
40+
environment:
41+
RABBITMQ_DEFAULT_USER: planningpoker
42+
RABBITMQ_DEFAULT_PASS: ${PLANNINGPOKER_APP_RABBITMQ_PASSWORD}
43+
healthcheck:
44+
test: "rabbitmq-diagnostics -q check_running && rabbitmq-diagnostics -q check_local_alarms && rabbitmq-diagnostics -q check_port_listener 5672"
45+
interval: 30s
46+
timeout: 10s
47+
retries: 3
48+
start_period: 20s
49+
start_interval: 2s

docker/test/redis.conf

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<PropertyGroup Condition="'$(Configuration)'=='Release'">
8+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="RabbitMQ.Client" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\Duracellko.PlanningPoker.Azure\Duracellko.PlanningPoker.Azure.csproj" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<Compile Update="Resources.Designer.cs">
21+
<DesignTime>True</DesignTime>
22+
<AutoGen>True</AutoGen>
23+
<DependentUpon>Resources.resx</DependentUpon>
24+
</Compile>
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<EmbeddedResource Update="Resources.resx">
29+
<Generator>ResXFileCodeGenerator</Generator>
30+
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
31+
</EmbeddedResource>
32+
</ItemGroup>
33+
34+
</Project>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Duracellko.PlanningPoker.Azure;
4+
5+
namespace Duracellko.PlanningPoker.RabbitMQ;
6+
7+
/// <summary>
8+
/// When implemented, then object is able to convert messages of type <see cref="T:NodeMessage"/> to RabbitMQ message and vice versa.
9+
/// </summary>
10+
public interface IMessageConverter
11+
{
12+
/// <summary>
13+
/// Gets headers of RabbitMQ message converted from <see cref="T:NodeMessage"/>.
14+
/// </summary>
15+
/// <param name="message">The message to convert.</param>
16+
/// <returns>Headers of the message.</returns>
17+
IDictionary<string, object> GetMessageHeaders(NodeMessage message);
18+
19+
/// <summary>
20+
/// Gets body of RabbitMQ message converted from <see cref="T:NodeMessage"/>.
21+
/// </summary>
22+
/// <param name="message">The message to convert.</param>
23+
/// <returns>Body of the message.</returns>
24+
ReadOnlyMemory<byte> GetMessageBody(NodeMessage message);
25+
26+
/// <summary>
27+
/// Converts RabbitMQ message headers and body to <see cref="T:NodeMessage"/> object.
28+
/// </summary>
29+
/// <param name="headers">Headers of the message to convert.</param>
30+
/// <param name="body">Body of the message to convert.</param>
31+
/// <returns>Converted message of NodeMessage type.</returns>
32+
NodeMessage GetNodeMessage(IDictionary<string, object> headers, ReadOnlyMemory<byte> body);
33+
34+
/// <summary>
35+
/// Gets decoded value of Rabbit MQ message header with specified key.
36+
/// </summary>
37+
/// <param name="headers">The collection of header key-value pairs.</param>
38+
/// <param name="key">The key to get header value for.</param>
39+
/// <returns>Value header with specified key.</returns>
40+
string? GetHeader(IDictionary<string, object> headers, string key);
41+
}

0 commit comments

Comments
 (0)