Skip to content

Commit 1b46264

Browse files
Merge pull request #1148 from WojciechNagorski/integration-tests-mstests
MSTest Integration tests
2 parents 592c86c + bfef6aa commit 1b46264

20 files changed

+627
-8
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[*.cs]
2+
3+
#### SYSLIB diagnostics ####
4+
5+
# SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time
6+
#
7+
# TODO: Remove this when https://github.com/sshnet/SSH.NET/issues/1131 is implemented.
8+
dotnet_diagnostic.SYSLIB1045.severity = none
9+
10+
### StyleCop Analyzers rules ###
11+
12+
#### .NET Compiler Platform analysers rules ####
13+
14+
# IDE0007: Use var instead of explicit type
15+
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0007
16+
dotnet_diagnostic.IDE0007.severity = suggestion
17+
18+
# IDE0028: Use collection initializers
19+
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0028
20+
dotnet_diagnostic.IDE0028.severity = suggestion
21+
22+
# IDE0058: Remove unnecessary expression value
23+
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0058
24+
dotnet_diagnostic.IDE0058.severity = suggestion
25+
26+
# IDE0059: Remove unnecessary value assignment
27+
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0059
28+
dotnet_diagnostic.IDE0059.severity = suggestion
29+
30+
# IDE0230: Use UTF-8 string literal
31+
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0230
32+
dotnet_diagnostic.IDE0230.severity = suggestion
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
FROM alpine:latest
2+
3+
COPY --chown=root:root server/ssh /etc/ssh/
4+
COPY --chown=root:root server/script /opt/sshnet
5+
COPY user/sshnet /home/sshnet/.ssh
6+
7+
RUN apk update && apk upgrade --no-cache && \
8+
apk add --no-cache syslog-ng && \
9+
# install and configure sshd
10+
apk add --no-cache openssh && \
11+
# install openssh-server-pam to allow for keyboard-interactive authentication
12+
apk add --no-cache openssh-server-pam && \
13+
dos2unix /etc/ssh/* && \
14+
chmod 400 /etc/ssh/ssh*key && \
15+
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config && \
16+
sed -i 's/#LogLevel\s*INFO/LogLevel DEBUG3/' /etc/ssh/sshd_config && \
17+
echo 'PubkeyAcceptedAlgorithms ssh-rsa' >> /etc/ssh/sshd_config && \
18+
chmod 646 /etc/ssh/sshd_config && \
19+
# install and configure sudo
20+
apk add --no-cache sudo && \
21+
addgroup sudo && \
22+
# allow root to run any command
23+
echo 'root ALL=(ALL) ALL' > /etc/sudoers && \
24+
# allow everyone in the 'sudo' group to run any command without a password
25+
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \
26+
# add user to run most of the integration tests
27+
adduser -D sshnet && \
28+
passwd -u sshnet && \
29+
echo 'sshnet:ssh4ever' | chpasswd && \
30+
dos2unix /home/sshnet/.ssh/* && \
31+
chown -R sshnet:sshnet /home/sshnet && \
32+
chmod -R 700 /home/sshnet/.ssh && \
33+
chmod -R 644 /home/sshnet/.ssh/authorized_keys && \
34+
# add user to administer container (update configs, restart sshd)
35+
adduser -D sshnetadm && \
36+
passwd -u sshnetadm && \
37+
echo 'sshnetadm:ssh4ever' | chpasswd && \
38+
addgroup sshnetadm sudo && \
39+
dos2unix /opt/sshnet/* && \
40+
# install shadow package; we use chage command in this package to expire/unexpire password of the sshnet user
41+
apk add --no-cache shadow && \
42+
# allow us to use telnet command; we use this in the remote port forwarding tests
43+
apk --no-cache add busybox-extras && \
44+
# install full-fledged ps command
45+
apk add --no-cache procps
46+
47+
EXPOSE 22 22
48+
49+
ENTRYPOINT ["/opt/sshnet/start.sh"]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net7.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
8+
<IsPackable>false</IsPackable>
9+
<IsTestProject>true</IsTestProject>
10+
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
11+
<!--
12+
Even though we're not interested in producing XML docs for test projects, we have to enable this in order to have the .NET Compiler
13+
Platform analyzers produce the IDE0005 (Remove unnecessary import) diagnostic.
14+
15+
To avoid warnings for missing XML docs, we add CS1591 (Missing XML comment for publicly visible type or member) to the NoWarn property.
16+
17+
We can stop producing XML docs for test projects (and remove the NoWarn for CS1591) once the following issue is fixed:
18+
https://github.com/dotnet/roslyn/issues/41640.
19+
-->
20+
<NoWarn>$(NoWarn);CS1591</NoWarn>
21+
22+
</PropertyGroup>
23+
24+
<ItemGroup>
25+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
26+
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
27+
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
28+
<PackageReference Include="Testcontainers" Version="3.4.0" />
29+
<PackageReference Include="coverlet.collector" Version="6.0.0">
30+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
31+
<PrivateAssets>all</PrivateAssets>
32+
</PackageReference>
33+
</ItemGroup>
34+
35+
<ItemGroup>
36+
<ProjectReference Include="..\Renci.SshNet\Renci.SshNet.csproj">
37+
<Aliases>LocalSshNet</Aliases>
38+
</ProjectReference>
39+
</ItemGroup>
40+
41+
<ItemGroup>
42+
<None Update="app.config">
43+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
44+
</None>
45+
</ItemGroup>
46+
47+
</Project>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace IntegrationTests
2+
{
3+
/// <summary>
4+
/// The SCP client integration tests
5+
/// </summary>
6+
[TestClass]
7+
public class ScpClientTests : IntegrationTestBase, IDisposable
8+
{
9+
private readonly ScpClient _scpClient;
10+
11+
public ScpClientTests()
12+
{
13+
_scpClient = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password);
14+
_scpClient.Connect();
15+
}
16+
17+
[TestMethod]
18+
19+
public void Upload_And_Download_FileStream()
20+
{
21+
var file = $"/tmp/{Guid.NewGuid()}.txt";
22+
var fileContent = "File content !@#$%^&*()_+{}:,./<>[];'\\|";
23+
24+
using var uploadStream = new MemoryStream(Encoding.UTF8.GetBytes(fileContent));
25+
_scpClient.Upload(uploadStream, file);
26+
27+
using var downloadStream = new MemoryStream();
28+
_scpClient.Download(file, downloadStream);
29+
30+
var result = Encoding.UTF8.GetString(downloadStream.ToArray());
31+
32+
Assert.AreEqual(fileContent, result);
33+
}
34+
35+
public void Dispose()
36+
{
37+
_scpClient.Disconnect();
38+
_scpClient.Dispose();
39+
}
40+
}
41+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
namespace IntegrationTests
2+
{
3+
/// <summary>
4+
/// The SFTP client integration tests
5+
/// </summary>
6+
[TestClass]
7+
public class SftpClientTests : IntegrationTestBase, IDisposable
8+
{
9+
private readonly SftpClient _sftpClient;
10+
11+
public SftpClientTests()
12+
{
13+
_sftpClient = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password);
14+
_sftpClient.Connect();
15+
}
16+
17+
[TestMethod]
18+
public void Create_directory_with_contents_and_list_it()
19+
{
20+
var testDirectory = "/home/sshnet/sshnet-test";
21+
var testFileName = "test-file.txt";
22+
var testFilePath = $"{testDirectory}/{testFileName}";
23+
var testContent = "file content";
24+
25+
// Create new directory and check if it exists
26+
_sftpClient.CreateDirectory(testDirectory);
27+
Assert.IsTrue(_sftpClient.Exists(testDirectory));
28+
29+
// Upload file and check if it exists
30+
using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent));
31+
_sftpClient.UploadFile(fileStream, testFilePath);
32+
Assert.IsTrue(_sftpClient.Exists(testFilePath));
33+
34+
// Check if ListDirectory works
35+
var files = _sftpClient.ListDirectory(testDirectory);
36+
37+
_sftpClient.DeleteFile(testFilePath);
38+
_sftpClient.DeleteDirectory(testDirectory);
39+
40+
var builder = new StringBuilder();
41+
foreach (var file in files)
42+
{
43+
builder.AppendLine($"{file.FullName} {file.IsRegularFile} {file.IsDirectory}");
44+
}
45+
46+
Assert.AreEqual(@"/home/sshnet/sshnet-test/. False True
47+
/home/sshnet/sshnet-test/.. False True
48+
/home/sshnet/sshnet-test/test-file.txt True False
49+
", builder.ToString());
50+
}
51+
52+
[TestMethod]
53+
public async Task Create_directory_with_contents_and_list_it_async()
54+
{
55+
var testDirectory = "/home/sshnet/sshnet-test";
56+
var testFileName = "test-file.txt";
57+
var testFilePath = $"{testDirectory}/{testFileName}";
58+
var testContent = "file content";
59+
60+
// Create new directory and check if it exists
61+
_sftpClient.CreateDirectory(testDirectory);
62+
Assert.IsTrue(_sftpClient.Exists(testDirectory));
63+
64+
// Upload file and check if it exists
65+
using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent));
66+
_sftpClient.UploadFile(fileStream, testFilePath);
67+
Assert.IsTrue(_sftpClient.Exists(testFilePath));
68+
69+
// Check if ListDirectory works
70+
var files = await _sftpClient.ListDirectoryAsync(testDirectory, CancellationToken.None);
71+
72+
_sftpClient.DeleteFile(testFilePath);
73+
_sftpClient.DeleteDirectory(testDirectory);
74+
75+
var builder = new StringBuilder();
76+
foreach (var file in files)
77+
{
78+
builder.AppendLine($"{file.FullName} {file.IsRegularFile} {file.IsDirectory}");
79+
}
80+
81+
Assert.AreEqual(@"/home/sshnet/sshnet-test/. False True
82+
/home/sshnet/sshnet-test/.. False True
83+
/home/sshnet/sshnet-test/test-file.txt True False
84+
", builder.ToString());
85+
}
86+
87+
[TestMethod]
88+
[ExpectedException(typeof(SftpPermissionDeniedException), "Permission denied")]
89+
public void Test_Sftp_ListDirectory_Permission_Denied()
90+
{
91+
_sftpClient.ListDirectory("/root");
92+
}
93+
94+
public void Dispose()
95+
{
96+
_sftpClient.Disconnect();
97+
_sftpClient.Dispose();
98+
}
99+
}
100+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
namespace IntegrationTests
2+
{
3+
/// <summary>
4+
/// The SSH client integration tests
5+
/// </summary>
6+
[TestClass]
7+
public class SshClientTests : IntegrationTestBase, IDisposable
8+
{
9+
private readonly SshClient _sshClient;
10+
11+
public SshClientTests()
12+
{
13+
_sshClient = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password);
14+
_sshClient.Connect();
15+
}
16+
17+
[TestMethod]
18+
public void Echo_Command_with_all_characters()
19+
{
20+
var builder = new StringBuilder();
21+
var response = _sshClient.RunCommand("echo $'test !@#$%^&*()_+{}:,./<>[];\\|'");
22+
23+
Assert.AreEqual("test !@#$%^&*()_+{}:,./<>[];\\|\n", response.Result);
24+
}
25+
26+
public void Dispose()
27+
{
28+
_sshClient.Disconnect();
29+
_sshClient.Dispose();
30+
}
31+
}
32+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace IntegrationTests
2+
{
3+
[TestClass]
4+
public class TestInitializer
5+
{
6+
[AssemblyInitialize]
7+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "MSTests requires context parameter")]
8+
public static async Task Initialize(TestContext context)
9+
{
10+
await InfrastructureFixture.Instance.InitializeAsync();
11+
}
12+
13+
[AssemblyCleanup]
14+
public static async Task Cleanup()
15+
{
16+
await InfrastructureFixture.Instance.DisposeAsync();
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)