Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 73ed308

Browse files
Cristian PopCristian Pop
authored andcommitted
Adding parallel test execution script.
Several System.Net.Security test fixes.
1 parent 0444706 commit 73ed308

File tree

13 files changed

+326
-65
lines changed

13 files changed

+326
-65
lines changed
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
# Licensed to the .NET Foundation under one or more agreements.
2+
# The .NET Foundation licenses this file to you under the MIT license.
3+
# See the LICENSE file in the project root for more information.
4+
5+
# Usage:
6+
#
7+
# . ParallelTestExecution.ps1
8+
# cd <testFolder> (e.g. testFolder = src\System.Net.Security\tests\FunctionalTests)
9+
# RunMultiple <n> <delayVarianceMilliseconds> [-UntilFailed]
10+
#
11+
# The above sequence will open up <n> windows running the test project present in the current folder.
12+
# If -UntilFailed is used, the tests will continuously loop until a failure is detected.
13+
# Between loops, the execution will pause for <delayVarianceMilliseconds>.
14+
15+
function BuildAndTestBinary
16+
{
17+
$output = (msbuild /t:rebuild,test)
18+
if ($lastexitcode -ne 0)
19+
{
20+
throw "Build/test failed."
21+
}
22+
23+
return $output
24+
}
25+
26+
function TileWindows
27+
{
28+
$shell = New-Object -ComObject Shell.Application
29+
$shell.TileHorizontally()
30+
}
31+
32+
function CurrentPath
33+
{
34+
return (Get-Item -Path ".\" -Verbose).FullName
35+
}
36+
37+
function ParseCurrentPath
38+
{
39+
$p = CurrentPath
40+
41+
$test_found = $false
42+
$contract_found = $false
43+
$root_found = $false
44+
45+
while ((-not $root_found) -and ($p -ne ""))
46+
{
47+
$leaf = Split-Path $p -Leaf
48+
49+
if (Test-Path (Join-Path $p 'build.cmd'))
50+
{
51+
$Global:RootPath = $p
52+
$root_found = $true
53+
}
54+
55+
if ($test_found -and (-not $contract_found))
56+
{
57+
$Global:ContractName = $leaf
58+
$contract_found = $true
59+
}
60+
61+
if ($leaf -eq "tests")
62+
{
63+
$test_found = $true
64+
}
65+
66+
$p = Split-Path $p
67+
}
68+
69+
if (-not $test_found)
70+
{
71+
throw "This folder doesn't appear to be part of a test (looking for ...\contract\tests\...)."
72+
}
73+
}
74+
75+
function ParseTestExecutionCommand($msBuildOutput)
76+
{
77+
$foundTestExecution = $false
78+
$cmdLine = ""
79+
80+
foreach ($line in $msBuildOutput)
81+
{
82+
if ($foundTestExecution -eq $true)
83+
{
84+
$cmdLine = $line
85+
break
86+
}
87+
88+
if ($line.Contains("RunTestsForProject:"))
89+
{
90+
$foundTestExecution = $true
91+
}
92+
}
93+
94+
if (-not $foundTestExecution)
95+
{
96+
throw "Cannot parse MSBuild output: please ensure that the current folder contains a test."
97+
}
98+
99+
$Global:TestCommand = $cmdLine.Trim()
100+
}
101+
102+
function ParseTestFolder($testExecutionCmdLine)
103+
{
104+
$coreRunPath = $testExecutionCmdLine.Split()[0]
105+
return Split-Path $coreRunPath
106+
}
107+
108+
function Initialize
109+
{
110+
ParseCurrentPath
111+
112+
Write-Host -NoNewline "Initializing tests for $($Global:ContractName) . . . "
113+
114+
try
115+
{
116+
$output = BuildAndTestBinary
117+
ParseTestExecutionCommand($output)
118+
119+
Write-Host -ForegroundColor Green "OK"
120+
}
121+
catch
122+
{
123+
Write-Host -ForegroundColor Red "Failed"
124+
throw
125+
}
126+
}
127+
128+
function RunOne($testCommand)
129+
{
130+
if ($testCommand -ne "")
131+
{
132+
$Global:TestCommand = $testCommand
133+
}
134+
135+
if ($Global:TestCommand -eq $null)
136+
{
137+
throw "Run Initialize first or pass the test command line as a parameter."
138+
}
139+
140+
Write-Host $Global:TestCommand
141+
$path = ParseTestFolder($Global:TestCommand)
142+
Write-Host "$path"
143+
144+
Push-Location
145+
cd $path
146+
Invoke-Expression $Global:TestCommand
147+
if ($lastexitcode -ne 0)
148+
{
149+
throw "Test execution failed."
150+
}
151+
152+
Pop-Location
153+
}
154+
155+
function RunUntilFailed($testCommand, $delayVarianceMilliseconds = 0)
156+
{
157+
158+
try
159+
{
160+
while($true)
161+
{
162+
RunOne $testCommand
163+
164+
if ($delayVarianceMilliseconds -ne 0)
165+
{
166+
$sleepMilliseconds = Get-Random -Minimum 0 -Maximum $delayVarianceMilliseconds
167+
Write-Host -ForegroundColor Cyan "Sleeping $sleepMilliseconds"
168+
Start-Sleep -Milliseconds $sleepMilliseconds
169+
}
170+
}
171+
}
172+
catch
173+
{
174+
Write-Host -ForegroundColor Red "Test execution failed!"
175+
Read-Host "Press ENTER to continue..."
176+
}
177+
}
178+
179+
function RunMultiple(
180+
[int]$n = 2,
181+
[int]$RandomDelayVarianceMilliseconds = 0,
182+
[switch]$UntilFailed = $false)
183+
{
184+
if ($Global:TestCommand -eq $null)
185+
{
186+
Initialize
187+
}
188+
189+
$script = $PSCommandPath
190+
$testCommand = $Global:TestCommand
191+
192+
if ($untilFailed)
193+
{
194+
$executionMethod = "RunUntilFailed"
195+
}
196+
else
197+
{
198+
$executionMethod = "RunOne"
199+
}
200+
201+
$cmdArguments = "-Command `"&{. $script; $executionMethod '$testCommand' $RandomDelayVarianceMilliseconds}`""
202+
203+
$processes = @()
204+
205+
for ($i=0; $i -lt $n; $i++)
206+
{
207+
$thisCmdArguments = $cmdArguments -replace ("testResults.xml", "testResults$i.xml")
208+
$process = Start-Process -PassThru powershell -ArgumentList $thisCmdArguments
209+
$processes += $process
210+
}
211+
212+
$processesExited = $false
213+
while (-not ([console]::KeyAvailable -or $processesExited))
214+
{
215+
Clear-Host
216+
217+
Write-Host -ForegroundColor Cyan "Active test processes:"
218+
Write-Host
219+
Write-Host "[Press any key to close.]"
220+
Write-Host
221+
$processes | Format-Table -Property Id, CPU, Handles, WS, ExitCode
222+
223+
$processesExited = $true
224+
foreach($p in $processes)
225+
{
226+
if (-not $p.HasExited)
227+
{
228+
$processesExited = $false
229+
}
230+
}
231+
232+
Start-Sleep -Milliseconds 1000
233+
TileWindows
234+
}
235+
236+
if (-not $processesExited)
237+
{
238+
Write-Host -ForegroundColor Cyan "Terminating all processes."
239+
foreach ($p in $processes)
240+
{
241+
if (-not $p.HasExited)
242+
{
243+
$p.Kill()
244+
}
245+
}
246+
}
247+
248+
Write-Host "Done."
249+
}

src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace System.Net.Test.Common
1010
{
1111
public class VirtualNetwork
1212
{
13-
private readonly int WaitForReadDataTimeoutMilliseconds = 10 * 1000;
13+
private readonly int WaitForReadDataTimeoutMilliseconds = 30 * 1000;
1414

1515
private readonly ConcurrentQueue<byte[]> _clientWriteQueue = new ConcurrentQueue<byte[]>();
1616
private readonly ConcurrentQueue<byte[]> _serverWriteQueue = new ConcurrentQueue<byte[]>();
@@ -34,9 +34,29 @@ public void ReadFrame(bool server, out byte[] buffer)
3434
packetQueue = _serverWriteQueue;
3535
}
3636

37-
semaphore.Wait(WaitForReadDataTimeoutMilliseconds);
37+
if (!semaphore.Wait(WaitForReadDataTimeoutMilliseconds))
38+
{
39+
throw new TimeoutException("VirtualNetwork: Timeout reading the next frame.");
40+
}
41+
42+
bool dequeueSucceeded = false;
43+
int remainingTries = 3;
44+
int backOffDelayMilliseconds = 2;
45+
46+
do
47+
{
48+
dequeueSucceeded = packetQueue.TryDequeue(out buffer);
49+
if (dequeueSucceeded)
50+
{
51+
break;
52+
}
53+
54+
remainingTries--;
55+
backOffDelayMilliseconds *= backOffDelayMilliseconds;
56+
Thread.Sleep(backOffDelayMilliseconds);
57+
}
58+
while (!dequeueSucceeded && (remainingTries > 0));
3859

39-
bool dequeueSucceeded = packetQueue.TryDequeue(out buffer);
4060
Debug.Assert(dequeueSucceeded, "Packet queue: TryDequeue failed.");
4161
}
4262

src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,9 @@ public override Task<int> ReadAsync(byte[] buffer, int offset, int count, Cancel
114114

115115
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
116116
{
117-
try
118-
{
119-
cancellationToken.ThrowIfCancellationRequested();
120-
Write(buffer, offset, count);
121-
return Task.CompletedTask;
122-
}
123-
catch (Exception e)
124-
{
125-
return Task.FromException(e);
126-
}
117+
return cancellationToken.IsCancellationRequested ?
118+
Task.FromCanceled<int>(cancellationToken) :
119+
Task.Run(() => Write(buffer, offset, count));
127120
}
128121
}
129122
}

src/Common/tests/Tests/System/Net/VirtualNetworkStreamTest.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@ public void VirtualNetworkStream_SingleThreadIntegrityTest_Ok()
2424
{
2525
for (int i = 0; i < 100000; i++)
2626
{
27-
int bufferSize = rnd.Next(1, 2048);
28-
29-
byte[] writeFrame = new byte[bufferSize];
27+
int bufferSize;
28+
byte[] writeFrame;
29+
30+
bufferSize = rnd.Next(1, 2048);
31+
writeFrame = new byte[bufferSize];
3032
rnd.NextBytes(writeFrame);
33+
3134
uint writeChecksum = Fletcher32.Checksum(writeFrame, 0, writeFrame.Length);
3235
client.Write(writeFrame, 0, writeFrame.Length);
3336

@@ -99,6 +102,8 @@ public void VirtualNetworkStream_MultiThreadIntegrityTest_Ok()
99102
Assert.True(maxFrameSize > sizeof(int) + 1);
100103

101104
var rnd = new Random();
105+
var rndLock = new object();
106+
102107
var network = new VirtualNetwork();
103108
var checksumAndLengths = new ConcurrentDictionary<int, Tuple<uint, int>>();
104109

@@ -107,12 +112,21 @@ public void VirtualNetworkStream_MultiThreadIntegrityTest_Ok()
107112
using (var client = new VirtualNetworkStream(network, isServer: false))
108113
using (var server = new VirtualNetworkStream(network, isServer: true))
109114
{
110-
Parallel.For(0, 100000, async (int i) =>
115+
Parallel.For(0, 100, (int i) =>
111116
{
112-
int bufferSize = rnd.Next(sizeof(int) + 1, maxFrameSize);
117+
int bufferSize;
118+
int delayMilliseconds;
119+
byte[] writeFrame;
120+
121+
lock (rndLock)
122+
{
123+
bufferSize = rnd.Next(sizeof(int) + 1, maxFrameSize);
124+
delayMilliseconds = rnd.Next(0, 10);
125+
126+
writeFrame = new byte[bufferSize];
127+
rnd.NextBytes(writeFrame);
128+
}
113129

114-
byte[] writeFrame = new byte[bufferSize];
115-
rnd.NextBytes(writeFrame);
116130

117131
// First 4 bytes represent the sequence number.
118132
byte[] sequenceNo = BitConverter.GetBytes(i);
@@ -123,14 +137,12 @@ public void VirtualNetworkStream_MultiThreadIntegrityTest_Ok()
123137

124138
checksumAndLengths.AddOrUpdate(i, writeFrameInfo, (seq, checkSum) => { Debug.Fail("Attempt to update checksum."); return new Tuple<uint, int>(0, 0); });
125139

126-
await client.WriteAsync(writeFrame, 0, writeFrame.Length);
127-
128-
int delayMilliseconds = rnd.Next(0, 10);
129-
await Task.Delay(delayMilliseconds);
140+
client.WriteAsync(writeFrame, 0, writeFrame.Length).GetAwaiter().GetResult();
141+
Task.Delay(delayMilliseconds).GetAwaiter().GetResult();
130142

131143
// First read the index to know how much data to read from this frame.
132144
var readFrame = new byte[maxFrameSize];
133-
int readLen = await server.ReadAsync(readFrame, 0, maxFrameSize);
145+
int readLen = server.ReadAsync(readFrame, 0, maxFrameSize).GetAwaiter().GetResult();
134146

135147
int idx = BitConverter.ToInt32(readFrame, 0);
136148
Tuple<uint, int> expectedFrameInfo = checksumAndLengths[idx];

src/Common/tests/project.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"System.Runtime.Handles": "4.0.1-rc3-24022-00",
1919
"System.Runtime.InteropServices": "4.1.0-rc3-24022-00",
2020
"System.Text.RegularExpressions": "4.1.0-rc3-24022-00",
21+
"System.Threading.Thread": "4.0.0-rc3-24022-00",
2122
"System.Threading.Tasks": "4.0.11-rc3-24022-00",
2223
"System.Threading.Tasks.Parallel": "4.0.1-rc3-24022-00",
2324
"xunit": "2.1.0",

0 commit comments

Comments
 (0)