Skip to content

Commit

Permalink
Test Exception Contracts for Tentacle Client
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanwoctopusdeploy committed Dec 6, 2023
1 parent 081c788 commit f810686
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ public async Task WhenRpcRetriesTimeOut_DuringUploadFile_TheRpcCallIsCancelled(T
// Start the script which will wait for a file to exist
var duration = Stopwatch.StartNew();
var executeScriptTask = clientAndTentacle.TentacleClient.UploadFile(remotePath, dataStream, CancellationToken, inMemoryLog);

var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ConnectionFaulted, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

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

methodUsages.For(nameof(IAsyncClientFileTransferService.UploadFileAsync)).Started.Should().BeGreaterOrEqualTo(2);
Expand Down Expand Up @@ -123,8 +124,9 @@ public async Task WhenUploadFileFails_AndTakesLongerThanTheRetryDuration_TheCall
var dataStream = DataStream.FromString("The Stream");
var executeScriptTask = clientAndTentacle.TentacleClient.UploadFile(remotePath, dataStream, CancellationToken, inMemoryLog);

Func<Task> action = async () => await executeScriptTask;
await action.Should().ThrowAsync<HalibutClientException>();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ConnectionFaulted, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

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

methodUsages.For(nameof(IAsyncClientFileTransferService.UploadFileAsync)).Started.Should().Be(1);
methodUsages.For(nameof(IAsyncClientFileTransferService.DownloadFileAsync)).Started.Should().Be(0);
Expand Down Expand Up @@ -183,8 +185,10 @@ public async Task WhenRpcRetriesTimeOut_DuringDownloadFile_TheRpcCallIsCancelled
var duration = Stopwatch.StartNew();
var executeScriptTask = clientAndTentacle.TentacleClient.DownloadFile(tempFile.File.FullName, CancellationToken, inMemoryLog);

Func<Task<DataStream>> action = async () => await executeScriptTask;
await action.Should().ThrowAsync<HalibutClientException>();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ConnectionFaulted, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

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

duration.Stop();

recordedUsages.For(nameof(IAsyncClientFileTransferService.DownloadFileAsync)).Started.Should().BeGreaterOrEqualTo(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ 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.ConnectionFaulted, tentacleConfigurationTestCase.TentacleType, clientTentacle).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 +84,10 @@ 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.ConnectionFaulted, tentacleConfigurationTestCase.TentacleType, clientTentacle).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
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ public async Task DuringGetCapabilities_ScriptExecutionCanBeCancelled(TentacleCo
var (_, actualException, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, ensureCancellationOccursDuringAnRpcCall);

// ASSERT
// The ExecuteScript operation threw an OperationCancelledException
actualException.Should().BeTaskOrOperationCancelledException();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ScriptExecutionCancelled, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

actualException.ShouldMatchExceptionContract(expectedException);

// If the rpc call could be cancelled then the correct error was recorded
var latestException = capabilitiesMethodUsages.For(nameof(IAsyncClientCapabilitiesServiceV2.GetCapabilitiesAsync)).LastException;
Expand Down Expand Up @@ -185,8 +186,9 @@ public async Task DuringStartScript_ScriptExecutionCanBeCancelled(TentacleConfig
var (_, actualException, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, ensureCancellationOccursDuringAnRpcCall);

// ASSERT
// The ExecuteScript operation threw an OperationCancelledException
actualException.Should().BeTaskOrOperationCancelledException();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ScriptExecutionCancelled, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

actualException.ShouldMatchExceptionContract(expectedException);

// If the rpc call could be cancelled then the correct error was recorded
var latestException = recordedUsages.For(nameof(IAsyncClientScriptServiceV2.StartScriptAsync)).LastException;
Expand Down Expand Up @@ -303,8 +305,9 @@ public async Task DuringGetStatus_ScriptExecutionCanBeCancelled(TentacleConfigur
var (_, actualException, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, ensureCancellationOccursDuringAnRpcCall);

// ASSERT
// The ExecuteScript operation threw an OperationCancelledException
actualException.Should().BeTaskOrOperationCancelledException();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ScriptExecutionCancelled, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

actualException.ShouldMatchExceptionContract(expectedException);

// If the rpc call could be cancelled then the correct error was recorded
var latestException = recordedUsages.For(nameof(IAsyncClientScriptServiceV2.GetStatusAsync)).LastException;
Expand Down Expand Up @@ -384,9 +387,13 @@ public async Task DuringCompleteScript_ScriptExecutionCanBeCancelled(TentacleCon
.Build();

// ACT
var (responseAndLogs, _, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, new SemaphoreSlim(Int32.MaxValue, Int32.MaxValue));
var (_, actualException, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, new SemaphoreSlim(int.MaxValue, int.MaxValue));

// ASSERT
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ConnectionFaulted, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

actualException.ShouldMatchExceptionContract(expectedException, Logger);

// Halibut Errors were recorded on CompleteScript
recordedUsages.For(nameof(IAsyncClientScriptServiceV2.CompleteScriptAsync)).LastException?.Should().Match<Exception>(x => x is HalibutClientException || x is OperationCanceledException || x is TaskCanceledException); // Complete Script was cancelled quickly
cancellationDuration.Should().BeLessOrEqualTo(TimeSpan.FromSeconds(30));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ public async Task DuringGetCapabilities_ScriptExecutionCanBeCancelled(TentacleCo
var (_, actualException, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, ensureCancellationOccursDuringAnRpcCall);

// ASSERT
// The ExecuteScript operation threw an OperationCancelledException
actualException.Should().BeTaskOrOperationCancelledException();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ConnectionFaulted, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

actualException.ShouldMatchExceptionContract(expectedException);

// If the rpc call could be cancelled then the correct error was recorded
var latestException = capabilitiesMethodUsages.For(nameof(IAsyncClientCapabilitiesServiceV2.GetCapabilitiesAsync)).LastException;
Expand Down Expand Up @@ -235,8 +236,9 @@ public async Task DuringStartScript_ScriptExecutionCanBeCancelled(TentacleConfig
var (_, actualException, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, ensureCancellationOccursDuringAnRpcCall);

// ASSERT
// The ExecuteScript operation threw an OperationCancelledException
actualException.Should().BeTaskOrOperationCancelledException();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ScriptExecutionCancelled, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

actualException.ShouldMatchExceptionContract(expectedException);

// If the rpc call could be cancelled then the correct error was recorded
var latestException = recordedUsages.For(nameof(IAsyncClientScriptServiceV2.StartScriptAsync)).LastException;
Expand Down Expand Up @@ -390,8 +392,9 @@ public async Task DuringGetStatus_ScriptExecutionCanBeCancelled(TentacleConfigur
var (_, actualException, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, ensureCancellationOccursDuringAnRpcCall);

// ASSERT
// The ExecuteScript operation threw an OperationCancelledException
actualException.Should().BeTaskOrOperationCancelledException();
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ScriptExecutionCancelled, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

actualException.ShouldMatchExceptionContract(expectedException);

// If the rpc call could be cancelled then the correct error was recorded
var latestException = recordedUsages.For(nameof(IAsyncClientScriptServiceV2.GetStatusAsync)).LastException;
Expand Down Expand Up @@ -483,9 +486,13 @@ public async Task DuringCompleteScript_ScriptExecutionCanBeCancelled(TentacleCon
.Build();

// ACT
var (responseAndLogs, _, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, new SemaphoreSlim(int.MaxValue, int.MaxValue));
var (responseAndLogs, actualException, cancellationDuration) = await ExecuteScriptThenCancelExecutionWhenRpcCallHasStarted(clientAndTentacle, startScriptCommand, rpcCallHasStarted, new SemaphoreSlim(int.MaxValue, int.MaxValue));

// ASSERT
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ScriptExecutionCancelled, tentacleConfigurationTestCase.TentacleType, clientAndTentacle).Build();

actualException.ShouldMatchExceptionContract(expectedException);

// Halibut Errors were recorded on CompleteScript
recordedUsages.For(nameof(IAsyncClientScriptServiceV2.CompleteScriptAsync)).LastException?.Should().Match<Exception>(x => x is HalibutClientException || x is OperationCanceledException || x is TaskCanceledException);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,9 @@ await clientTentacle.TentacleClient.ExecuteScript(startScriptCommand,
actualException = ex;
}

actualException.Should().NotBeNull().And.BeOfType<OperationCanceledException>().And.Match<Exception>(x => x.Message == "Script execution was cancelled");
var expectedException = new ExceptionContractAssertionBuilder(FailureScenario.ScriptExecutionCancelled, tentacleConfigurationTestCase.TentacleType, clientTentacle).Build();

actualException!.ShouldMatchExceptionContract(expectedException);

var allLogs = logs.JoinLogs();
allLogs.Should().Contain("hello");
Expand Down
Loading

0 comments on commit f810686

Please sign in to comment.