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

Chore(tests) Run E2E tests on Docker images #1339

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
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
11 changes: 10 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
{
"appPort": [2525, 8080],
"extensions": ["ms-vscode.csharp", "formulahendry.dotnet-test-explorer", "msjsdiag.debugger-for-chrome", "ms-azuretools.vscode-docker", "dbaeumer.vscode-eslint", "octref.vetur", "ms-azure-devops.azure-pipelines"]
"extensions": [
"ms-vscode.csharp",
"formulahendry.dotnet-test-explorer",
"msjsdiag.debugger-for-chrome",
"ms-azuretools.vscode-docker",
"dbaeumer.vscode-eslint",
"octref.vetur",
"ms-azure-devops.azure-pipelines",
"ms-dotnettools.csdevkit"
]
}
4 changes: 3 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [{
"configurations": [

{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
<PackageReference Include="FlaUI.Core" Version="4.0.0" />
<PackageReference Include="FlaUI.UIA3" Version="4.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />



<PackageReference Include="NUnit" Version="4.1.0" />

<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
Expand Down
105 changes: 85 additions & 20 deletions Rnwood.Smtp4dev.Tests/E2E/E2ETests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Medallion.Shell;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Containers;
using Medallion.Shell;
using System;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -35,6 +37,7 @@ public class E2ETestContext
public int SmtpPortNumber { get; set; }

public int ImapPortNumber { get; set; }
public string Hostname { get; internal set; }
}


Expand Down Expand Up @@ -84,40 +87,60 @@ protected void RunE2ETest(Action<E2ETestContext> test, E2ETestOptions options =
"--tlsmode=StartTls"
}.Where(a => a != ""));

if (!args.Any(a => a.StartsWith("--urls")))
if (!binary.StartsWith("docker:"))
{
args.Add("--urls=http://*:0");
}
if (!args.Any(a => a.StartsWith("--urls")))
{
args.Add("--urls=http://*:0");
}

if (!args.Any(a => a.StartsWith("--imapport")))
{
args.Add("--imapport=0");
}
if (!args.Any(a => a.StartsWith("--imapport")))
{
args.Add("--imapport=0");
}

if (!args.Any(a => a.StartsWith("--smtpport")))
{
args.Add("--smtpport=0");
}
if (!args.Any(a => a.StartsWith("--smtpport")))
{
args.Add("--smtpport=0");
}

if (!args.Any(a => a.StartsWith("--smtpport")))

if (!string.IsNullOrEmpty(options.BasePath))
{
args.Add($"--basepath={options.BasePath}");
}
}
else
{
args.Add("--smtpport=0");
if (!args.Any(a => a.StartsWith("--urls")))
{
args.Add("--urls=http://*:80");
}
}

output.WriteLine("Args: " + string.Join(" ", args.Select(a => $"\"{a}\"")));



if (!string.IsNullOrEmpty(options.BasePath))
if (binary.StartsWith("docker:"))
{
args.Add($"--basepath={options.BasePath}");
RunWithDocker(test, options, binary, args);
}
else
{
RunWithNormalBinary(test, options, workingDir, binary, args, timeout);
}
}

output.WriteLine("Args: " + string.Join(" ", args.Select(a => $"\"{a}\"")));
private void RunWithNormalBinary(Action<E2ETestContext> test, E2ETestOptions options, string workingDir, string binary, List<string> args, CancellationToken timeout)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;

using (Command serverProcess = Command.Run(binary, args,
o => o.DisposeOnExit(false).WorkingDirectory(workingDir).CancellationToken(timeout)))
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;


try
{
Expand Down Expand Up @@ -176,23 +199,65 @@ protected void RunE2ETest(Action<E2ETestContext> test, E2ETestOptions options =
test(new E2ETestContext
{
BaseUrl = baseUrl,
Hostname = "localhost",
SmtpPortNumber = smtpPortNumber.Value,
ImapPortNumber = imapPortNumber.Value
});
}
finally
{

serverProcess.TrySignalAsync(CommandSignal.ControlC).Wait();
serverProcess.StandardInput.Close();
if (!serverProcess.Process.WaitForExit(5000))
{
serverProcess.Kill();
output.WriteLine("E2E process didn't exit!");
}

cancellationTokenSource.Cancel();
}
}
}

private void RunWithDocker(Action<E2ETestContext> test, E2ETestOptions options, string binary, List<string> args)
{
string dockerImage = binary.Split(':', 2)[1];

CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

CancellationToken token = cancellationTokenSource.Token;


IContainer container = new ContainerBuilder()
.WithPortBinding(80, true)
.WithPortBinding(143, true)
.WithPortBinding(25, true)
.WithAutoRemove(true)
.WithImage(dockerImage)
.WithCommand(args.ToArray())
.WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(80))
.Build();

container.StartAsync(token).Wait();



test(new E2ETestContext
{
BaseUrl = new Uri($"http://{container.Hostname}:{container.GetMappedPublicPort(80)}{options.BasePath ?? ""}"),
Hostname = container.Hostname,
SmtpPortNumber = container.GetMappedPublicPort(25),
ImapPortNumber = container.GetMappedPublicPort(143)
});

output.WriteLine("");
output.WriteLine("Exit code: "+ container.GetExitCodeAsync().Result);
output.WriteLine(container.GetLogsAsync().Result.Stdout);
output.WriteLine(container.GetLogsAsync().Result.Stderr);



}
}
}
6 changes: 3 additions & 3 deletions Rnwood.Smtp4dev.Tests/E2E/E2ETests_Imap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ public void MessagesAvailable()
Text = "Body of end to end test"
};

smtpClient.Connect("localhost", context.SmtpPortNumber, SecureSocketOptions.StartTls, new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
smtpClient.Connect(context.Hostname, context.SmtpPortNumber, SecureSocketOptions.StartTls, new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
smtpClient.Send(message);
smtpClient.Disconnect(true, new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
}


using (ImapClient imapClient = new ImapClient())
{
imapClient.Connect("localhost", context.ImapPortNumber);
imapClient.Connect(context.Hostname, context.ImapPortNumber);
imapClient.Authenticate("user", "password");
imapClient.Inbox.Open(MailKit.FolderAccess.ReadWrite);

Expand All @@ -69,7 +69,7 @@ public void MessagesAvailable()

using (ImapClient imapClient = new ImapClient())
{
imapClient.Connect("localhost", context.ImapPortNumber);
imapClient.Connect(context.Hostname, context.ImapPortNumber);
imapClient.Authenticate("user", "password");
imapClient.Inbox.Open(MailKit.FolderAccess.ReadWrite);

Expand Down
14 changes: 7 additions & 7 deletions Rnwood.Smtp4dev.Tests/E2E/E2ETests_WebUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class E2ETests_WebUI : E2ETests
{
public E2ETests_WebUI(ITestOutputHelper output) : base(output)
{
new DriverManager().SetUpDriver(new ChromeConfig(), VersionResolveStrategy.MatchingBrowser);
//new DriverManager().SetUpDriver(new ChromeConfig(), VersionResolveStrategy.MatchingBrowser);
}

[Theory]
Expand All @@ -32,7 +32,7 @@ public E2ETests_WebUI(ITestOutputHelper output) : base(output)
[InlineData("/smtp4dev", true)]
public void CheckMessageIsReceivedAndDisplayed(string basePath, bool inMemoryDb)
{
RunUITest($"{nameof(CheckMessageIsReceivedAndDisplayed)}-{basePath}-{inMemoryDb}", (browser, baseUrl, smtpPortNumber) =>
RunUITest($"{nameof(CheckMessageIsReceivedAndDisplayed)}-{basePath}-{inMemoryDb}", (browser, baseUrl, hostname, smtpPortNumber) =>
{
browser.Navigate().GoToUrl(baseUrl);
HomePage homePage = new HomePage(browser);
Expand All @@ -56,7 +56,7 @@ public void CheckMessageIsReceivedAndDisplayed(string basePath, bool inMemoryDb)
Text = "Body of end to end test"
};

smtpClient.Connect("localhost", smtpPortNumber, SecureSocketOptions.StartTls,
smtpClient.Connect(hostname, smtpPortNumber, SecureSocketOptions.StartTls,
new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
smtpClient.Send(message);
smtpClient.Disconnect(true, new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
Expand All @@ -76,7 +76,7 @@ public void CheckMessageIsReceivedAndDisplayed(string basePath, bool inMemoryDb)
[Fact]
public void CheckUTF8MessageIsReceivedAndDisplayed()
{
RunUITest(nameof(CheckUTF8MessageIsReceivedAndDisplayed), (browser, baseUrl, smtpPortNumber) =>
RunUITest(nameof(CheckUTF8MessageIsReceivedAndDisplayed), (browser, baseUrl, hostname, smtpPortNumber) =>
{
browser.Navigate().GoToUrl(baseUrl);
HomePage homePage = new HomePage(browser);
Expand All @@ -101,7 +101,7 @@ public void CheckUTF8MessageIsReceivedAndDisplayed()
Text = "Body of end to end test"
};

smtpClient.Connect("localhost", smtpPortNumber, SecureSocketOptions.StartTls,
smtpClient.Connect(hostname, smtpPortNumber, SecureSocketOptions.StartTls,
new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);

FormatOptions formatOptions = FormatOptions.Default.Clone();
Expand Down Expand Up @@ -138,7 +138,7 @@ class UITestOptions : E2ETestOptions
{
}

private void RunUITest(string testName, Action<IWebDriver, Uri, int> uitest, UITestOptions options = null)
private void RunUITest(string testName, Action<IWebDriver, Uri, string, int> uitest, UITestOptions options = null)
{
options ??= new UITestOptions();

Expand All @@ -153,7 +153,7 @@ private void RunUITest(string testName, Action<IWebDriver, Uri, int> uitest, UIT
using var browser = new ChromeDriver(chromeOptions);
try
{
uitest(browser, context.BaseUrl, context.SmtpPortNumber);
uitest(browser, context.BaseUrl, context.Hostname, context.SmtpPortNumber);
}
catch
{
Expand Down
1 change: 1 addition & 0 deletions Rnwood.Smtp4dev.Tests/Rnwood.Smtp4dev.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<PackageReference Include="Selenium.WebDriver" Version="4.18.1" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.9" />
<PackageReference Include="Testcontainers" Version="3.7.0" />
<PackageReference Include="WebDriverManager" Version="2.17.2" />
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
Expand Down
44 changes: 24 additions & 20 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ stages:
env:
SMTP4DEV_E2E_WORKINGDIR: $(Agent.TempDirectory)/e2e
SMTP4DEV_E2E_BINARY: $(Agent.TempDirectory)/e2e/Rnwood.Smtp4dev
SMTP4DEV_E2E_ARGS:
inputs:
command: test
projects: Rnwood.Smtp4dev.Tests
Expand Down Expand Up @@ -188,6 +189,7 @@ stages:
env:
SMTP4DEV_E2E_WORKINGDIR: $(Agent.TempDirectory)/e2e
SMTP4DEV_E2E_BINARY: $(Agent.TempDirectory)/e2e/Rnwood.Smtp4dev.Desktop
SMTP4DEV_E2E_ARGS:
inputs:
command: test
projects: Rnwood.Smtp4dev.Desktop.Tests
Expand Down Expand Up @@ -233,25 +235,17 @@ stages:
command: build
dockerfile: "**/Dockerfile.linux"
arguments: "--build-arg version=$(tag) -t $(docker_repo):linux-amd64-$(tag)"
# - task: DotNetCoreCLI@2
# displayName: Run Tests
# env:
# SMTP4DEV_E2E_WORKINGDIR: $(Agent.TempDirectory)
# SMTP4DEV_E2E_USEDEFAULTDBPATH: 1
# SMTP4DEV_E2E_BINARY: docker
# SMTP4DEV_E2E_ARGS: |
# run
# -i
# -p
# 25:25
# -p
# 80:80
# -p
# 110:110
# $(docker_repo):linux-amd64-$(tag)
# --urls=http://*:80
# --smtpport=25
# --imapport=110
- task: DotNetCoreCLI@2
displayName: Run Tests
inputs:
command: test
projects: Rnwood.Smtp4dev.Tests
configuration: release
env:
SMTP4DEV_E2E_WORKINGDIR: $(Agent.TempDirectory)
SMTP4DEV_E2E_USEDEFAULTDBPATH: 1
SMTP4DEV_E2E_BINARY: docker:$(docker_repo):linux-amd64-$(tag)
SMTP4DEV_E2E_ARGS:
- task: Docker@2
displayName: Push image
condition: or(variables['isreleasebuild'], variables['iscibuild'])
Expand Down Expand Up @@ -298,7 +292,7 @@ stages:
- job: DockerBuildWindows
displayName: DockerBuild - Windows
pool:
vmImage: "windows-2022"
vmImage: "windows-2019"
steps:
- task: UseDotNet@2
displayName: Install .NET Core SDK v$(netcoresdk_version)
Expand All @@ -320,6 +314,16 @@ stages:
command: build
dockerfile: "**/Dockerfile.windows"
arguments: "--build-arg version=$(tag) -t $(docker_repo):windows-amd64-$(tag)"
- task: DotNetCoreCLI@2
displayName: Run Tests
inputs:
command: test
projects: Rnwood.Smtp4dev.Tests
configuration: release
env:
SMTP4DEV_E2E_WORKINGDIR: $(Agent.TempDirectory)
SMTP4DEV_E2E_USEDEFAULTDBPATH: 1
SMTP4DEV_E2E_BINARY: docker:$(docker_repo):windows-amd64-$(tag)
- task: Docker@2
displayName: Push image
condition: or(variables['isreleasebuild'], variables['iscibuild'])
Expand Down
Loading