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

Bump coverlet.collector from 6.0.0 to 6.0.2 #13

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@
using System.Formats.Tar;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RyuSocks.Test.Integration
{
public class ServerEnvironment : IAsyncDisposable, IDisposable
public class FTPServerEnvironment : IAsyncDisposable, IDisposable
{
private const string FTPServerImage = "delfer/alpine-ftp-server";
private const string FTPBaseServerImage = "delfer/alpine-ftp-server";
private const string FTPServerImage = "ryusocks-test-ftpserver";
private const string FTPServerTag = "latest";
private const string FTPMountPath = "/test";
private const string NetworkName = "ryusocks-test-network";
Expand All @@ -38,14 +41,25 @@ public class ServerEnvironment : IAsyncDisposable, IDisposable
private static readonly string _assetsPath = Path.Combine(ProjectPath, "assets");
public static readonly DirectoryInfo FTPServerFiles = new(_assetsPath);

private static readonly Dictionary<string, string> _buildContext = new()
private static readonly Dictionary<string, string> _ryuSocksBuildContext = new()
{
{ "RyuSocks.Test.Integration/docker/Dockerfile", "Dockerfile" },
{ "RyuSocks.Test.Integration/docker/server.Dockerfile", "Dockerfile" },
{ "RyuSocks.Generator", "RyuSocks.Generator" },
{ "RyuSocks", "RyuSocks" },
{ "RyuSocks.Test.Integration/docker/TestServer.cs", "RyuSocks/Program.cs" },
{ "RyuSocks.Test.Integration/docker/TestProject.csproj", "TestProject/TestProject.csproj" },
{ "RyuSocks.Test.Integration/docker/TestServer.cs", "TestProject/Program.cs" },
};

private static readonly Dictionary<string, string> _ftpBuildContext = new()
{
{ "RyuSocks.Test.Integration/docker/ftp.Dockerfile", "Dockerfile" },
{ "RyuSocks.Test.Integration/docker/vsftpd.conf", "vsftpd.conf" },
{ "RyuSocks.Test.Integration/assets", "assets" },
};

private static readonly DockerClientConfiguration _dockerConfig;
private readonly List<Thread> _threads = [];
private readonly CancellationTokenSource _cancellationTokenSource = new();
private DockerClient _docker;

private string _networkId;
Expand All @@ -55,24 +69,31 @@ public class ServerEnvironment : IAsyncDisposable, IDisposable
public string RyuSocksIPAddress { get; private set; }
public string FTPServerIPAddress { get; private set; }

public ServerEnvironment()
static FTPServerEnvironment()
{
var dockerEndpoint = Environment.GetEnvironmentVariable("DOCKER_HOST");
_dockerConfig = dockerEndpoint != null ? new DockerClientConfiguration(new Uri(dockerEndpoint)) : new DockerClientConfiguration();
}

public FTPServerEnvironment()
{
CreateEnvironment().Wait();
}

private async Task CreateEnvironment()
{
_docker = new DockerClientConfiguration().CreateClient();
_docker = _dockerConfig.CreateClient();

try
{
await _docker.Images.CreateImageAsync(
new ImagesCreateParameters { FromImage = FTPServerImage, Tag = FTPServerTag, },
new ImagesCreateParameters { FromImage = FTPBaseServerImage, Tag = FTPServerTag, },
null,
new Progress<JSONMessage>()
);

await BuildTestServer();
await BuildDockerImage(_ftpBuildContext, FTPServerImage);
await BuildDockerImage(_ryuSocksBuildContext, TestServerImage);

_networkId = (await _docker.Networks.CreateNetworkAsync(
new NetworksCreateParameters
Expand All @@ -98,16 +119,8 @@ await _docker.Images.CreateImageAsync(
Image = FTPServerImage,
Env =
[
$"USERS=\"{FTPUsername}|{FTPPassword}|{FTPMountPath}|1000\"",
$"USERS={FTPUsername}|{FTPPassword}|{FTPMountPath}|1000",
],
HostConfig = new HostConfig
{
AutoRemove = true,
Mounts =
[
new Mount { Type = "bind", Source = _assetsPath, Target = FTPMountPath },
],
},
Name = "ryusocks-ftpserver",
Hostname = "ftpserver",
NetworkingConfig = containerNetwork,
Expand All @@ -118,10 +131,6 @@ await _docker.Images.CreateImageAsync(
new CreateContainerParameters
{
Image = TestServerImage,
HostConfig = new HostConfig
{
AutoRemove = true,
},
Name = "ryusocks-server",
Hostname = "ryusocks-server",
NetworkingConfig = containerNetwork,
Expand All @@ -135,6 +144,14 @@ await _docker.Images.CreateImageAsync(
.Networks[NetworkName].IPAddress;
RyuSocksIPAddress = (await _docker.Containers.InspectContainerAsync(_ryuSocksContainerId)).NetworkSettings
.Networks[NetworkName].IPAddress;

_threads.Add(new Thread(() => _ = PrintContainerLogs(_ryuSocksContainerId, "RyuSocks", _cancellationTokenSource.Token)));
_threads.Add(new Thread(() => _ = PrintContainerLogs(_ftpContainerId, "FTPServer", _cancellationTokenSource.Token)));

foreach (var thread in _threads)
{
thread.Start();
}
}
catch (DockerApiException)
{
Expand All @@ -143,14 +160,56 @@ await _docker.Images.CreateImageAsync(
}
}

private async Task BuildTestServer()
private async Task PrintContainerLogs(string containerId, string name, CancellationToken token)
{
var logStream = await _docker.Containers.GetContainerLogsAsync(
containerId,
false,
new ContainerLogsParameters
{
ShowStderr = true,
ShowStdout = true,
Follow = true,
},
token
);

var stdout = Console.OpenStandardOutput();
var stderr = Console.OpenStandardError();

var buffer = new byte[1024 * 1024];
MultiplexedStream.ReadResult readResult = await logStream.ReadOutputAsync(buffer, 0, buffer.Length, token);

while (!readResult.EOF && !token.IsCancellationRequested)
{
var stream = readResult.Target == MultiplexedStream.TargetStream.StandardError
? stderr
: stdout;

await stream.WriteAsync(Encoding.Default.GetBytes($"<{name}>: "), token);
await stream.WriteAsync(buffer.AsMemory(0, readResult.Count), token);

if (readResult.Count < 1024)
{
await stream.FlushAsync(token);
}

Array.Clear(buffer);
readResult = await logStream.ReadOutputAsync(buffer, 0, buffer.Length, token);
}

stderr.Close();
stdout.Close();
}

private async Task BuildDockerImage(Dictionary<string, string> buildContext, string imageName)
{
MemoryStream tarMemory = new();
TarWriter tarWriter = new(tarMemory, true);

string solutionPath = Path.GetFullPath(Path.Combine(ProjectPath, ".."));

foreach ((string hostPath, string tarPath) in _buildContext)
foreach ((string hostPath, string tarPath) in buildContext)
{
string fullHostPath = Path.GetFullPath(Path.Combine(solutionPath, hostPath));

Expand Down Expand Up @@ -185,7 +244,7 @@ private async Task BuildTestServer()
await _docker.Images.BuildImageFromDockerfileAsync(
new ImageBuildParameters
{
Tags = [$"{TestServerImage}:latest"],
Tags = [$"{imageName}:latest"],
Remove = true,
ForceRemove = true,
Pull = "always",
Expand All @@ -201,6 +260,12 @@ await _docker.Images.BuildImageFromDockerfileAsync(

private async Task DestroyEnvironment()
{
await _cancellationTokenSource.CancelAsync();
foreach (var thread in _threads)
{
thread.Join();
}

if (_ftpContainerId != null)
{
try
Expand Down Expand Up @@ -248,6 +313,15 @@ private async Task DestroyEnvironment()
{
// Ignored.
}

try
{
await _docker.Images.DeleteImageAsync(FTPBaseServerImage, new ImageDeleteParameters { Force = true });
}
catch (DockerImageNotFoundException)
{
// Ignored.
}
}

protected virtual async ValueTask DisposeAsyncCore()
Expand Down
2 changes: 1 addition & 1 deletion RyuSocks.Test.Integration/RyuSocks.Test.Integration.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="coverlet.collector" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
117 changes: 117 additions & 0 deletions RyuSocks.Test.Integration/SocksServerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (C) RyuSOCKS
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

using FluentFTP;
using FluentFTP.Proxy.SyncProxy;
using System;
using System.IO;
using System.Net;
using Xunit;

namespace RyuSocks.Test.Integration
{
public class SocksServerTests : IClassFixture<FTPServerEnvironment>, IDisposable
{
private readonly FTPServerEnvironment _fixture;
private readonly FtpClientSocks5Proxy _ftp;

public SocksServerTests(FTPServerEnvironment fixture)
{
_fixture = fixture;
Console.WriteLine($"Using ProxyHost: {_fixture.RyuSocksIPAddress}");
_ftp = new FtpClientSocks5Proxy(new FtpProxyProfile
{
FtpCredentials = new NetworkCredential(FTPServerEnvironment.FTPUsername, FTPServerEnvironment.FTPPassword),
FtpHost = _fixture.FTPServerIPAddress,
ProxyHost = _fixture.RyuSocksIPAddress,
ProxyPort = 1080,
});
_ftp.Config.LogToConsole = true;
_ftp.Config.ConnectTimeout = 20 * 1000;
_ftp.Config.ReadTimeout = 20 * 1000;
}

[Fact]
public void FTPClient_CanConnect()
{
_ftp.Connect();
}

[Fact]
public void FTPClient_CanListFiles()
{
_ftp.Connect();

var items = _ftp.GetListing("assets");

Assert.Equal(items.Length, FTPServerEnvironment.FTPServerFiles.GetFiles().Length);
}

[Theory]
[InlineData(0, true)]
[InlineData(0, false)]
[InlineData(1, true)]
[InlineData(1, false)]
public void FTPClient_CanDownloadFile(int fileIndex, bool isPassiveMode)
{
var file = FTPServerEnvironment.FTPServerFiles.GetFiles()[fileIndex];
var downloadDirectory = Directory.CreateTempSubdirectory("Ryujinx.Test.Integration.FTPClient");
var downloadPath = Path.Combine(downloadDirectory.FullName, file.Name);

_ftp.Config.DataConnectionType = isPassiveMode ? FtpDataConnectionType.AutoPassive : FtpDataConnectionType.AutoActive;
_ftp.Connect();

var result = _ftp.DownloadFile(downloadPath, $"assets/{file.Name}");

Assert.Equal(FtpStatus.Success, result);
Assert.Equal(File.ReadAllBytes(downloadPath), File.ReadAllBytes(file.FullName));

downloadDirectory.Delete(true);
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void FTPClient_CanUploadFile(bool isPassiveMode)
{
string fileName = isPassiveMode ? "upload_passive.bin" : "upload_active.bin";
byte[] fileBytes = new byte[1024];
Random.Shared.NextBytes(fileBytes);

_ftp.Config.DataConnectionType = isPassiveMode ? FtpDataConnectionType.AutoPassive : FtpDataConnectionType.AutoActive;
_ftp.Connect();

var result = _ftp.UploadBytes(fileBytes, $"upload/{fileName}");

Assert.Equal(FtpStatus.Success, result);
}

private void Dispose(bool disposing)
{
if (disposing)
{
_ftp?.Dispose();
}
}

public void Dispose()
{
// Dispose of unmanaged resources.
Dispose(true);

// Suppress finalization.
GC.SuppressFinalize(this);
}
}
}
Binary file added RyuSocks.Test.Integration/assets/data.bin
Binary file not shown.
1 change: 1 addition & 0 deletions RyuSocks.Test.Integration/assets/simple.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A simple text file.
22 changes: 0 additions & 22 deletions RyuSocks.Test.Integration/docker/Dockerfile

This file was deleted.

10 changes: 10 additions & 0 deletions RyuSocks.Test.Integration/docker/TestProject.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\RyuSocks\RyuSocks.csproj" />
</ItemGroup>
</Project>
Loading
Loading