Made send of test case list non-blocking
This commit is contained in:
Родитель
4fe71ae114
Коммит
ad66e46217
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -26,7 +27,7 @@ namespace xunit.runner.wpf
|
|||
/// <summary>
|
||||
/// Begin a run of specific unit tests for the given assembly.
|
||||
/// </summary>
|
||||
ITestRunSession RunSpecific(string assemblyPath, IEnumerable<string> testCaseDisplayNames, CancellationToken cancellationToken = default(CancellationToken));
|
||||
ITestRunSession RunSpecific(string assemblyPath, ImmutableArray<string> testCaseDisplayNames, CancellationToken cancellationToken = default(CancellationToken));
|
||||
}
|
||||
|
||||
internal interface ITestSession
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
|
@ -16,6 +17,43 @@ namespace xunit.runner.wpf.Impl
|
|||
{
|
||||
internal partial class RemoteTestUtil
|
||||
{
|
||||
private sealed class BackgroundWriter<T>
|
||||
{
|
||||
private readonly ClientWriter _writer;
|
||||
private readonly ImmutableArray<T> _data;
|
||||
private readonly Action<ClientWriter, T> _writeValue;
|
||||
private readonly CancellationToken _cancellationToken;
|
||||
|
||||
internal BackgroundWriter(ClientWriter writer, ImmutableArray<T> data, Action<ClientWriter, T> writeValue, CancellationToken cancellationToken)
|
||||
{
|
||||
_writer = writer;
|
||||
_writeValue = writeValue;
|
||||
_data = data;
|
||||
_cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
internal Task WriteAsync()
|
||||
{
|
||||
return Task.Run(() => GoOnBackground(), _cancellationToken);
|
||||
}
|
||||
|
||||
private void GoOnBackground()
|
||||
{
|
||||
foreach (var item in _data)
|
||||
{
|
||||
if (_cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
_writer.Write(TestDataKind.Value);
|
||||
_writeValue(_writer, item);
|
||||
}
|
||||
|
||||
_writer.Write(TestDataKind.EndOfData);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class BackgroundReader<T> where T : class
|
||||
{
|
||||
private readonly ConcurrentQueue<T> _queue;
|
||||
|
@ -25,7 +63,7 @@ namespace xunit.runner.wpf.Impl
|
|||
|
||||
internal ClientReader Reader => _reader;
|
||||
|
||||
private BackgroundReader(ConcurrentQueue<T> queue, ClientReader reader, Func<ClientReader, T> readValue, CancellationToken cancellationToken)
|
||||
internal BackgroundReader(ConcurrentQueue<T> queue, ClientReader reader, Func<ClientReader, T> readValue, CancellationToken cancellationToken)
|
||||
{
|
||||
_queue = queue;
|
||||
_reader = reader;
|
||||
|
@ -33,10 +71,9 @@ namespace xunit.runner.wpf.Impl
|
|||
_cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
internal static void Go(ConcurrentQueue<T> queue, ClientReader reader, Func<ClientReader, T> readValue, CancellationToken cancellationToken)
|
||||
internal Task ReadAsync()
|
||||
{
|
||||
var impl = new BackgroundReader<T>(queue, reader, readValue, cancellationToken);
|
||||
Task.Run(impl.GoOnBackground);
|
||||
return Task.Run(() => GoOnBackground(), _cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -44,7 +81,7 @@ namespace xunit.runner.wpf.Impl
|
|||
/// named pipe client stream.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal Task GoOnBackground()
|
||||
private void GoOnBackground()
|
||||
{
|
||||
while (!_cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
|
@ -69,8 +106,6 @@ namespace xunit.runner.wpf.Impl
|
|||
|
||||
// Signal we are done
|
||||
_queue.Enqueue(null);
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,17 +122,16 @@ namespace xunit.runner.wpf.Impl
|
|||
|
||||
internal Task Task => _taskCompletionSource.Task;
|
||||
|
||||
private BackgroundProducer(
|
||||
internal BackgroundProducer(
|
||||
Connection connection,
|
||||
Dispatcher dispatcher,
|
||||
Func<ClientReader, T> readValue,
|
||||
ConcurrentQueue<T> queue,
|
||||
Action<List<T>> callback,
|
||||
int maxResultPerTick = MaxResultPerTick,
|
||||
TimeSpan? interval = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
TimeSpan? interval = null)
|
||||
{
|
||||
_connection = connection;
|
||||
_queue = new ConcurrentQueue<T>();
|
||||
_queue = queue;
|
||||
_maxPerTick = maxResultPerTick;
|
||||
_callback = callback;
|
||||
_timer = new DispatcherTimer(
|
||||
|
@ -106,19 +140,6 @@ namespace xunit.runner.wpf.Impl
|
|||
OnTimerTick,
|
||||
dispatcher);
|
||||
_taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
|
||||
BackgroundReader<T>.Go(_queue, connection.Reader, readValue, cancellationToken);
|
||||
}
|
||||
|
||||
internal static Task Go(
|
||||
Connection connection,
|
||||
Dispatcher dispatcher,
|
||||
Func<ClientReader, T> readValue,
|
||||
Action<List<T>> callback,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var producer = new BackgroundProducer<T>(connection, dispatcher, readValue, callback, cancellationToken: cancellationToken);
|
||||
return producer.Task;
|
||||
}
|
||||
|
||||
private void OnTimerTick(object sender, EventArgs e)
|
||||
|
|
|
@ -24,7 +24,12 @@ namespace xunit.runner.wpf.Impl
|
|||
|
||||
internal DiscoverSession(Connection connection, Dispatcher dispatcher, CancellationToken cancellationToken)
|
||||
{
|
||||
_task = BackgroundProducer<TestCaseData>.Go(connection, dispatcher, r => r.ReadTestCaseData(), OnDiscovered, cancellationToken);
|
||||
var queue = new ConcurrentQueue<TestCaseData>();
|
||||
var backgroundReader = new BackgroundReader<TestCaseData>(queue, new ClientReader(connection.Stream), r => r.ReadTestCaseData(), cancellationToken);
|
||||
backgroundReader.ReadAsync();
|
||||
|
||||
var backgroundProducer = new BackgroundProducer<TestCaseData>(connection, dispatcher, queue, OnDiscovered);
|
||||
_task = backgroundProducer.Task;
|
||||
}
|
||||
|
||||
private void OnDiscovered(List<TestCaseData> list)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
|
@ -22,12 +23,47 @@ namespace xunit.runner.wpf.Impl
|
|||
private event EventHandler<TestResultDataEventArgs> _testFinished;
|
||||
private event EventHandler _sessionFinished;
|
||||
|
||||
internal RunSession(Connection connection, Dispatcher dispatcher, CancellationToken cancellationToken)
|
||||
internal RunSession(Connection connection, Dispatcher dispatcher, ImmutableArray<string> testCaseDisplayNames, CancellationToken cancellationToken)
|
||||
{
|
||||
_task = BackgroundProducer<TestResultData>.Go(connection, dispatcher, r => r.ReadTestResultData(), OnFinished, cancellationToken);
|
||||
var queue = CreateQueue(connection, testCaseDisplayNames, cancellationToken);
|
||||
var backgroundProducer = new BackgroundProducer<TestResultData>(connection, dispatcher, queue, OnDataProduced);
|
||||
_task = backgroundProducer.Task;
|
||||
}
|
||||
|
||||
private void OnFinished(List<TestResultData> list)
|
||||
/// <summary>
|
||||
/// Create the <see cref="ConcurrentQueue{T}"/> which will be populated with the <see cref="TestResultData"/>
|
||||
/// as it arrives from the worker.
|
||||
/// </summary>
|
||||
private static ConcurrentQueue<TestResultData> CreateQueue(Connection connection, ImmutableArray<string> testCaseDisplayNames, CancellationToken cancellationToken)
|
||||
{
|
||||
var queue = new ConcurrentQueue<TestResultData>();
|
||||
var unused = CreateQueueCore(queue, connection, testCaseDisplayNames, cancellationToken);
|
||||
return queue;
|
||||
}
|
||||
|
||||
private static async Task CreateQueueCore(ConcurrentQueue<TestResultData> queue, Connection connection, ImmutableArray<string> testCaseDisplayNames, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!testCaseDisplayNames.IsDefaultOrEmpty)
|
||||
{
|
||||
var backgroundWriter = new BackgroundWriter<string>(new ClientWriter(connection.Stream), testCaseDisplayNames, (w, s) => w.Write(s), cancellationToken);
|
||||
await backgroundWriter.WriteAsync();
|
||||
}
|
||||
|
||||
var backgroundReader = new BackgroundReader<TestResultData>(queue, new ClientReader(connection.Stream), r => r.ReadTestResultData(), cancellationToken);
|
||||
await backgroundReader.ReadAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.Fail(ex.Message);
|
||||
|
||||
// Signal data completed
|
||||
queue.Enqueue(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDataProduced(List<TestResultData> list)
|
||||
{
|
||||
Debug.Assert(!_task.IsCompleted);
|
||||
if (list == null)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
|
@ -54,27 +55,13 @@ namespace xunit.runner.wpf.Impl
|
|||
private RunSession RunAll(string assemblyPath, CancellationToken cancellationToken)
|
||||
{
|
||||
var connection = StartWorkerProcess(Constants.ActionRunAll, assemblyPath);
|
||||
return new RunSession(connection, _dispatcher, cancellationToken);
|
||||
return new RunSession(connection, _dispatcher, ImmutableArray<string>.Empty, cancellationToken);
|
||||
}
|
||||
|
||||
private RunSession RunSpecific(string assemblyPath, IEnumerable<string> testCaseDisplayNames, CancellationToken cancellationToken)
|
||||
private RunSession RunSpecific(string assemblyPath, ImmutableArray<string> testCaseDisplayNames, CancellationToken cancellationToken)
|
||||
{
|
||||
var connection = StartWorkerProcess(Constants.ActionRunSpecific, assemblyPath);
|
||||
|
||||
// First send along all of the test cases to run
|
||||
using (var writer = new ClientWriter(connection.Stream))
|
||||
{
|
||||
foreach (var cur in testCaseDisplayNames)
|
||||
{
|
||||
writer.Write(TestDataKind.Value);
|
||||
writer.Write(cur);
|
||||
}
|
||||
|
||||
writer.Write(TestDataKind.EndOfData);
|
||||
}
|
||||
|
||||
// Now wait for the results as we normally would
|
||||
return new RunSession(connection, _dispatcher, cancellationToken);
|
||||
return new RunSession(connection, _dispatcher, testCaseDisplayNames, cancellationToken);
|
||||
}
|
||||
|
||||
#region ITestUtil
|
||||
|
@ -89,7 +76,7 @@ namespace xunit.runner.wpf.Impl
|
|||
return RunAll(assemblyPath, cancellationToken);
|
||||
}
|
||||
|
||||
ITestRunSession ITestUtil.RunSpecific(string assemblyPath, IEnumerable<string> testCaseDisplayNames, CancellationToken cancellationToken)
|
||||
ITestRunSession ITestUtil.RunSpecific(string assemblyPath, ImmutableArray<string> testCaseDisplayNames, CancellationToken cancellationToken)
|
||||
{
|
||||
return RunSpecific(assemblyPath, testCaseDisplayNames, cancellationToken);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Windows;
|
|||
using GalaSoft.MvvmLight.CommandWpf;
|
||||
using Microsoft.Win32;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Collections.Specialized;
|
||||
|
@ -348,7 +349,7 @@ namespace xunit.runner.wpf.ViewModel
|
|||
var testCaseDisplayNames = TestCases
|
||||
.Where(x => x.AssemblyFileName == assemblyPath)
|
||||
.Select(x => x.DisplayName)
|
||||
.ToList();
|
||||
.ToImmutableArray();
|
||||
session = this.testUtil.RunSpecific(assemblyPath, testCaseDisplayNames, this.cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<package id="CommonServiceLocator" version="1.3" targetFramework="net452" />
|
||||
<package id="MvvmLight" version="5.1.1.0" targetFramework="net452" />
|
||||
<package id="MvvmLightLibs" version="5.1.1.0" targetFramework="net452" />
|
||||
<package id="System.Collections.Immutable" version="1.1.37" targetFramework="net452" />
|
||||
<package id="xunit.abstractions" version="2.0.0" targetFramework="net452" />
|
||||
<package id="xunit.runner.utility" version="2.1.0-beta4-build3109" targetFramework="net452" />
|
||||
</packages>
|
|
@ -54,6 +54,10 @@
|
|||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.1.37.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MvvmLightLibs.5.1.1.0\lib\net45\System.Windows.Interactivity.dll</HintPath>
|
||||
|
|
Загрузка…
Ссылка в новой задаче