Skip to content

Commit 9a2345a

Browse files
committed
Implement ResultFileHandler
1 parent 2e6c738 commit 9a2345a

File tree

5 files changed

+334
-83
lines changed

5 files changed

+334
-83
lines changed

src/Microsoft.DotNet.XHarness.Apple/AppOperations/AppTester.cs

Lines changed: 25 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ public AppTester(
204204
timeout,
205205
null,
206206
(level, message) => _mainLog.WriteLine(message));
207+
IResultFileHandler resultFileHandler = new ResultFileHandler(_processManager, _mainLog);
207208

208209
deviceListener.ConnectedTask
209210
.TimeoutAfter(testLaunchTimeout)
@@ -252,6 +253,7 @@ await RunSimulatorTests(
252253
mlaunchArguments,
253254
crashReporter,
254255
testReporter,
256+
resultFileHandler,
255257
deviceListener,
256258
(ISimulatorDevice)device,
257259
companionDevice as ISimulatorDevice,
@@ -289,6 +291,7 @@ await RunDeviceTests(
289291
mlaunchArguments,
290292
crashReporter,
291293
testReporter,
294+
resultFileHandler,
292295
deviceListener,
293296
device,
294297
appOutputLog,
@@ -309,6 +312,7 @@ private async Task RunSimulatorTests(
309312
MlaunchArguments mlaunchArguments,
310313
ICrashSnapshotReporter crashReporter,
311314
ITestReporter testReporter,
315+
IResultFileHandler resultFileHandler,
312316
ISimpleListener deviceListener,
313317
ISimulatorDevice simulator,
314318
ISimulatorDevice? companionSimulator,
@@ -327,58 +331,20 @@ private async Task RunSimulatorTests(
327331
cancellationToken);
328332

329333
await testReporter.CollectSimulatorResult(result);
330-
if (simulator == null || simulator.OSVersion == null)
331-
{
332-
_mainLog.WriteLine("Simulator OS version is not set, skipping result copying.");
333-
return;
334-
}
335-
336-
var osVersionParts = simulator.OSVersion.Split(' ', StringSplitOptions.RemoveEmptyEntries);
337-
if (osVersionParts.Length < 2)
338-
{
339-
_mainLog.WriteLine("Simulator OS version is not in the expected format, skipping result copying.");
340-
return;
341-
}
342-
343-
bool versionParsed = Version.TryParse(osVersionParts[1], out var osVersion);
344334

345335
// On iOS 18 and later, transferring results over a TCP tunnel isn’t supported.
346336
// Instead, copy the results file from the device to the host machine.
347-
_mainLog.WriteLine($"Simulator OS version: {osVersion}");
348-
if (versionParsed && osVersion!.Major >= 18)
337+
if (deviceListener.TestLog != null &&
338+
!await resultFileHandler.CopyResultsAsync(
339+
runMode,
340+
true,
341+
simulator.OSVersion,
342+
simulator.UDID,
343+
appInformation.BundleIdentifier,
344+
deviceListener.TestLog.FullPath,
345+
cancellationToken))
349346
{
350-
try
351-
{
352-
var resultsFilePathOnDevice = runMode == RunMode.iOS
353-
? "/Documents/test-results.xml"
354-
: "/Library/Caches/Documents/test-results.xml";
355-
var resultsFilePathOnHost = deviceListener.TestLog.FullPath;
356-
var simCtlCmd = $"cp \"$(xcrun simctl get_app_container {simulator.UDID} {appInformation.BundleIdentifier} data){resultsFilePathOnDevice}\" \"{resultsFilePathOnHost}\"";
357-
358-
var _ = await _processManager.ExecuteCommandAsync(
359-
"/bin/bash",
360-
new[] { "-c", simCtlCmd },
361-
_mainLog,
362-
_mainLog,
363-
_mainLog,
364-
TimeSpan.FromMinutes(1),
365-
null,
366-
cancellationToken: cancellationToken);
367-
368-
if (File.Exists(resultsFilePathOnHost))
369-
{
370-
_mainLog.WriteLine($"Test results copied from simulator to {resultsFilePathOnHost}");
371-
}
372-
else
373-
{
374-
_mainLog.WriteLine($"Failed to copy test results from simulator");
375-
}
376-
}
377-
catch (Exception ex)
378-
{
379-
_mainLog.WriteLine($"Exception while copying test results from simulator: {ex}");
380-
throw;
381-
}
347+
throw new InvalidOperationException("Failed to copy test results from simulator to host.");
382348
}
383349
}
384350

@@ -387,6 +353,7 @@ private async Task RunDeviceTests(
387353
MlaunchArguments mlaunchArguments,
388354
ICrashSnapshotReporter crashReporter,
389355
ITestReporter testReporter,
356+
IResultFileHandler resultFileHandler,
390357
ISimpleListener deviceListener,
391358
IDevice device,
392359
ILog appOutputLog,
@@ -401,8 +368,6 @@ private async Task RunDeviceTests(
401368
var deviceLogCapturer = _deviceLogCapturerFactory.Create(_mainLog, deviceSystemLog, device.Name);
402369
deviceLogCapturer.StartCapture();
403370

404-
bool versionParsed = Version.TryParse(device.OSVersion, out var osVersion);
405-
406371
try
407372
{
408373
await crashReporter.StartCaptureAsync();
@@ -457,39 +422,17 @@ private async Task RunDeviceTests(
457422

458423
// On iOS 18 and later, transferring results over a TCP tunnel isn’t supported.
459424
// Instead, copy the results file from the device to the host machine.
460-
_mainLog.WriteLine($"Device OS version: {osVersion}");
461-
if (versionParsed && osVersion!.Major >= 18)
425+
if (deviceListener.TestLog != null &&
426+
!await resultFileHandler.CopyResultsAsync(
427+
runMode,
428+
false,
429+
device.OSVersion,
430+
device.UDID,
431+
appInformation.BundleIdentifier,
432+
deviceListener.TestLog.FullPath,
433+
cancellationToken))
462434
{
463-
var resultsFilePathOnDevice = runMode == RunMode.iOS
464-
? "/Documents/test-results.xml"
465-
: "/Library/Caches/Documents/test-results.xml";
466-
var resultsFilePathOnHost = deviceListener.TestLog.FullPath;
467-
var devicectlCmd = $"xcrun devicectl device copy from --device {device.UDID} --source {resultsFilePathOnDevice} --destination {resultsFilePathOnHost} --domain-type appDataContainer --domain-identifier {appInformation.BundleIdentifier}";
468-
try
469-
{
470-
var result = await _processManager.ExecuteCommandAsync(
471-
"/bin/bash",
472-
new List<string> { "-c", devicectlCmd },
473-
_mainLog,
474-
_mainLog,
475-
_mainLog,
476-
TimeSpan.FromMinutes(1),
477-
null,
478-
cancellationToken: cancellationToken);
479-
if (File.Exists(resultsFilePathOnHost))
480-
{
481-
_mainLog.WriteLine($"Test results copied from device to {resultsFilePathOnHost}");
482-
}
483-
else
484-
{
485-
_mainLog.WriteLine($"Failed to copy test results from device");
486-
}
487-
}
488-
catch (Exception ex)
489-
{
490-
_mainLog.WriteLine($"Exception while copying test results from device: {ex}");
491-
throw;
492-
}
435+
throw new InvalidOperationException("Failed to copy test results from device to host.");
493436
}
494437
}
495438

src/Microsoft.DotNet.XHarness.TestRunners.Common/iOSApplicationEntryPointBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public override async Task RunAsync()
2525
var options = ApplicationOptions.Current;
2626

2727
// On iOS 18 and later, transferring results over a TCP tunnel isn’t supported.
28-
// Instead, save results to a file.
28+
// Instead, copy the results file from the device to the host machine.
2929
if (!OperatingSystem.IsMacCatalyst() && Environment.OSVersion.Version.Major >= 18)
3030
{
3131
using TextWriter? resultsFileMaybe = options.EnableXml ? System.IO.File.CreateText(TestsResultsFinalPath) : null;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
using System.Threading;
6+
using System.Threading.Tasks;
7+
8+
#nullable enable
9+
namespace Microsoft.DotNet.XHarness.iOS.Shared;
10+
11+
public interface IResultFileHandler
12+
{
13+
/// <summary>
14+
/// Copy the XML results file from the app container (simulator or device) to the host path.
15+
/// </summary>
16+
Task<bool> CopyResultsAsync(
17+
RunMode runMode,
18+
bool isSimulator,
19+
string osVersion,
20+
string udid,
21+
string bundleIdentifier,
22+
string hostDestinationPath,
23+
CancellationToken token);
24+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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+
using System;
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using Microsoft.DotNet.XHarness.Common.Logging;
11+
using Microsoft.DotNet.XHarness.iOS.Shared.Execution;
12+
13+
#nullable enable
14+
namespace Microsoft.DotNet.XHarness.iOS.Shared;
15+
16+
public class ResultFileHandler : IResultFileHandler
17+
{
18+
private IMlaunchProcessManager _processManager;
19+
private IFileBackedLog _mainLog;
20+
21+
public ResultFileHandler(IMlaunchProcessManager pm, IFileBackedLog fs)
22+
{
23+
_processManager = pm;
24+
_mainLog = fs;
25+
}
26+
27+
public async Task<bool> CopyResultsAsync(
28+
RunMode runMode,
29+
bool isSimulator,
30+
string osVersion,
31+
string udid,
32+
string bundleIdentifier,
33+
string hostDestinationPath,
34+
CancellationToken token)
35+
{
36+
// This file path is set in iOSApplicationEntryPointBase
37+
string sourcePath = runMode == RunMode.iOS
38+
? "/Documents/test-results.xml"
39+
: "/Library/Caches/Documents/test-results.xml";
40+
41+
if (isSimulator)
42+
{
43+
// Version format contains string like "Simulator 18.0".
44+
string [] osVersionParts = osVersion.Split(' ', StringSplitOptions.RemoveEmptyEntries);
45+
if (osVersionParts.Length < 2)
46+
{
47+
_mainLog.WriteLine("Simulator OS version is not in the expected format, skipping result copying.");
48+
return false;
49+
}
50+
51+
if (!Version.TryParse(osVersionParts[1], out Version osVersionParsed))
52+
{
53+
_mainLog.WriteLine("Simulator OS version is not in the expected format, skipping result copying.");
54+
return false;
55+
}
56+
57+
if (osVersionParsed.Major >= 18)
58+
{
59+
60+
string cmd = $"cp \"$(xcrun simctl get_app_container {udid} {bundleIdentifier} data){sourcePath}\" \"{hostDestinationPath}\"";
61+
62+
await _processManager.ExecuteCommandAsync(
63+
"/bin/bash",
64+
new[] { "-c", cmd },
65+
_mainLog,
66+
_mainLog,
67+
_mainLog,
68+
TimeSpan.FromMinutes(1),
69+
null,
70+
cancellationToken: token);
71+
72+
if (!File.Exists(hostDestinationPath))
73+
{
74+
_mainLog.WriteLine($"Failed to copy results file from simulator. Expected at: {hostDestinationPath}");
75+
return false;
76+
}
77+
}
78+
79+
return true;
80+
}
81+
else
82+
{
83+
if (!Version.TryParse(osVersion, out Version osVersionParsed))
84+
{
85+
_mainLog.WriteLine($"Device OS version is not in the expected format, skipping result copying.");
86+
return false;
87+
}
88+
89+
if (osVersionParsed.Major >= 18)
90+
{
91+
string cmd = $"xcrun devicectl device copy from --device {udid} --source {sourcePath} --destination {hostDestinationPath} --domain-type appDataContainer --domain-identifier {bundleIdentifier}";
92+
await _processManager.ExecuteCommandAsync(
93+
"/bin/bash",
94+
new List<string> { "-c", cmd },
95+
_mainLog,
96+
_mainLog,
97+
_mainLog,
98+
TimeSpan.FromMinutes(1),
99+
null,
100+
cancellationToken: token);
101+
102+
if (!File.Exists(hostDestinationPath))
103+
{
104+
_mainLog.WriteLine($"Failed to copy results file from device. Expected at: {hostDestinationPath}");
105+
return false;
106+
}
107+
}
108+
109+
return true;
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)