Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanwoctopusdeploy committed Dec 1, 2023
1 parent 1044090 commit 9cc9aca
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ public async Task FailedUploadsAreNotRetriedAndFail(TentacleConfigurationTestCas
.Build(CancellationToken);

var remotePath = Path.Combine(clientTentacle.TemporaryDirectory.DirectoryPath, "UploadFile.txt");

var uploadFileTask = clientTentacle.TentacleClient.UploadFile(remotePath, DataStream.FromString("Hello"), CancellationToken);

Func<Task> action = async () => await uploadFileTask;
await action.Should().ThrowAsync<HalibutClientException>();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ConnectionRejected, tentacleConfigurationTestCase, clientTentacle)
.ForFileTransferService(FileTransferServiceOperation.UploadFile).Build();

await AssertionExtensions.Should(async () => await uploadFileTask).ThrowExceptionContractAsync(expectedException);

recordedUsages.For(nameof(IAsyncClientFileTransferService.UploadFileAsync)).LastException.Should().NotBeNull();
recordedUsages.For(nameof(IAsyncClientFileTransferService.UploadFileAsync)).Started.Should().Be(1);
Expand Down Expand Up @@ -84,9 +85,11 @@ public async Task FailedDownloadsAreNotRetriedAndFail(TentacleConfigurationTestC

await clientTentacle.TentacleClient.UploadFile(remotePath, DataStream.FromString("Hello"), CancellationToken);
var downloadFileTask = clientTentacle.TentacleClient.DownloadFile(remotePath, CancellationToken);

var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ConnectionRejected, tentacleConfigurationTestCase, clientTentacle)
.ForFileTransferService(FileTransferServiceOperation.DownloadFile).Build();

Func<Task> action = async () => await downloadFileTask;
await action.Should().ThrowAsync<HalibutClientException>();
await AssertionExtensions.Should(async () => await downloadFileTask).ThrowExceptionContractAsync(expectedException);

recordedUsages.For(nameof(IAsyncClientFileTransferService.DownloadFileAsync)).LastException.Should().NotBeNull();
recordedUsages.For(nameof(IAsyncClientFileTransferService.DownloadFileAsync)).Started.Should().Be(1);
Expand Down
185 changes: 185 additions & 0 deletions source/Octopus.Tentacle.Tests.Integration/ExceptionContractFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
using System;
using System.Threading.Tasks;
using FluentAssertions;
using FluentAssertions.Specialized;
using Halibut;
using Octopus.Tentacle.Tests.Integration.Support;

namespace Octopus.Tentacle.Tests.Integration
{
public static class ExceptionContractAssertionBuilderExtensionMethods
{
public static async Task<ExceptionAssertions<Exception>> ThrowExceptionContractAsync(
this NonGenericAsyncFunctionAssertions should,
ExceptionContract expected,
string because = "",
params object[] becauseArgs)
{
var exceptionAssertions = await should.ThrowAsync<Exception>();
var exception = exceptionAssertions.And;

exception.Should().BeOfType(expected.ExceptionType, because, becauseArgs);
exception.Message.Should().ContainAny(expected.ExceptionMessageShouldContainAny, because, becauseArgs);

return exceptionAssertions;
}

public static async Task<ExceptionAssertions<Exception>> ThrowExceptionContractAsync<T>(
this GenericAsyncFunctionAssertions<T> should,
ExceptionContract expected,
string because = "",
params object[] becauseArgs)
{
var exceptionAssertions = await should.ThrowAsync<Exception>();
var exception = exceptionAssertions.And;

exception.Should().BeOfType(expected.ExceptionType, because, becauseArgs);
exception.Message.Should().ContainAny(expected.ExceptionMessageShouldContainAny, because, becauseArgs);

return exceptionAssertions;
}
}

public class ExceptionContractAssertionBuilder
{
// - RPC Retries not supported
// - RPC Retries Disabled
// - RPC Retries - First Try
// - RPC Retries - Retrying

// Connecting
// Transferring

// Connecting / Transferring Error e.g. connection timeout or transferring error
// - Get Capabilities
// - Start Script
// - Get Status
// - Cancel Script
// - Complete Script
// - Upload File
// - Download File

// Cancelled
// - Get Capabilities
// - Start Script
// - Get Status
// - Cancel Script
// - Complete Script
// - Upload File
// - Download File

// RPC Retries Timeout
// - Get Capabilities
// - Start Script
// - Get Status
// - Cancel Script
// - Complete Script
// - Upload File
// - Download File

readonly FailureScenario failureScenario;
readonly TentacleConfigurationTestCase tentacleConfigurationTestCase;
readonly ClientAndTentacle clientAndTentacle;
FileTransferServiceOperation? fileTransferServiceOperation;
ScriptServiceOperation? scriptServiceOperation;

public ExceptionContractAssertionBuilder(FailureScenario failureScenario, TentacleConfigurationTestCase tentacleConfigurationTestCase, ClientAndTentacle clientAndTentacle)
{
this.failureScenario = failureScenario;
this.tentacleConfigurationTestCase = tentacleConfigurationTestCase;
this.clientAndTentacle = clientAndTentacle;
}

public ExceptionContractAssertionBuilder ForScriptService(ScriptServiceOperation scriptServiceOperation)
{
this.scriptServiceOperation = scriptServiceOperation;

return this;
}

public ExceptionContractAssertionBuilder ForFileTransferService(FileTransferServiceOperation fileTransferSercviceOperation)
{
this.fileTransferServiceOperation = fileTransferSercviceOperation;

return this;
}

public ExceptionContract Build()
{
if (scriptServiceOperation == null && fileTransferServiceOperation == null)
{
throw new InvalidOperationException("No operation specified");
}

if (scriptServiceOperation != null && fileTransferServiceOperation != null)
{
throw new InvalidOperationException("Script Service and File Transfer Service Operation both specified");
}

if (scriptServiceOperation != null && tentacleConfigurationTestCase.ScriptServiceToTest == null)
{
throw new InvalidOperationException("Script Service Version not specified in the TentacleConfigurationTestCase");
}

if (fileTransferServiceOperation != null)
{
if (failureScenario == FailureScenario.ConnectionRejected && tentacleConfigurationTestCase.TentacleType == TentacleType.Listening)
{
return new ExceptionContract(typeof(HalibutClientException), new[] { $"An error occurred when sending a request to '{clientAndTentacle.ServiceEndPoint}/', after the request began: Attempted to read past the end of the stream." });
}

if (failureScenario == FailureScenario.ConnectionRejected && tentacleConfigurationTestCase.TentacleType == TentacleType.Polling)
{
return new ExceptionContract(typeof(HalibutClientException), new[] { "Attempted to read past the end of the stream." });
}

//if (fileTransferServiceOperation == FileTransferServiceOperation.UploadFile)
//{

//}
//else if (fileTransferServiceOperation == FileTransferServiceOperation.DownloadFile)
//{
// //return new ExceptionContract(typeof(DownloadFileException), new[] { "DownloadFileException" });
//}
}
else
{

}

throw new NotImplementedException();
}
}

public class ExceptionContract
{
public Type ExceptionType { get; }
public string[] ExceptionMessageShouldContainAny { get; }

public ExceptionContract(Type exceptionType, string[] exceptionMessageShouldContainAny)
{
ExceptionType = exceptionType;
ExceptionMessageShouldContainAny = exceptionMessageShouldContainAny;
}
}

public enum ScriptServiceOperation
{
GetCapabilities,
StartScript,
GetStatus,
CancelScript,
CompleteScript
}

public enum FileTransferServiceOperation
{
UploadFile,
DownloadFile
}

public enum FailureScenario
{
ConnectionRejected
}
}

0 comments on commit 9cc9aca

Please sign in to comment.