Made send of test case list non-blocking

This commit is contained in:
Jared Parsons 2015-08-21 13:36:36 -07:00
Родитель 4fe71ae114
Коммит ad66e46217
8 изменённых файлов: 105 добавлений и 49 удалений

Просмотреть файл

@ -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>