-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Test Exception Contracts for Tentacle Client
- Loading branch information
1 parent
e273d83
commit a19e956
Showing
3 changed files
with
213 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
192 changes: 192 additions & 0 deletions
192
source/Octopus.Tentacle.Tests.Integration/ExceptionContractFixture.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
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.ConnectionFaulted) | ||
{ | ||
switch (tentacleConfigurationTestCase.TentacleType) | ||
{ | ||
case 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.", | ||
$"An error occurred when sending a request to '{clientAndTentacle.ServiceEndPoint}/', after the request began: Unable to write data to the transport connection: An established connection was aborted by the software in your host machine", | ||
$"An error occurred when sending a request to '{clientAndTentacle.ServiceEndPoint}/', after the request began: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine", | ||
$"An error occurred when sending a request to '{clientAndTentacle.ServiceEndPoint}/', before the request could begin: Connection refused" | ||
}); | ||
case TentacleType.Polling: | ||
return new ExceptionContract(typeof(HalibutClientException), new[] | ||
{ | ||
"Attempted to read past the end of the stream.", | ||
"Unable to write data to the transport connection: An established connection was aborted by the software in your host machine", | ||
"Unable to read data from the transport connection: An established connection was aborted by the software in your host machine", | ||
"Connection refused", | ||
"Unable to write data to the transport connection: Broken pipe" | ||
}); | ||
default: | ||
throw new ArgumentOutOfRangeException(); | ||
} | ||
} | ||
} | ||
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 | ||
{ | ||
ConnectionFaulted | ||
} | ||
} |