Skip to content
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

feat: Client tests using Example app #50

Merged
merged 13 commits into from
Dec 19, 2024
36 changes: 1 addition & 35 deletions .github/workflows/ci-dotnet-runtests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,41 +86,6 @@ jobs:
$matrixBuilds = '${{steps.set-matrix.outputs.matrix_builds}}' | ConvertFrom-Json | ConvertTo-Json
Write-Host $matrixBuilds

# build_tests_in_project:
# name: Build ${{ matrix.project.name }}
# runs-on: ubuntu-24.04 # Build on pinned version of ubuntu
# needs: build_matrix
# strategy:
# fail-fast: false
# matrix:
# project: ${{fromJson(needs.build_matrix.outputs.matrix_builds)}}
# env:
# OUTPUT_PATH: ${{ github.workspace }}/source/${{ matrix.project.name}}/bin/Release/${{matrix.project.dotnet_version}}
# steps:
# - name: Checkout repository
# uses: actions/checkout@v4

# - uses: actions/cache@v4
# with:
# path: ~/.nuget/packages
# key: ${{ inputs.nuget_cache_key_prefix }}-${{ runner.os }}-${{ hashFiles('**/*.csproj') }}

# - name: Build ${{ matrix.project.name }}
# run: |
# dotnet publish \
# '${{ matrix.project.filepath }}' \
# --configuration Release \
# --output '${{ env.OUTPUT_PATH }}' \
# -p:ErrorOnDuplicatePublishOutputFiles=false # To avoid the error "Found multiple publish output files with the same relative path"

# # ls ${{ env.OUTPUT_PATH}}

# - uses: actions/upload-artifact@v4
# with:
# retention-days: 2
# name: pm-tests-${{ matrix.project.name }}-${{ github.event.pull_request.number }}
# path: ${{ env.OUTPUT_PATH }}/*

integration_tests:
if: ${{ needs.build_matrix.outputs.matrix_builds != '[]' }}
needs: [
Expand All @@ -140,6 +105,7 @@ jobs:
run_integration_tests: true
tests_filter_expression: empty # Means skip.
use_azure_functions_tools: true
azure_functions_core_tools_version: 4.0.5455
aspnetcore_test_contentroot_variable_name: empty
aspnetcore_test_contentroot_variable_value: empty
solution_file_path: source\ProcessManager.sln
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<Compile Include="..\ProcessManager.Core.Tests\Fixtures\ProcessManagerDatabaseManager.cs" Link="Fixtures\ProcessManagerDatabaseManager.cs" />
<Compile Include="..\ProcessManager.Tests\Fixtures\ProcessManagerAppManager.cs" Link="Fixtures\ProcessManagerAppManager.cs" />
</ItemGroup>

<ItemGroup>
Expand All @@ -27,6 +28,7 @@
<ItemGroup>
<ProjectReference Include="..\ProcessManager.DatabaseMigration\ProcessManager.DatabaseMigration.csproj" />
<ProjectReference Include="..\Example.Orchestrations\Example.Orchestrations.csproj" />
<ProjectReference Include="..\ProcessManager\ProcessManager.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,83 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using Energinet.DataHub.Core.FunctionApp.TestCommon.Azurite;
using Energinet.DataHub.Core.FunctionApp.TestCommon.Configuration;
using Energinet.DataHub.ProcessManager.Core.Tests.Fixtures;
using Energinet.DataHub.ProcessManager.Tests.Fixtures;
using Xunit.Abstractions;

namespace Energinet.DataHub.Example.Orchestrations.Tests.Fixtures;

/// <summary>
/// Support testing Process Manager Orchestrations app using default fixture configuration.
/// Support testing the interactions with Example.Orchestrations and
/// Process Manager Api, by coordinating the startup of the dependent applications
/// Example.Orchestrations and ProcessManager (Api).
/// </summary>
public class ExampleOrchestrationsAppFixture
: IAsyncLifetime
public class ExampleOrchestrationsAppFixture : IAsyncLifetime
{
private const string TaskHubName = "ExampleOrchestrationsAppTest01";

public ExampleOrchestrationsAppFixture()
{
ExampleOrchestrationsAppManager = new ExampleOrchestrationsAppManager();
DatabaseManager = new ProcessManagerDatabaseManager("ExampleOrchestrationsAppTests");
AzuriteManager = new AzuriteManager(useOAuth: true);

IntegrationTestConfiguration = new IntegrationTestConfiguration();

ExampleOrchestrationsAppManager = new ExampleOrchestrationsAppManager(
DatabaseManager,
IntegrationTestConfiguration,
AzuriteManager,
taskHubName: TaskHubName,
appPort: 8113,
manageDatabase: false,
manageAzurite: false);

ProcessManagerAppManager = new ProcessManagerAppManager(
DatabaseManager,
IntegrationTestConfiguration,
AzuriteManager,
taskHubName: TaskHubName,
appPort: 8114,
manageDatabase: false,
manageAzurite: false);
}

public IntegrationTestConfiguration IntegrationTestConfiguration { get; }

public ExampleOrchestrationsAppManager ExampleOrchestrationsAppManager { get; }

public ProcessManagerAppManager ProcessManagerAppManager { get; }

private ProcessManagerDatabaseManager DatabaseManager { get; }

private AzuriteManager AzuriteManager { get; }

public async Task InitializeAsync()
{
AzuriteManager.CleanupAzuriteStorage();
AzuriteManager.StartAzurite();

await DatabaseManager.CreateDatabaseAsync();

await ExampleOrchestrationsAppManager.StartAsync();
await ProcessManagerAppManager.StartAsync();
}

public async Task DisposeAsync()
{
await ExampleOrchestrationsAppManager.DisposeAsync();
await ProcessManagerAppManager.DisposeAsync();

await DatabaseManager.DeleteDatabaseAsync();

AzuriteManager.Dispose();
}

public void SetTestOutputHelper(ITestOutputHelper? testOutputHelper)
{
ExampleOrchestrationsAppManager.SetTestOutputHelper(testOutputHelper);
ProcessManagerAppManager.SetTestOutputHelper(testOutputHelper);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Energinet.DataHub.Core.DurableFunctionApp.TestCommon.DurableTask;
using Energinet.DataHub.Core.FunctionApp.TestCommon.Azurite;
using Energinet.DataHub.Core.FunctionApp.TestCommon.Configuration;
using Energinet.DataHub.Core.FunctionApp.TestCommon.FunctionAppHost;
using Energinet.DataHub.Core.TestCommon.Diagnostics;
using Energinet.DataHub.ProcessManagement.Core.Infrastructure.Extensions.Options;
using Energinet.DataHub.ProcessManager.Core.Tests.Fixtures;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Xunit.Abstractions;

namespace Energinet.DataHub.Example.Orchestrations.Tests.Fixtures;
Expand Down Expand Up @@ -75,10 +73,6 @@ public ExampleOrchestrationsAppManager(

IntegrationTestConfiguration = configuration;
AzuriteManager = azuriteManager;

DurableTaskManager = new DurableTaskManager(
nameof(ProcessManagerTaskHubOptions.ProcessManagerStorageConnectionString),
AzuriteManager.FullConnectionString);
}

public ProcessManagerDatabaseManager DatabaseManager { get; }
Expand All @@ -88,26 +82,18 @@ public ExampleOrchestrationsAppManager(
[NotNull]
public FunctionAppHostManager? AppHostManager { get; private set; }

[NotNull]
public IDurableClient? DurableClient { get; private set; }

private IntegrationTestConfiguration IntegrationTestConfiguration { get; }

private AzuriteManager AzuriteManager { get; }

private DurableTaskManager DurableTaskManager { get; }

/// <summary>
/// Start the example orchestration app
/// </summary>
public async Task StartAsync()
{
if (_manageAzurite)
{
// Clean up old Azurite storage
CleanupAzuriteStorage();

// Storage emulator
AzuriteManager.CleanupAzuriteStorage();
AzuriteManager.StartAzurite();
}

Expand All @@ -119,16 +105,12 @@ public async Task StartAsync()

// Create and start host
AppHostManager = new FunctionAppHostManager(appHostSettings, TestLogger);

StartHost(AppHostManager);

DurableClient = DurableTaskManager.CreateClient(taskHubName: _taskHubName);
}

public async ValueTask DisposeAsync()
{
AppHostManager.Dispose();
await DurableTaskManager.DisposeAsync();

if (_manageAzurite)
AzuriteManager.Dispose();
Expand All @@ -150,16 +132,6 @@ public void SetTestOutputHelper(ITestOutputHelper? testOutputHelper)
TestLogger.TestOutputHelper = testOutputHelper;
}

/// <summary>
/// Cleanup Azurite storage to avoid situations where Durable Functions
/// would otherwise continue working on old orchestrations that e.g. failed in
/// previous runs.
/// </summary>
public void CleanupAzuriteStorage()
{
AzuriteManager.CleanupAzuriteStorage();
}

private static void StartHost(FunctionAppHostManager hostManager)
{
IEnumerable<string> hostStartupLog;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright 2020 Energinet DataHub A/S
//
// Licensed under the Apache License, Version 2.0 (the "License2");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using Energinet.DataHub.Core.TestCommon;
using Energinet.DataHub.Example.Orchestrations.Abstractions.Processes.BRS_X01.Example.V1.Model;
using Energinet.DataHub.Example.Orchestrations.Tests.Fixtures;
using Energinet.DataHub.ProcessManager.Abstractions.Api.Model;
using Energinet.DataHub.ProcessManager.Abstractions.Api.Model.OrchestrationInstance;
using FluentAssertions;
using Xunit.Abstractions;

namespace Energinet.DataHub.ProcessManager.Tests.Integration.Processes;

/// <summary>
/// Test case where we verify the Example.Orchestrations and Process Manager Api
/// can be used to start an example orchestration (with input parameter) and
/// monitor its status during its lifetime.
/// </summary>
[Collection(nameof(ExampleOrchestrationsAppCollection))]
public class MonitorExampleUsingApiScenario : IAsyncLifetime
{
public MonitorExampleUsingApiScenario(
ExampleOrchestrationsAppFixture fixture,
ITestOutputHelper testOutputHelper)
{
Fixture = fixture;
Fixture.SetTestOutputHelper(testOutputHelper);
}

private ExampleOrchestrationsAppFixture Fixture { get; }

public Task InitializeAsync()
{
Fixture.ProcessManagerAppManager.AppHostManager.ClearHostLog();
Fixture.ExampleOrchestrationsAppManager.AppHostManager.ClearHostLog();

return Task.CompletedTask;
}

public Task DisposeAsync()
{
Fixture.ProcessManagerAppManager.SetTestOutputHelper(null!);
Fixture.ExampleOrchestrationsAppManager.SetTestOutputHelper(null!);

return Task.CompletedTask;
}

[Fact]
public async Task ExampleOrchestration_WhenStarted_CanMonitorLifecycle()
{
var orchestration = new Brs_X01_Example_V1();
var input = new InputV1(false);

var command = new StartExampleCommandV1(
operatingIdentity: new UserIdentityDto(
Guid.NewGuid(),
Guid.NewGuid()),
input);

using var scheduleRequest = new HttpRequestMessage(
HttpMethod.Post,
$"/api/orchestrationinstance/command/start/custom/{orchestration.Name}/{orchestration.Version}");
scheduleRequest.Content = new StringContent(
JsonSerializer.Serialize(command),
Encoding.UTF8,
"application/json");

// Step 1: Start new example orchestration instance
using var response = await Fixture.ExampleOrchestrationsAppManager.AppHostManager
.HttpClient
.SendAsync(scheduleRequest);
response.EnsureSuccessStatusCode();

var calculationId = await response.Content
.ReadFromJsonAsync<Guid>();

// Step 2: Query until terminated with succeeded
var getRequest = new GetOrchestrationInstanceByIdQuery(
new UserIdentityDto(
Guid.NewGuid(),
Guid.NewGuid()),
calculationId);

var isTerminated = await Awaiter.TryWaitUntilConditionAsync(
async () =>
{
using var queryRequest = new HttpRequestMessage(
HttpMethod.Post,
"/api/orchestrationinstance/query/id");
queryRequest.Content = new StringContent(
JsonSerializer.Serialize(getRequest),
Encoding.UTF8,
"application/json");

using var queryResponse = await Fixture.ProcessManagerAppManager.AppHostManager
.HttpClient
.SendAsync(queryRequest);
queryResponse.EnsureSuccessStatusCode();

var orchestrationInstance = await queryResponse.Content
.ReadFromJsonAsync<OrchestrationInstanceDto>();

return orchestrationInstance!.Lifecycle.State == OrchestrationInstanceLifecycleStates.Terminated;
dstenroejl marked this conversation as resolved.
Show resolved Hide resolved
},
timeLimit: TimeSpan.FromSeconds(40),
delay: TimeSpan.FromSeconds(2));

isTerminated.Should().BeTrue("because we expects the orchestration instance can complete within given wait time");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2020 Energinet DataHub A/S
//
// Licensed under the Apache License, Version 2.0 (the "License2");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO: Delete when we have moved tests depending on "ObsoleteProcessManagerClientCollection"

// xUnit documentation:
// * https://xunit.net/docs/running-tests-in-parallel.html
// This is required because our fixtures cannot be executed in parallel.
[assembly: CollectionBehavior(DisableTestParallelization = true)]
Loading
Loading