Skip to content

Commit

Permalink
Merge pull request #160 from FrendsPlatform/issue-159
Browse files Browse the repository at this point in the history
SFTP.DeleteFiles - Initial implementation
  • Loading branch information
Svenskapojkarna authored Sep 4, 2023
2 parents d78aded + 3ef5b85 commit e647bfa
Show file tree
Hide file tree
Showing 35 changed files with 2,027 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/DeleteFiles_build_and_test_on_main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: DeleteFiles_build_main

on:
push:
branches:
- main
paths:
- 'Frends.SFTP.DeleteFiles/**'
workflow_dispatch:

jobs:
build:
uses: FrendsPlatform/FrendsTasks/.github/workflows/linux_build_main.yml@main
with:
workdir: Frends.SFTP.DeleteFiles
prebuild_command: docker-compose -f ./Frends.SFTP.DeleteFiles.Tests/docker-compose.yml up -d
secrets:
badge_service_api_key: ${{ secrets.BADGE_SERVICE_API_KEY }}

19 changes: 19 additions & 0 deletions .github/workflows/DeleteFiles_build_and_test_on_push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: DeleteFiles_build_test

on:
push:
branches-ignore:
- main
paths:
- 'Frends.SFTP.DeleteFiles/**'
workflow_dispatch:

jobs:
build:
uses: FrendsPlatform/FrendsTasks/.github/workflows/linux_build_test.yml@main
with:
workdir: Frends.SFTP.DeleteFiles
prebuild_command: docker-compose -f ./Frends.SFTP.DeleteFiles.Tests/docker-compose.yml up -d
secrets:
badge_service_api_key: ${{ secrets.BADGE_SERVICE_API_KEY }}
test_feed_api_key: ${{ secrets.TASKS_TEST_FEED_API_KEY }}
13 changes: 13 additions & 0 deletions .github/workflows/DeleteFiles_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: DeleteFiles_release

on:
workflow_dispatch:

jobs:
build:
uses: FrendsPlatform/FrendsTasks/.github/workflows/release.yml@main
with:
workdir: Frends.SFTP.DeleteFiles
secrets:
feed_api_key: ${{ secrets.TASKS_FEED_API_KEY }}

46 changes: 46 additions & 0 deletions Frends.SFTP.DeleteFiles/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[*.cs]

# SA1649: File name should match first type name
dotnet_diagnostic.SA1649.severity = none

# SA1633: File should have header
dotnet_diagnostic.SA1633.severity = none

# IDE0160: Convert to block scoped namespace
csharp_style_namespace_declarations = file_scoped

# SA0001: XML comment analysis is disabled due to project configuration
dotnet_diagnostic.SA0001.severity = none

# SA1101: Prefix local calls with this
dotnet_diagnostic.SA1101.severity = none

# SA1600: Elements should be documented
dotnet_diagnostic.SA1600.severity = none

# SA1503: Braces should not be omitted
dotnet_diagnostic.SA1503.severity = none

# SA1130: Use lambda syntax
dotnet_diagnostic.SA1130.severity = none

# S3267: Loops should be simplified with "LINQ" expressions
dotnet_diagnostic.S3267.severity = none

# SA1309: Field names should not begin with underscore
dotnet_diagnostic.SA1309.severity = none

# SA1401: Fields should be private
dotnet_diagnostic.SA1401.severity = none

# CA2211: Non-constant fields should not be visible
dotnet_diagnostic.CA2211.severity = none

# S3010: Static fields should not be updated in constructors
dotnet_diagnostic.S3010.severity = none

# SA1501: Statement should not be on a single line
dotnet_diagnostic.SA1501.severity = none

# SA1008: Opening parenthesis should be spaced correctly
dotnet_diagnostic.SA1008.severity = none
5 changes: 5 additions & 0 deletions Frends.SFTP.DeleteFiles/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

## [1.0.0] - 2023-09-01
### Changed
- Initial implementation
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
namespace Frends.SFTP.DeleteFiles.Tests;

using System;
using System.IO;
using System.Net.Sockets;
using Frends.SFTP.DeleteFiles.Definitions;
using Frends.SFTP.DeleteFiles.Enums;
using NUnit.Framework;
using Renci.SshNet.Common;

[TestFixture]
public class ConnectionTests : UnitTestBase
{
[Test]
public void DeleteFiles_TestTransferThatThrowsWithIncorrectCredentials()
{
var connection = Helpers.GetSftpConnection();
connection.ConnectionTimeout = 10;
connection.Username = "demo";
connection.Password = "demo";

var ex = Assert.Throws<SshAuthenticationException>(() => SFTP.DeleteFiles(_input, connection, default));
Assert.AreEqual("Permission denied (password).", ex.Message);
}

[Test]
public void DeleteFiles_TestPrivateKeyFileRsa()
{
var connection = Helpers.GetSftpConnection();
connection.Authentication = AuthenticationType.UsernamePasswordPrivateKeyFile;
connection.PrivateKeyPassphrase = "passphrase";
connection.PrivateKeyFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../Volumes/ssh_host_rsa_key");

var result = SFTP.DeleteFiles(_input, connection, default);
Assert.AreEqual(3, result.Files.Count);
}

[Test]
public void DeleteFiles_TestPrivateKeyFileRsaFromString()
{
var key = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../Volumes/ssh_host_rsa_key"));

var connection = Helpers.GetSftpConnection();
connection.HostKeyAlgorithm = HostKeyAlgorithms.RSA;
connection.Authentication = AuthenticationType.UsernamePasswordPrivateKeyString;
connection.PrivateKeyPassphrase = "passphrase";
connection.PrivateKeyString = key;

var result = SFTP.DeleteFiles(_input, connection, default);
Assert.AreEqual(3, result.Files.Count);
}

[Test]
public void DeleteFiles_TestWithInteractiveKeyboardAuthentication()
{
var connection = Helpers.GetSftpConnection();
connection.UseKeyboardInteractiveAuthentication = true;

var result = SFTP.DeleteFiles(_input, connection, default);
Assert.AreEqual(3, result.Files.Count);
}

[Test]
public void DeleteFiles_TestWithInteractiveKeyboardAuthenticationAndPrivateKey()
{
var connection = Helpers.GetSftpConnection();
connection.Authentication = AuthenticationType.UsernamePrivateKeyFile;
connection.PrivateKeyFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../Volumes/ssh_host_rsa_key");
connection.Password = null;
connection.PrivateKeyPassphrase = "passphrase";
connection.UseKeyboardInteractiveAuthentication = true;
connection.PromptAndResponse = new PromptResponse[] { new PromptResponse { Prompt = "Password", Response = "pass" } };

var result = SFTP.DeleteFiles(_input, connection, default);
Assert.AreEqual(3, result.Files.Count);

connection.Authentication = AuthenticationType.UsernamePrivateKeyString;
connection.PrivateKeyFile = null;
connection.PrivateKeyString = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../Volumes/ssh_host_rsa_key"));
connection.PrivateKeyPassphrase = "passphrase";

_input.Directory = "/delete/subDir";
result = SFTP.DeleteFiles(_input, connection, default);
Assert.AreEqual(3, result.Files.Count);
}

[Test]
public void DeleteFiles_TestThrowsWithWrongPort()
{
var connection = Helpers.GetSftpConnection();
connection.Port = 51644;
var input = new Input
{
Directory = "/upload",
FileMask = "filenotexisting.txt",
};

Assert.Throws<SocketException>(() => SFTP.DeleteFiles(input, connection, default));
}

[Test]
public void DeleteFiles_TestThrowsWithIncorrectCredentials()
{
var connection = Helpers.GetSftpConnection();
connection.Password = "demo";
connection.Username = "demo";

var input = new Input
{
Directory = "/upload",
FileMask = "filenotexisting.txt",
};

var ex = Assert.Throws<SshAuthenticationException>(() => SFTP.DeleteFiles(input, connection, default));
Assert.AreEqual("Permission denied (password).", ex.Message);
}

[Test]
public void DeleteFiles_TestThrowsWithIncorrectPrivateKeyPassphrase()
{
var connection = Helpers.GetSftpConnection();
connection.Authentication = AuthenticationType.UsernamePasswordPrivateKeyFile;
connection.PrivateKeyPassphrase = "demo";
connection.PrivateKeyFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../Volumes/ssh_host_rsa_key");

var input = new Input
{
Directory = "/upload",
FileMask = "filenotexisting.txt",
};

var ex = Assert.Throws<ArgumentException>(() => SFTP.DeleteFiles(input, connection, default));
Assert.IsTrue(ex.Message.StartsWith("Error when initializing connection info:"));
}

[Test]
public void DeleteFiles_TestThrowsWithEmptyPrivateKeyFile()
{
var connection = Helpers.GetSftpConnection();
connection.Authentication = AuthenticationType.UsernamePasswordPrivateKeyFile;
connection.PrivateKeyPassphrase = "passphrase";
connection.PrivateKeyFile = "";

Check warning on line 142 in Frends.SFTP.DeleteFiles/Frends.SFTP.DeleteFiles.Tests/ConnectionTests.cs

View workflow job for this annotation

GitHub Actions / build / Build main branch

Use string.Empty for empty strings

Check warning on line 142 in Frends.SFTP.DeleteFiles/Frends.SFTP.DeleteFiles.Tests/ConnectionTests.cs

View workflow job for this annotation

GitHub Actions / build / Build main branch

Use string.Empty for empty strings

Check warning on line 142 in Frends.SFTP.DeleteFiles/Frends.SFTP.DeleteFiles.Tests/ConnectionTests.cs

View workflow job for this annotation

GitHub Actions / build / ReleaseTheTask

Use string.Empty for empty strings

Check warning on line 142 in Frends.SFTP.DeleteFiles/Frends.SFTP.DeleteFiles.Tests/ConnectionTests.cs

View workflow job for this annotation

GitHub Actions / build / ReleaseTheTask

Use string.Empty for empty strings

var input = new Input
{
Directory = "/upload",
FileMask = "filenotexisting.txt",
};

var ex = Assert.Throws<ArgumentException>(() => SFTP.DeleteFiles(input, connection, default));
Assert.IsTrue(ex.Message.StartsWith("Error when initializing connection info: "));
}

[Test]
public void DeleteFiles_TestThrowsWithIncorrectPrivateKeyString()
{
var key = Helpers.GenerateDummySshKey();

var connection = Helpers.GetSftpConnection();
connection.Authentication = AuthenticationType.UsernamePasswordPrivateKeyString;
connection.PrivateKeyPassphrase = "passphrase";
connection.PrivateKeyString = key.ToString();

var input = new Input
{
Directory = "/upload",
FileMask = "filenotexisting.txt",
};

var ex = Assert.Throws<ArgumentException>(() => SFTP.DeleteFiles(input, connection, default));
Assert.IsTrue(ex.Message.StartsWith("Error when initializing connection info: "));
}

[Test]
public void DeleteFiles_TestThrowsWithIncorrectServerFingerprint()
{
var fingerprint = "f6:fc:1c:03:17:5f:67:4f:1f:0b:50:5a:9f:f9:30:e5";

var connection = Helpers.GetSftpConnection();
connection.ServerFingerPrint = fingerprint;

var input = new Input
{
Directory = "/upload",
FileMask = "filenotexisting.txt",
};

var ex = Assert.Throws<SshConnectionException>(() => SFTP.DeleteFiles(input, connection, default));
Assert.AreEqual("Key exchange negotiation failed.", ex.Message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM atmoz/sftp

ARG DEBIAN_FRONTEND=noninteractive

COPY ./Volumes/sshd_config /etc/ssh/sshd_config
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
namespace Frends.SFTP.DeleteFiles.Tests;

using NUnit.Framework;
using Renci.SshNet.Common;

/// <summary>
/// Test class.
/// </summary>
[TestFixture]
internal class UnitTests : UnitTestBase
{
[Test]
public void DeleteFiles_SimpleDelete()
{
var result = SFTP.DeleteFiles(_input, _connection, default);
Assert.AreEqual(3, result.Files.Count);
}

[Test]
public void DeleteFiles_TaskShouldNotThrowIfNoFiles()
{
_input.FileMask = "FileThatDontExist";
var result = SFTP.DeleteFiles(_input, _connection, default);
Assert.AreEqual(0, result.Files.Count);
}

[Test]
public void DeleteFiles_TestWithFilePaths()
{
var filePaths = new string[] { "/delete/subDir/test2.txt", "/delete/subDir/test1.txt" };
_input.FilePaths = filePaths;
var result = SFTP.DeleteFiles(_input, _connection, default);
Assert.AreEqual(2, result.Files.Count);
}

[Test]
public void DeleteFiles_TestWithDirectoryNotExisting()
{
_input.Directory = "/does/not/exist";
var ex = Assert.Throws<SftpPathNotFoundException>(() => SFTP.DeleteFiles(_input, _connection, default));
Assert.AreEqual($"No such Directory '{_input.Directory}'.", ex.Message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.507">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.7.0.75501">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Frends.SFTP.DeleteFiles\Frends.SFTP.DeleteFiles.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "No documentation needed for Tests", Scope = "namespaceanddescendants", Target = "Frends.SFTP.DeleteFiles.Tests")]
Loading

0 comments on commit e647bfa

Please sign in to comment.