Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment9+10: Tyler + Austin #87

Open
wants to merge 86 commits into
base: Assignment9+10-Multithreading
Choose a base branch
from

Conversation

twoody0
Copy link

@twoody0 twoody0 commented Dec 11, 2024

Partnered with @AustinH5544

twoody0 and others added 30 commits November 30, 2024 12:50
RunAsync_UsingTplWithCancellation_CatchAggregateExceptionWrapping()
RunAsync_UsingTplWithCancellation_CatchAggregateExceptionWrappingTaskCanceledException()
Copy link

@LeoMarlow LeoMarlow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice work boys! I only found one issue thats sort of a non issue ? I think that your returning the wrong type of exemption with the cancelation. It seems to work tho anyway.
Anyway any extra detail is left in comments -L

Implement PingProcess' public Task RunTaskAsync(string hostNameOrAddress) ✔
First implement public void RunTaskAsync_Success() test method to test PingProcess.RunTaskAsync() using "localhost". ✔
Do NOT use async/await in this implementation. ✔
Implement PingProcess' async public Task RunAsync(string hostNameOrAddress) ✔
First implement the public void RunAsync_UsingTaskReturn_Success() test method to test PingProcess.RunAsync() using "localhost" without using async/await. ✔
Also implement the async public Task RunAsync_UsingTpl_Success() test method to test PingProcess.RunAsync() using "localhost" but this time DO using async/await. ✔
Add support for an optional cancellation token to the PingProcess.RunAsync() signature. ✔
Inside the PingProcess.RunAsync() invoke the token's ThrowIfCancellationRequested() method so an exception is thrown. ✔
Test that, when cancelled from the test method, the exception thrown is an AggregateException ✔/ ?
with a TaskCanceledException inner exception ✔/ ?
using the test methods RunAsync_UsingTplWithCancellation_CatchAggregateExceptionWrapping ✔
and RunAsync_UsingTplWithCancellation_CatchAggregateExceptionWrappingTaskCanceledException ✔ respectively.
Complete/fix AND test async public Task RunAsync(IEnumerable hostNameOrAddresses, CancellationToken cancellationToken = default) which executes ping for an array of hostNameOrAddresses (which can all be "localhost") in parallel, adding synchronization if needed. ✔
NOTE:
The order of the items in the stdOutput is irrelevant and expected to be intermingled.
StdOutput must have all the ping output returned (no lines can be missing) even though intermingled. ✔
Implement AND test public Task RunLongRunningAsync(ProcessStartInfo startInfo, Action<string?>? progressOutput, Action<string?>? progressError, CancellationToken token) using Task.Factory.StartNew() and invoking RunProcessInternal with a TaskCreation value of TaskCreationOptions.LongRunning and a TaskScheduler value of TaskScheduler.Current. Returning a Task is also okay.
NOTE: This method does NOT use Task.Run. ✔
Extra Credit
Test and implement PingProcess.RunAsync(System.IProgress progess) so that you can capture the output as it occurs rather than capturing the output only when the process finishes. ❌
Fundamentals
Place all shared project properties into a Directory.Build.Props file.✔
Place all shared project items into a Directory.Build.targets file.✔
Ensure nullable reference types is enabled ✔
Ensure that you turn on code analysis for all projects(EnableNETAnalyzers) ✔
Set LangVersion and the TargetFramework to the latest released versions available (preview versions optional) ✔
and enabled .NET analyzers for both projects ✔
For this assignment, consider using Assert.AreEqual() (the generic version) ✔
All of the above should be unit tested ✔
Choose simplicity over complexity ✔

Assignment.Tests/PingProcessTests.cs Show resolved Hide resolved
Assignment/PingProcess.cs Show resolved Hide resolved
}

[TestMethod]
[ExpectedException(typeof(AggregateException))]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im not sure how you made this work. I had to flatten and rethrow as AggregateException here. When you cancel it should return a cancelationException

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that it was an aggregate exception until you flatten it and pull out the inner exception, but we will look more into it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I am aware, any errors caused within a task results in an aggregate exception

catch (AggregateException ex)
{
AggregateException flattened = ex.Flatten();
Assert.IsTrue(flattened.InnerExceptions.Any(e => e is TaskCanceledException),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may be backwards CanceledExemption should be the default and Aggregate should be the one you flatten. It works like this but is kinda confusing

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is my understanding that you flatten the Aggregate to get the TaskCanceledException but I could be wrong. I will look more into it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here they catch an aggregate exception and flatten it. A flattened aggregate is still an aggregate exception. They then call the inner exceptions and check if it is a TaskCanceled Exception, which should be fine.

Copy link

@BDullanty BDullanty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Implement PingProcess' public Task<PingResult> RunTaskAsync(string hostNameOrAddress)
    • First implement public void RunTaskAsync_Success() test method to test PingProcess.RunTaskAsync() using "localhost". ✔
    • Do NOT use async/await in this implementation. ✔
  2. Implement PingProcess' async public Task<PingResult> RunAsync(string hostNameOrAddress)
    • First implement the public void RunAsync_UsingTaskReturn_Success() test method to test PingProcess.RunAsync() using "localhost" without using async/await. ✔
    • Also implement the async public Task RunAsync_UsingTpl_Success() test method to test PingProcess.RunAsync() using "localhost" but this time DO using async/await. ✔
  3. Add support for an optional cancellation token to the PingProcess.RunAsync() signature. ✔
  • Inside the PingProcess.RunAsync() invoke the token's ThrowIfCancellationRequested() method so an exception is thrown. ✔
  • Test that, when cancelled from the test method, the exception thrown is an AggregateException
    • with a TaskCanceledException inner exception ✔
    • using the test methods RunAsync_UsingTplWithCancellation_CatchAggregateExceptionWrapping
    • and RunAsync_UsingTplWithCancellation_CatchAggregateExceptionWrappingTaskCanceledException ✔ respectively.
  1. Complete/fix AND test async public Task<PingResult> RunAsync(IEnumerable<string> hostNameOrAddresses, CancellationToken cancellationToken = default) which executes ping for an array of hostNameOrAddresses (which can all be "localhost") in parallel, adding synchronization if needed. ✔
    NOTE:
    • The order of the items in the stdOutput is irrelevant and expected to be intermingled.
    • StdOutput must have all the ping output returned (no lines can be missing) even though intermingled. ❌
  2. Implement AND test public Task<int> RunLongRunningAsync(ProcessStartInfo startInfo, Action<string?>? progressOutput, Action<string?>? progressError, CancellationToken token) using Task.Factory.StartNew() and invoking RunProcessInternal with a TaskCreation value of TaskCreationOptions.LongRunning and a TaskScheduler value of TaskScheduler.Current. Returning a Task<PingResult> is also okay.✔
    NOTE: This method does NOT use Task.Run.✔

Extra Credit

  • Test and implement PingProcess.RunAsync(System.IProgress<T> progess) so that you can capture the output as it occurs rather than capturing the output only when the process finishes. ❌✔

Fundamentals

  • Place all shared project properties into a Directory.Build.Props file.✔
  • Place all shared project items into a Directory.Build.targets file.✔
  • Ensure nullable reference types is enabled ✔
  • Ensure that you turn on code analysis for all projects(EnableNETAnalyzers) ✔
  • Set LangVersion and the TargetFramework to the latest released versions available (preview versions optional) ✔
  • and enabled .NET analyzers for both projects ✔
  • For this assignment, consider using Assert.AreEqual<T>() (the generic version) ✔
  • All of the above should be unit tested ✔
  • Choose simplicity over complexity ✔

Good work :)

}

[TestMethod]
[ExpectedException(typeof(AggregateException))]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I am aware, any errors caused within a task results in an aggregate exception

Assignment.Tests/PingProcessTests.cs Show resolved Hide resolved
catch (AggregateException ex)
{
AggregateException flattened = ex.Flatten();
Assert.IsTrue(flattened.InnerExceptions.Any(e => e is TaskCanceledException),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here they catch an aggregate exception and flatten it. A flattened aggregate is still an aggregate exception. They then call the inner exceptions and check if it is a TaskCanceled Exception, which should be fine.

Assignment.Tests/PingProcessTests.cs Outdated Show resolved Hide resolved
void updateStdOutput(string? line) =>
(stringBuilder ??= new StringBuilder()).AppendLine(line);

Process process = RunProcessInternal(StartInfo, updateStdOutput, null, cancellationToken);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add this within the Task.Run itself

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts on why it should be inside?


// Act
Task task = Sut.RunAsync("localhost -c 4").ContinueWith(t => result = t.Result);
task.Wait();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than continue with, perhaps using task.Wait() then just referring to task.Result may be easier to read

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look into this. In your opinion would it just be easier or is it functionally better?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed that, I do feel like it's slightly more readable


// Assert
Assert.IsFalse(string.IsNullOrWhiteSpace(result.StdOutput));
Assert.AreEqual(0, result.ExitCode);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  - StdOutput must have all the ping output returned (no lines can be missing) even though intermingled. ❌
  
  Perhaps set a static number (like 9 * 4) based on Linux and check for that amount of lines

Copy link

@AustinH5544 AustinH5544 Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We changed it, thanks for the input!

Copy link

Summary

Summary
Generated on: 12/13/2024 - 00:43:58
Coverage date: 12/13/2024 - 00:43:56
Parser: MultiReport (2x Cobertura)
Assemblies: 1
Classes: 2
Files: 1
Line coverage: 91.6% (121 of 132)
Covered lines: 121
Uncovered lines: 11
Coverable lines: 132
Total lines: 200
Branch coverage: 75% (30 of 40)
Covered branches: 30
Total branches: 40
Method coverage: Feature is only available for sponsors
Tag: 1034_12307384732

Coverage

Assignment - 91.6%
Name Line Branch
Assignment 91.6% 75%
Assignment.PingProcess 91.6% 75%
Assignment.PingResult 100%

Copy link

@KennethWhite KennethWhite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Looks like you knocked out all the assignment criteria, great code coverage as well! Also nice work on testing for the TaskCanceledException within the AggregateException without trying to rethrow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants