Skip to content

Commit d74fc45

Browse files
committed
[CI] Use dotnet test slicer in nightly tests
Updates the `TimeZoneInfo` and `Localization` test stages to use the `dotnet-test-slicer` tool used by other MSBuild test runs. These test jobs have a pretty high frequency of failing and timing out, and a few changes have been made to try to reduce the points of failure. SetUp and TearDown functions have been trimmed down and made standard across the two fixtures. OneTimeSetup will prepare the device and install the project, and we will only attempt to attach log files during TearDown. The tests will launch the app activity directly with ADB, rather than using `dotnet build -t:Run` for every iteration. The tests will attempt to reinstall the app if it is not present as a fallback.
1 parent dab495f commit d74fc45

File tree

7 files changed

+218
-436
lines changed

7 files changed

+218
-436
lines changed

build-tools/automation/azure-pipelines-nightly.yaml

Lines changed: 68 additions & 275 deletions
Large diffs are not rendered by default.

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ static CodeBehindTests ()
152152
{
153153
TestProjectRootDirectory = Path.GetFullPath (Path.Combine (XABuildPaths.TopDirectory, "tests", "CodeBehind", "BuildTests"));
154154
CommonSampleLibraryRootDirectory = Path.GetFullPath (Path.Combine (XABuildPaths.TopDirectory, "tests", "CodeBehind", CommonSampleLibraryName));
155-
TestOutputDir = Path.Combine (SetUp.TestDirectoryRoot, "temp", "CodeBehind");
155+
TestOutputDir = Path.Combine (XABuildPaths.TestOutputDirectory, "temp", "CodeBehind");
156156
if (Builder.UseDotNet) {
157157
ProjectName += ".NET";
158158
}

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/EmbeddedDSOTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public bool Build (string projectOrSolution, string target, string [] parameters
5757
static EmbeddedDSOTests ()
5858
{
5959
TestProjectRootDirectory = Path.GetFullPath (Path.Combine (XABuildPaths.TopDirectory, "tests", "EmbeddedDSOs", "EmbeddedDSO"));
60-
TestOutputDir = Path.Combine (SetUp.TestDirectoryRoot, "temp", "EmbeddedDSO");
60+
TestOutputDir = Path.Combine (XABuildPaths.TestOutputDirectory, "temp", "EmbeddedDSO");
6161

6262
produced_binaries = new List <string> {
6363
$"{ProjectAssemblyName}.dll",

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs

Lines changed: 23 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,58 +23,9 @@ public class BaseTest
2323
public static ConcurrentDictionary<string, string> TestOutputDirectories = new ConcurrentDictionary<string, string> ();
2424
public static ConcurrentDictionary<string, string> TestPackageNames = new ConcurrentDictionary<string, string> ();
2525

26-
[SetUpFixture]
27-
public class SetUp
28-
{
29-
public static string TestDirectoryRoot {
30-
get;
31-
private set;
32-
}
33-
34-
[OneTimeSetUp]
35-
public void BeforeAllTests ()
36-
{
37-
TestDirectoryRoot = XABuildPaths.TestOutputDirectory;
38-
}
39-
40-
[OneTimeTearDown]
41-
public void AfterAllTests ()
42-
{
43-
if (System.Diagnostics.Debugger.IsAttached)
44-
return;
45-
46-
//NOTE: adb.exe can cause a couple issues on Windows
47-
// 1) it holds a lock on ~/android-toolchain, so a future build that needs to delete/recreate would fail
48-
// 2) the MSBuild <Exec /> task *can* hang until adb.exe exits
49-
50-
try {
51-
RunAdbCommand ("kill-server", true);
52-
} catch (Exception ex) {
53-
Console.Error.WriteLine ("Failed to run adb kill-server: " + ex);
54-
}
55-
56-
//NOTE: in case `adb kill-server` fails, kill the process as a last resort
57-
foreach (var p in Process.GetProcessesByName ("adb.exe"))
58-
p.Kill ();
59-
}
60-
61-
}
62-
6326
protected bool IsWindows => TestEnvironment.IsWindows;
6427

65-
protected bool IsMacOS => TestEnvironment.IsMacOS;
66-
67-
protected bool IsLinux => TestEnvironment.IsLinux;
68-
69-
public string StagingPath {
70-
get { return Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); }
71-
}
72-
73-
public string Root {
74-
get {
75-
return Path.GetFullPath (SetUp.TestDirectoryRoot);
76-
}
77-
}
28+
public string Root => Path.GetFullPath (XABuildPaths.TestOutputDirectory);
7829

7930
public static bool CommercialBuildAvailable => TestEnvironment.CommercialBuildAvailable;
8031

@@ -569,6 +520,28 @@ public void TestSetup ()
569520
TestContext.Out.Flush ();
570521
}
571522

523+
[OneTimeTearDown]
524+
protected virtual void AfterAllTests ()
525+
{
526+
if (System.Diagnostics.Debugger.IsAttached)
527+
return;
528+
529+
//NOTE: adb.exe can cause a couple issues on Windows
530+
// 1) it holds a lock on ~/android-toolchain, so a future build that needs to delete/recreate would fail
531+
// 2) the MSBuild <Exec /> task *can* hang until adb.exe exits
532+
if (IsWindows) {
533+
try {
534+
RunAdbCommand ("kill-server", true);
535+
} catch (Exception ex) {
536+
Console.Error.WriteLine ("Failed to run adb kill-server: " + ex);
537+
}
538+
539+
//NOTE: in case `adb kill-server` fails, kill the process as a last resort
540+
foreach (var p in Process.GetProcessesByName ("adb.exe"))
541+
p.Kill ();
542+
}
543+
}
544+
572545
[TearDown]
573546
protected virtual void CleanupTest ()
574547
{

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public void DeviceSetup ()
7373
}
7474

7575
[OneTimeTearDown]
76-
public void DeviceTearDown ()
76+
protected virtual void DeviceTearDown ()
7777
{
7878
if (IsDeviceAttached ()) {
7979
// make sure we are not on a guest user anymore.
@@ -199,11 +199,16 @@ protected static void RunProjectAndAssert (XamarinAndroidApplicationProject proj
199199
builder.BuildLogFile = logName;
200200
Assert.True (builder.RunTarget (proj, "_Run", doNotCleanupOnUpdate: doNotCleanupOnUpdate, parameters: parameters), "Project should have run.");
201201
} else {
202-
var result = AdbStartActivity ($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity");
203-
Assert.IsTrue (result.Contains ("Starting: Intent { cmp="), $"Attempt to start activity failed with:\n{result}");
202+
StartActivityAndAssert (proj);
204203
}
205204
}
206205

206+
protected static void StartActivityAndAssert (XamarinAndroidApplicationProject proj)
207+
{
208+
var result = AdbStartActivity ($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity");
209+
Assert.IsTrue (result.Contains ("Starting: Intent { cmp="), $"Attempt to start activity failed with:\n{result}");
210+
}
211+
207212
protected TimeSpan ProfileFor (Func<bool> func, TimeSpan? timeout = null)
208213
{
209214
var stopwatch = new Stopwatch ();

tests/MSBuildDeviceIntegration/Tests/LocalizationTests.cs

Lines changed: 54 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Globalization;
44
using System.IO;
55
using System.Linq;
6+
using System.Threading;
67
using Mono.Unix.Native;
78
using NUnit.Framework;
89
using NUnit.Framework.Interfaces;
@@ -16,8 +17,8 @@ namespace Xamarin.Android.Build.Tests
1617
[NonParallelizable]
1718
public class LocalizationTests : DeviceTest
1819
{
19-
static ProjectBuilder builder;
20-
static XamarinAndroidApplicationProject proj;
20+
ProjectBuilder builder;
21+
XamarinAndroidApplicationProject proj;
2122
string localeFileSuffix;
2223

2324
[OneTimeSetUp]
@@ -60,19 +61,6 @@ public override void SetupTest ()
6061
if (!string.IsNullOrEmpty (localeParam)) {
6162
localeFileSuffix = localeParam.Replace ("/", "-");
6263
}
63-
64-
if (!IsDeviceAttached (refreshCachedValue: true)) {
65-
RestartDevice ();
66-
AssertHasDevices ();
67-
}
68-
69-
// Attempt to reinstall the app that was installed during fixture setup if it is missing
70-
var packageOutput = RunAdbCommand ($"shell pm list packages {proj.PackageName}").Trim ();
71-
var expectedPackageOutput = $"package:{proj.PackageName}";
72-
if (packageOutput != expectedPackageOutput) {
73-
builder.BuildLogFile = $"setup-install-{localeFileSuffix}.log";
74-
Assert.IsTrue (builder.Install (proj), "Install should have succeeded.");
75-
}
7664
}
7765

7866
/// <summary>
@@ -93,27 +81,22 @@ protected override void CleanupTest ()
9381
}
9482
}
9583

84+
protected override void DeviceTearDown ()
85+
{
86+
}
87+
9688
[OneTimeTearDown]
97-
public void AfterAllTests ()
89+
protected override void AfterAllTests ()
9890
{
99-
string output = Path.Combine (Root, builder?.ProjectDirectory);
100-
if (TestContext.CurrentContext.Result.FailCount == 0 && Directory.Exists (output)) {
101-
try {
102-
Directory.Delete (output, recursive: true);
103-
} catch (IOException ex) {
104-
// This happens on CI occasionally, let's not fail the test
105-
TestContext.Out.WriteLine ($"Failed to delete '{output}': {ex}");
106-
}
107-
}
10891
}
10992

11093

11194
const int LOCALIZATION_NODE_COUNT = 15;
11295
const int LOCALIZATION_RETRY_COUNT = 3;
11396

114-
static object [] GetLocalizationTestCases (int node)
97+
static List<string> GetLocalizationTestInfo ()
11598
{
116-
List<object> tests = new List<object> ();
99+
var tests = new List<string> ();
117100
var ignore = new string [] {
118101
"he-IL", // maps to wi-IL on Android.
119102
"id-ID", // maps to in-ID on Android
@@ -127,11 +110,14 @@ static object [] GetLocalizationTestCases (int node)
127110
TestContext.WriteLine ($"Ignoring {ci.Name} Localization Test");
128111
continue;
129112
}
130-
tests.Add (new object [] {
131-
ci.Name,
132-
});
113+
tests.Add (ci.Name);
133114
}
115+
return tests;
116+
}
134117

118+
static object [] GetLocalizationTestCases (int node)
119+
{
120+
var tests = GetLocalizationTestInfo ();
135121
return tests.Where (p => tests.IndexOf (p) % LOCALIZATION_NODE_COUNT == node).ToArray ();
136122
}
137123

@@ -210,41 +196,56 @@ static object [] GetLocalizationTestCases (int node)
210196
[TestCaseSource (nameof (GetLocalizationTestCases), new object [] { 14 })]
211197
public void CheckLocalizationIsCorrectNode15 (string locale) => CheckLocalizationIsCorrect (locale);
212198

199+
[Test]
200+
[Retry (LOCALIZATION_RETRY_COUNT)]
201+
[TestCaseSource (nameof (GetLocalizationTestInfo))]
202+
public void CheckLocalizationIsCorrectWithSlicer (string locale) => CheckLocalizationIsCorrect (locale);
203+
213204

214205
public void CheckLocalizationIsCorrect (string locale)
215206
{
207+
AssertHasDevices ();
208+
209+
// Attempt to reinstall the app that was installed during fixture setup if it is missing
210+
var packageOutput = RunAdbCommand ($"shell pm list packages {proj.PackageName}").Trim ();
211+
var expectedPackageOutput = $"package:{proj.PackageName}";
212+
if (packageOutput != expectedPackageOutput) {
213+
builder.BuildLogFile = $"setup-install-{localeFileSuffix}.log";
214+
Assert.IsTrue (builder.Install (proj), "Install should have succeeded.");
215+
}
216+
217+
RunAdbCommand ($"shell am force-stop --user all {proj.PackageName}");
218+
RunAdbCommand ($"shell am kill --user all {proj.PackageName}");
219+
216220
var appStartupLogcatFile = Path.Combine (Root, builder.ProjectDirectory, $"startup-logcat-{locale.Replace ("/", "-")}.log");
217221
string deviceLocale = RunAdbCommand ("shell getprop persist.sys.locale")?.Trim ();
218222
TestContext.Out.WriteLine ($"test value:{locale}, prop value:{deviceLocale}");
219223

220-
if (deviceLocale != locale) {
221-
for (int attempt = 0; attempt < 5; attempt++) {
222-
TestContext.Out.WriteLine ($"{nameof(CheckLocalizationIsCorrect)}: Setting Locale to {locale}, attempt {attempt}...");
223-
ClearAdbLogcat ();
224-
var rebootLogcatFile = Path.Combine (Root, builder.ProjectDirectory, $"reboot{attempt}-logcat-{locale.Replace ("/", "-")}.log");
225-
226-
// https://developer.android.com/guide/topics/resources/localization#changing-the-emulator-locale-from-the-adb-shell
227-
RunAdbCommand ($"shell \"su root setprop persist.sys.locale {locale};su root stop;sleep 5;su root start;\"");
228-
229-
if (!MonitorAdbLogcat ((l) => {
230-
if (l.Contains ("ActivityManager: Finished processing BOOT_COMPLETED"))
231-
return true;
232-
return false;
233-
}, rebootLogcatFile, timeout: 60)) {
234-
TestContext.Out.WriteLine ($"{nameof(CheckLocalizationIsCorrect)}: wating for boot to complete failed or timed out.");
235-
}
236-
deviceLocale = RunAdbCommand ("shell getprop persist.sys.locale")?.Trim ();
237-
if (deviceLocale == locale) {
238-
break;
239-
}
224+
for (int attempt = 0; attempt < 5; attempt++) {
225+
TestContext.Out.WriteLine ($"{nameof(CheckLocalizationIsCorrect)}: Setting Locale to {locale}, attempt {attempt}...");
226+
ClearAdbLogcat ();
227+
var rebootLogcatFile = Path.Combine (Root, builder.ProjectDirectory, $"reboot{attempt}-logcat-{locale.Replace ("/", "-")}.log");
228+
229+
// https://developer.android.com/guide/topics/resources/localization#changing-the-emulator-locale-from-the-adb-shell
230+
RunAdbCommand ($"shell \"su root setprop persist.sys.locale {locale};su root stop;sleep 5;su root start;\"");
231+
232+
if (!MonitorAdbLogcat ((l) => {
233+
if (l.Contains ("ActivityManager: Finished processing BOOT_COMPLETED"))
234+
return true;
235+
return false;
236+
}, rebootLogcatFile, timeout: 60)) {
237+
TestContext.Out.WriteLine ($"{nameof(CheckLocalizationIsCorrect)}: wating for boot to complete failed or timed out.");
238+
}
239+
deviceLocale = RunAdbCommand ("shell getprop persist.sys.locale")?.Trim ();
240+
if (deviceLocale == locale) {
241+
break;
240242
}
241243
}
242244

243245
Assert.AreEqual (locale, deviceLocale, $"The command to set the device locale to {locale} failed. Current device locale is {deviceLocale}");
244246
ClearAdbLogcat ();
245-
RunAdbCommand ($"shell am force-stop --user all {proj.PackageName}");
246-
RunAdbCommand ($"shell am kill --user all {proj.PackageName}");
247-
RunProjectAndAssert (proj, builder, logName: $"run-{locale.Replace ("/", "-")}.log");
247+
Thread.Sleep (1000);
248+
StartActivityAndAssert (proj);
248249

249250
string logcatSearchString = "Strings.SomeString=";
250251
string expectedLogcatOutput = $"{logcatSearchString}{locale}";
@@ -258,7 +259,6 @@ public void CheckLocalizationIsCorrect (string locale)
258259
return false;
259260
}, appStartupLogcatFile, 45), $"App output did not contain '{logcatSearchString}'");
260261
Assert.IsTrue (logLine.Contains (expectedLogcatOutput), $"Line '{logLine}' did not contain '{expectedLogcatOutput}'");
261-
262262
string humanizerLogCatFile = Path.Combine (Root, builder.ProjectDirectory, $"humanizer-logcat-{locale.Replace ("/", "-")}.log");
263263
var culture = new CultureInfo (locale);
264264
expectedLogcatOutput = DateTime.UtcNow.AddHours(-30).Humanize(culture: culture);
@@ -271,7 +271,6 @@ public void CheckLocalizationIsCorrect (string locale)
271271
return false;
272272
}, humanizerLogCatFile, timeout:45), $"App output did not contain '{logcatSearchString}'");
273273
Assert.IsTrue (logLine.Contains (expectedLogcatOutput), $"Line '{logLine}' did not contain '{expectedLogcatOutput}'");
274-
275274
}
276275
}
277276
}

0 commit comments

Comments
 (0)