Skip to content

Commit

Permalink
Merge pull request #1100 from opentap/main
Browse files Browse the repository at this point in the history
9.21.0 RC
  • Loading branch information
alnlarsen committed Apr 24, 2023
2 parents c219117 + 84c4680 commit 7185ecc
Show file tree
Hide file tree
Showing 30 changed files with 698 additions and 501 deletions.
2 changes: 1 addition & 1 deletion .gitversion
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# This is the version number that will be used. Prerelease numbers are calculated by
# counting git commits since the last change in this value.
version = 9.20.4
version = 9.21.0

# A version is determined to be a "beta" prerelease if it originates from the default branch
# The default branch is the first branch that matches the following regular expession.
Expand Down
3 changes: 0 additions & 3 deletions BasicSteps/DialogStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,20 @@ public enum InputButtons
YesNo
}

[Obfuscation(Exclude = true, ApplyToMembers =true)]
enum WaitForInputResult1
{
// The order of the results determines the order in which the buttons is shown in the dialog box.
// The number assigned, determines the default value.
No = 2, Yes = 1
}

[Obfuscation(Exclude = true, ApplyToMembers = true)]
enum WaitForInputResult2
{
// The order of the results determines the order in which the buttons is shown in the dialog box.
// The number assigned, determines the default value.
Cancel = 2, Ok = 1
}

[Obfuscation(Exclude = true, ApplyToMembers = true)]
class DialogRequest : IDisplayAnnotation
{
public DialogRequest(string Title, string Message)
Expand Down
11 changes: 6 additions & 5 deletions Engine.UnitTests/DefaultPictureDataProviderTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
Expand Down Expand Up @@ -88,16 +89,16 @@ public async Task TestWebPicture()
{
for (int i = 0; i < 2; i++)
{
var client = listener.AcceptTcpClient();
var stream = client.GetStream();
using var client = listener.AcceptTcpClient();
using var stream = client.GetStream();
var header = $"HTTP/1.0 200 OK\r\nContent-Length: {fileContent.Length}\r\n\r\n";
stream.Write(Encoding.UTF8.GetBytes(header), 0, header.Length);
stream.Write(fileContent, 0, fileContent.Length);
// Ensure the client has finished downloading the resource before this thread's resources are disposed
TapThread.Sleep(TimeSpan.FromSeconds(1));
}
});



var pic = new Picture() {Source = source, Description = "Test Picture"};

// Ensure filenames and types are correct
Expand Down
54 changes: 54 additions & 0 deletions Engine.UnitTests/ResourceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using NUnit.Framework;
using OpenTap.Diagnostic;
using OpenTap.Engine.UnitTests;
Expand Down Expand Up @@ -85,6 +86,59 @@ public override void Run()
Assert.IsFalse(SomeInstrument.IsConnected);
}
}

public class SlowOpenInstrument : IInstrument
{
public event PropertyChangedEventHandler PropertyChanged;
public string Name { get; set; }
public void Open()
{
var trd = TapThread.Current;
while (trd != null)
{
if (trd.Name == "Plan Thread")
break;
trd = trd.Parent;
}
Assert.That(trd, Is.Not.Null);

var cancel = new CancellationTokenSource(TimeSpan.FromSeconds(2));
WasStopped = false;
int handle = WaitHandle.WaitAny(new[] { TapThread.Current.AbortToken.WaitHandle, cancel.Token.WaitHandle });
WasStopped = handle == 0;
}

public void Close()
{

}

public bool IsConnected => true;
public bool WasStopped { get; set; }
}

[Test]
public void SlowOpenInstrumentTest([Values(false, true)] bool UseLazyResourceManager)
{
using var session = Session.Create(SessionOptions.OverlayComponentSettings);
IResourceManager manager =
UseLazyResourceManager ? (IResourceManager)new LazyResourceManager() : new ResourceTaskManager();
EngineSettings.Current.ResourceManagerType = manager;

var instrument = new SlowOpenInstrument();
var step = new ResourceTestStep {MyTestResource = instrument, ResourceEnabled = true};
var plan = new TestPlan()
{
ChildTestSteps = { step }
};

Assert.IsFalse(instrument.WasStopped);
var abortToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000));
var run = plan.ExecuteAsync(abortToken.Token);
abortToken.Token.WaitHandle.WaitOne();
TapThread.Sleep(TimeSpan.FromSeconds(1));
Assert.IsTrue(instrument.WasStopped);
}


[Test]
Expand Down
31 changes: 31 additions & 0 deletions Engine.UnitTests/TapThreadTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;

namespace OpenTap.UnitTests
Expand Down Expand Up @@ -96,6 +97,36 @@ public void TestHierarchyCompleted2()
Assert.IsTrue(level2CompletedBeforeHierarchyCompletedCallback, "Second level child thread did not complete before onHierarchyCompleted callback.");
}

[Test]
public async Task TestAwaitedThreadThrows([Values(true, false)] bool throws)
{
void callback()
{
if (throws)
throw new Exception("Throws");
}

var trd = TapThread.StartAwaitable(callback);

if (throws)
{
try
{
await trd;
Assert.Fail("This should have thrown.");
}
catch (Exception ex)
{
StringAssert.Contains("Throws", ex.Message);
}
}
else
{
await trd;
Assert.Pass();
}
}

/// <summary>
/// Test what happens when sibling threads gets aborted - verify that only the right ones are aborted.
/// </summary>
Expand Down
3 changes: 2 additions & 1 deletion Engine.UnitTests/TestPlanTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2001,7 +2001,7 @@ public override void Open()
isopening = true;

if(OpenWait)
TapThread.Sleep(20);
Thread.Sleep(20);

isopening = false;

Expand Down Expand Up @@ -2115,6 +2115,7 @@ void newThread()
}

[Test]
[Repeat(10)]
public void OpenCloseOrderLazyRM()
{
var lastrm = EngineSettings.Current.ResourceManagerType;
Expand Down
11 changes: 5 additions & 6 deletions Engine/Authentication/AuthenticationSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void PrepareRequest(HttpRequestMessage request, string domain, CancellationToken
public HttpClient GetClient(string domain = null, bool withRetryPolicy = false, string baseAddress = null)
{
if (Uri.IsWellFormedUriString(domain, UriKind.Absolute))
throw new ArgumentException("Domain should only be the host part of a URI and not a full absolute URI.", "domain");
throw new ArgumentException("Domain should only be the host part of a URI and not a full absolute URI.", nameof(domain));
var client = new HttpClient(new AuthenticationClientHandler(domain, withRetryPolicy));
if (baseAddress != null)
{
Expand All @@ -130,9 +130,9 @@ public HttpClient GetClient(string domain = null, bool withRetryPolicy = false,
if (BaseAddress != null)
client.BaseAddress = new Uri(new Uri(BaseAddress), baseAddress);
else
throw new ArgumentException("Address cannot be relative when AuthenticationSettings.BaseAddress is null.", "baseAddress");
throw new ArgumentException("Address cannot be relative when AuthenticationSettings.BaseAddress is null.", nameof(baseAddress));
else
throw new ArgumentException("Address must be a well formed URL or null.", "baseAddress");
throw new ArgumentException("Address must be a well formed URL or null.", nameof(baseAddress));
}
else if(BaseAddress != null)
client.BaseAddress = new Uri(BaseAddress);
Expand Down Expand Up @@ -161,9 +161,8 @@ public HttpClient GetClient(string domain = null, bool withRetryPolicy = false,
}
}
}
var callingUseAgent = userAgent;
var asm2 = Assembly.GetCallingAssembly();
if (asm2 != null)
var callingUseAgent = userAgent;
if (Assembly.GetCallingAssembly() is Assembly asm2)
{
var assemblyData = PluginManager.GetSearcher().Assemblies.FirstOrDefault(ad => ad.Location == asm2.Location);
if (assemblyData?.SemanticVersion is SemanticVersion ver)
Expand Down
1 change: 1 addition & 0 deletions Engine/Authentication/TokenInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Xml.Serialization;

Expand Down
36 changes: 17 additions & 19 deletions Engine/ResourceTaskManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,11 @@ internal static TraceSource GetLogSource(IResource res)
return Log.GetOwnedSource(res) ?? Log.CreateSource(res.Name ?? "Resource");
}

async Task OpenResource(ResourceNode node, Task canStart)
void OpenResource(ResourceNode node, WaitHandle canStart)
{
await canStart;
foreach (var dep in node.StrongDependencies)
await openTasks[dep];
canStart.WaitOne();
var taskArray = node.StrongDependencies.Select(dep => openTasks[dep]).ToArray();
Task.WaitAll(taskArray);

Stopwatch swatch = Stopwatch.StartNew();

Expand All @@ -254,12 +254,12 @@ async Task OpenResource(ResourceNode node, Task canStart)
try
{
// start a new thread to do synchronous work
await Task.Factory.StartNew(node.Resource.Open);
node.Resource.Open();

reslog.Info(swatch, "Resource \"{0}\" opened.", node.Resource);

foreach (var dep in node.WeakDependencies)
await openTasks[dep];
var weakDeps = node.WeakDependencies.Select(dep => openTasks[dep]).ToArray();
Task.WaitAll(weakDeps);

ResourceOpened?.Invoke(node.Resource);
}
Expand Down Expand Up @@ -421,17 +421,17 @@ void BeginOpenResources(List<ResourceNode> resources, CancellationToken cancella
else
{
// Open all resources asynchronously
Task wait = new Task(() => { }); // This task is not started yet, so it's used as an awaitable semaphore.
var wait = new ManualResetEventSlim(false);
foreach (ResourceNode r in resources)
{
if (openTasks.ContainsKey(r.Resource)) continue;

openedResources.Add(r);

// async used to avoid blocking the thread while waiting for tasks.
openTasks[r.Resource] = OpenResource(r, wait);
openTasks[r.Resource] = TapThread.StartAwaitable(() => OpenResource(r, wait.WaitHandle));
}
wait.Start();
wait.Set();
}
}

Expand Down Expand Up @@ -566,13 +566,13 @@ public bool ShouldBeOpen()
return ReferenceCount > 0;
}

async Task OpenResource(LazyResourceManager requester, CancellationToken cancellationToken)
void OpenResource(LazyResourceManager requester, CancellationToken cancellationToken)
{
var node = ResourceNode;
foreach (var dep in node.StrongDependencies)
{
if (dep == null) continue;
await requester.RequestResourceOpen(dep, cancellationToken);
requester.RequestResourceOpen(dep, cancellationToken).Wait(cancellationToken);
}

Stopwatch swatch = Stopwatch.StartNew();
Expand All @@ -583,11 +583,8 @@ async Task OpenResource(LazyResourceManager requester, CancellationToken cancell
{
try
{
// start a new thread to do synchronous work
await Task.Factory.StartNew(node.Resource.Open);

node.Resource.Open();
reslog.Info(swatch, "Resource \"{0}\" opened.", node.Resource);

}
finally
{
Expand All @@ -599,7 +596,7 @@ async Task OpenResource(LazyResourceManager requester, CancellationToken cancell
foreach (var dep in node.WeakDependencies)
{
if (dep == null) continue;
await requester.RequestResourceOpen(dep, cancellationToken);
requester.RequestResourceOpen(dep, cancellationToken).Wait(cancellationToken);
}
}
catch (Exception ex)
Expand All @@ -621,7 +618,8 @@ public Task RequestOpen(LazyResourceManager requester, CancellationToken cancell
case ResourceState.Reset:
state = ResourceState.Opening;

return OpenTask = OpenResource(requester, cancellationToken);
return OpenTask =
TapThread.StartAwaitable(() => OpenResource(requester, cancellationToken));
case ResourceState.Opening:
return OpenTask;
case ResourceState.Open:
Expand Down Expand Up @@ -651,7 +649,7 @@ public Task RequestClose(LazyResourceManager requester)
{
state = ResourceState.Closing;

return CloseTask = Task.Factory.StartNew(() =>
return CloseTask = TapThread.StartAwaitable(() =>
{
try
{
Expand Down
Loading

0 comments on commit 7185ecc

Please sign in to comment.