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
17 changes: 16 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,21 @@ jobs:
run: dotnet test package/AgentWindowsManaged.Tests/DevolutionsAgent.Installer.Tests.csproj
shell: pwsh

gateway-installer-tests:
name: Gateway installer tests
runs-on: windows-2022
needs: [preflight]

steps:
- name: Checkout ${{ github.repository }}
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.ref }}

- name: Tests
run: dotnet test package/WindowsManaged.UnitTests/DevolutionsGateway.Installer.Tests.csproj
shell: pwsh

winapi-sanitizer-tests:
name: Windows API sanitizer tests
runs-on: windows-2022
Expand Down Expand Up @@ -1655,7 +1670,7 @@ jobs:
success:
name: Success
if: ${{ always() }}
needs: [tests, agent-tunnel-e2e, agent-policy-e2e, lints, oracle-markers, oracle-markers-tests, skill-links, check-dependencies, jetsocat-lipo, devolutions-gateway-powershell, gateway-service-account-tests, devolutions-gateway, devolutions-gateway-merge, devolutions-pedm-desktop, devolutions-agent, devolutions-agent-merge, devolutions-pedm-client, dotnet-utils-tests, agent-identity-vectors, agent-installer-event-log-tests, winapi-sanitizer-tests, winapi-miri, pedm-simulator, secure-memory-verifier]
needs: [tests, agent-tunnel-e2e, agent-policy-e2e, lints, oracle-markers, oracle-markers-tests, skill-links, check-dependencies, jetsocat-lipo, devolutions-gateway-powershell, gateway-service-account-tests, devolutions-gateway, devolutions-gateway-merge, devolutions-pedm-desktop, devolutions-agent, devolutions-agent-merge, devolutions-pedm-client, dotnet-utils-tests, agent-identity-vectors, agent-installer-event-log-tests, gateway-installer-tests, winapi-sanitizer-tests, winapi-miri, pedm-simulator, secure-memory-verifier]
runs-on: ubuntu-latest

steps:
Expand Down
504 changes: 504 additions & 0 deletions package/WindowsManaged.UnitTests/DataFolderTests.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net471</TargetFramework>
<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>
<AssemblyName>DevolutionsGateway.Installer.Tests</AssemblyName>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\WindowsManaged\DevolutionsGateway.csproj" Targets="CoreBuild;GetTargetPath" />
</ItemGroup>
</Project>
82 changes: 82 additions & 0 deletions package/WindowsManaged.UnitTests/InstallerSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.IO;
using System.Linq;

using DevolutionsGateway.Actions;

using Microsoft.Deployment.WindowsInstaller;

using WixSharp;

using Xunit;

using MsiInstaller = Microsoft.Deployment.WindowsInstaller.Installer;

namespace DevolutionsGateway.Installer.Tests;

/// <summary>
/// The installer's actions, and Windows Installer sessions to evaluate them in.
/// </summary>
internal static class InstallerSession
{
/// <summary>
/// The test collection of every test class that opens a session.
/// </summary>
/// <remarks>
/// Windows Installer opens one package at a time in a process, and xUnit runs the tests of one collection one at a
/// time.
/// </remarks>
public const string Collection = "Windows Installer session";

/// <summary>
/// The installer's action that runs the custom action <paramref name="methodName"/>.
/// </summary>
public static ManagedAction ActionOf(string methodName) =>
Assert.Single(GatewayActions.Actions.OfType<ManagedAction>(), a => a.MethodName == methodName);

/// <summary>
/// Evaluates <paramref name="condition"/> with the Windows Installer engine, in a session where
/// <paramref name="properties"/> (<c>NAME=value</c>) are set.
/// </summary>
public static bool EvaluateCondition(string condition, string[] properties) =>
WithSession(properties, session => session.EvaluateCondition(condition));

public static T WithSession<T>(string[] properties, Func<Session, T> action) =>
WithSession(AppContext.BaseDirectory, properties, action);

/// <summary>
/// Runs <paramref name="action"/> in a Windows Installer session of an empty package in <paramref name="folder"/>
/// where <paramref name="properties"/> (<c>NAME=value</c>) are set.
/// </summary>
public static T WithSession<T>(string folder, string[] properties, Func<Session, T> action)
{
string path = Path.Combine(folder, $"session-{Guid.NewGuid():N}.msi");

try
{
using (Database database = new(path, DatabaseOpenMode.CreateDirect))
{
database.Execute("CREATE TABLE `Property` (`Property` CHAR(72) NOT NULL, `Value` CHAR(0) NOT NULL LOCALIZABLE PRIMARY KEY `Property`)");
database.Execute($"INSERT INTO `Property` (`Property`, `Value`) VALUES ('ProductCode', '{Guid.NewGuid():B}')");
database.SummaryInfo.Template = "x64;1033";
database.SummaryInfo.RevisionNumber = Guid.NewGuid().ToString("B");
database.SummaryInfo.PageCount = 500;
database.Commit();
}

using Session session = MsiInstaller.OpenPackage(path, ignoreMachineState: true);

foreach (string property in properties)
{
string[] parts = property.Split(['='], 2);
session[parts[0]] = parts[1];
}

return action(session);
}
finally
{
System.IO.File.Delete(path);
}
}
}
15 changes: 15 additions & 0 deletions package/WindowsManaged.UnitTests/OutputLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using DevolutionsGateway.Actions;

using Xunit.Abstractions;

namespace DevolutionsGateway.Installer.Tests;

/// <summary>
/// Writes the log of the code under test to the test's output.
/// </summary>
internal sealed class OutputLogger(ITestOutputHelper output) : ILogger
{
public void Log(string msg) => output.WriteLine(msg);

public void Log(string format, params object[] args) => output.WriteLine(format, args);
}
Loading
Loading