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
1 change: 1 addition & 0 deletions .github/workflows/sdk_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ jobs:
name: ${{ matrix.prefix }}-${{ matrix['dapr-runtime-versions'].version }}-${{ matrix.projectName }}
needs: [ compute-integration-matrix ]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.compute-integration-matrix.outputs.matrix) }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
// ------------------------------------------------------------------------

using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Dapr.Testcontainers.Common;
using Dapr.Testcontainers.Common.Options;
using Docker.DotNet.Models;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using DotNet.Testcontainers.Networks;

Expand Down Expand Up @@ -44,9 +47,13 @@ public sealed class DaprPlacementContainer : IAsyncStartable
/// </summary>
public int ExternalPort { get; private set; }
/// <summary>
/// THe contains' internal port.
/// The container's internal port.
/// </summary>
public const int InternalPort = 50006;
/// <summary>
/// The container's internal health port.
/// </summary>
private const int HealthPort = 8080;

/// <summary>
/// Initializes a new instance of the <see cref="DaprPlacementContainer"/>.
Expand All @@ -59,14 +66,24 @@ public DaprPlacementContainer(DaprRuntimeOptions options, INetwork network, stri
_logAttachment = ContainerLogAttachment.TryCreate(logDirectory, "placement", _containerName);

//Placement service runs via port 50006
var containerBuilder = new ContainerBuilder()
.WithImage(options.PlacementImageTag)
.WithName(_containerName)
var containerBuilder = new ContainerBuilder()
.WithImage(options.PlacementImageTag)
.WithName(_containerName)
.WithNetwork(network)
.WithCommand("./placement", "-port", InternalPort.ToString())
.WithPortBinding(InternalPort, assignRandomHostPort: true)
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("placement server leadership acquired"))
;
.WithCommand("./placement", "-port", InternalPort.ToString())
.WithPortBinding(InternalPort, assignRandomHostPort: true)
.WithPortBinding(HealthPort, assignRandomHostPort: true)
.WithWaitStrategy(Wait.ForUnixContainer()
.UntilHttpRequestIsSucceeded(endpoint =>
endpoint
.ForPort(HealthPort)
.ForPath("/healthz")
.ForStatusCodeMatching(code => (int)code >= 200 && (int)code < 300),
mod =>
mod
.WithTimeout(TimeSpan.FromMinutes(2))
.WithInterval(TimeSpan.FromSeconds(5))
.WithMode(WaitStrategyMode.Running)));

if (_logAttachment is not null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

using System;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Dapr.Testcontainers.Common;
Expand Down Expand Up @@ -52,6 +54,10 @@ public sealed class DaprSchedulerContainer : IAsyncStartable
/// The container's internal port.
/// </summary>
public const int InternalPort = 51005;
/// <summary>
/// The container's internal health port.
/// </summary>
private const int HealthPort = 8080;

/// <summary>
/// Creates a new instance of a <see cref="DaprSchedulerContainer"/>.
Expand All @@ -70,17 +76,27 @@ public DaprSchedulerContainer(DaprRuntimeOptions options, INetwork network, stri
];

_testDirectory = TestDirectoryManager.CreateTestDirectory("scheduler");

var containerBuilder = new ContainerBuilder()
.WithImage(options.SchedulerImageTag)
.WithName(_containerName)
.WithName(_containerName)
.WithNetwork(network)
.WithCommand(cmd.ToArray())
.WithPortBinding(InternalPort, assignRandomHostPort: true)
.WithPortBinding(InternalPort, assignRandomHostPort: true)
.WithPortBinding(HealthPort, assignRandomHostPort: true) // Allows probes to reach healthz
// Mount an anonymous volume to /data to ensure the scheduler has write permissions
.WithBindMount(_testDirectory, containerDataDir, AccessMode.ReadWrite)
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("api is ready"))
;
.WithWaitStrategy(Wait.ForUnixContainer()
.UntilHttpRequestIsSucceeded(endpoint =>
endpoint
.ForPort(HealthPort)
.ForPath("/healthz")
.ForStatusCodeMatching(code => (int)code >= 200 && (int)code < 300),
mod =>
mod
.WithTimeout(TimeSpan.FromMinutes(2))
.WithInterval(TimeSpan.FromSeconds(5))
.WithMode(WaitStrategyMode.Running)));

if (_logAttachment is not null)
{
Expand Down
81 changes: 50 additions & 31 deletions src/Dapr.Testcontainers/Containers/Dapr/DaprdContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -33,9 +34,10 @@ public sealed class DaprdContainer : IAsyncStartable
{
private const int InternalHttpPort = 3500;
private const int InternalGrpcPort = 50001;
private const int InternalHealthPort = 8080;
private readonly IContainer _container;
private readonly ContainerLogAttachment? _logAttachment;
private string _containerName = $"dapr-{Guid.NewGuid():N}";
private readonly string _containerName = $"dapr-{Guid.NewGuid():N}";

/// <summary>
/// The internal network alias/name of the container.
Expand Down Expand Up @@ -123,57 +125,74 @@ public DaprdContainer(
cmd.Add("-scheduler-host-address");
cmd.Add("");
}
var containerBuilder = new ContainerBuilder()
.WithImage(options.RuntimeImageTag)
.WithName(_containerName)

var containerBuilder = new ContainerBuilder()
.WithImage(options.RuntimeImageTag)
.WithName(_containerName)
.WithLogger(ConsoleLogger.Instance)
.WithCommand(cmd.ToArray())
.WithCommand(cmd.ToArray())
.WithNetwork(network)
.WithExtraHost(ContainerHostAlias, "host-gateway")
.WithBindMount(componentsHostFolder, componentsPath, AccessMode.ReadOnly)
.WithWaitStrategy(Wait.ForUnixContainer()
.WithBindMount(componentsHostFolder, componentsPath, AccessMode.ReadOnly)
.WithWaitStrategy(Wait.ForUnixContainer()
.UntilMessageIsLogged("Internal gRPC server is running"));
//.UntilMessageIsLogged(@"^dapr initialized. Status: Running. Init Elapsed "))
// .UntilHttpRequestIsSucceeded(endpoint =>
// endpoint
// .ForPort(InternalHttpPort)
// .ForPath("/healthz")
// .ForStatusCodeMatching(code => (int)code >= 200 && (int)code < 300),
// mod =>
// mod
// .WithTimeout(TimeSpan.FromMinutes(2))
// .WithInterval(TimeSpan.FromSeconds(5))
// .WithMode(WaitStrategyMode.Running)));

if (_logAttachment is not null)
{
containerBuilder = containerBuilder.WithOutputConsumer(_logAttachment.OutputConsumer);
}

containerBuilder = daprHttpPort is not null ? containerBuilder.WithPortBinding(containerPort: InternalHttpPort, hostPort: daprHttpPort.Value) : containerBuilder.WithPortBinding(port: InternalHttpPort, assignRandomHostPort: true);
containerBuilder = daprGrpcPort is not null ? containerBuilder.WithPortBinding(containerPort: InternalGrpcPort, hostPort: daprGrpcPort.Value) : containerBuilder.WithPortBinding(port: InternalGrpcPort, assignRandomHostPort: true);
containerBuilder = daprHttpPort is not null ? containerBuilder.WithPortBinding(containerPort: InternalHttpPort, hostPort: daprHttpPort.Value) : containerBuilder.WithPortBinding(port: InternalHttpPort, assignRandomHostPort: true);
containerBuilder = daprGrpcPort is not null ? containerBuilder.WithPortBinding(containerPort: InternalGrpcPort, hostPort: daprGrpcPort.Value) : containerBuilder.WithPortBinding(port: InternalGrpcPort, assignRandomHostPort: true);

_container = containerBuilder.Build();
_container = containerBuilder.Build();
}

/// <inheritdoc />
public async Task StartAsync(CancellationToken cancellationToken = default)
{
await _container.StartAsync(cancellationToken);
try
{
await _container.StartAsync(cancellationToken);

var mappedHttpPort = _container.GetMappedPublicPort(InternalHttpPort);
var mappedGrpcPort = _container.GetMappedPublicPort(InternalGrpcPort);
var mappedHttpPort = _container.GetMappedPublicPort(InternalHttpPort);
var mappedGrpcPort = _container.GetMappedPublicPort(InternalGrpcPort);

if (_requestedHttpPort is not null && mappedHttpPort != _requestedHttpPort.Value)
{
throw new InvalidOperationException(
$"Dapr HTTP port mapping mismatch. Requested {_requestedHttpPort.Value}, but Docker mapped {mappedHttpPort}");
}
if (_requestedHttpPort is not null && mappedHttpPort != _requestedHttpPort.Value)
{
throw new InvalidOperationException(
$"Dapr HTTP port mapping mismatch. Requested {_requestedHttpPort.Value}, but Docker mapped {mappedHttpPort}");
}

if (_requestedGrpcPort is not null && mappedGrpcPort != _requestedGrpcPort.Value)
{
throw new InvalidOperationException(
$"Dapr gRPC port mapping mismatch. Requested {_requestedGrpcPort.Value}, but Docker mapped {mappedGrpcPort}");
}
if (_requestedGrpcPort is not null && mappedGrpcPort != _requestedGrpcPort.Value)
{
throw new InvalidOperationException(
$"Dapr gRPC port mapping mismatch. Requested {_requestedGrpcPort.Value}, but Docker mapped {mappedGrpcPort}");
}

HttpPort = mappedHttpPort;
GrpcPort = mappedGrpcPort;
HttpPort = mappedHttpPort;
GrpcPort = mappedGrpcPort;

// The container log wait strategy can fire before the host port is actually accepting connections
// (especially on Windows). Ensure the ports are reachable from the test process.
await WaitForTcpPortAsync("127.0.0.1", HttpPort, TimeSpan.FromSeconds(30), cancellationToken);
await WaitForTcpPortAsync("127.0.0.1", GrpcPort, TimeSpan.FromSeconds(30), cancellationToken);
// The container log wait strategy can fire before the host port is actually accepting connections
// (especially on Windows). Ensure the ports are reachable from the test process.
await WaitForTcpPortAsync("127.0.0.1", HttpPort, TimeSpan.FromSeconds(30), cancellationToken);
await WaitForTcpPortAsync("127.0.0.1", GrpcPort, TimeSpan.FromSeconds(30), cancellationToken);
}
catch (Exception ex)
{
var msg = ex.Message;
throw;
}
}

private static async Task WaitForTcpPortAsync(
Expand Down
2 changes: 1 addition & 1 deletion src/Dapr.Testcontainers/Harnesses/BaseHarness.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ DaprSchedulerExternalPort is null || DaprSchedulerAlias is null
await _daprd!.StartAsync(cancellationToken);
_sidecarPortsReady.TrySetResult();
}, cancellationToken);

Task? appTask = null;
if (startApp is not null)
{
Expand Down
Loading