Skip to content

Commit 7427692

Browse files
authored
[tests] Unit tests for finding NDK location based on $PATH (#40)
Commit 511d580 didn't provide unit tests to ensure that the Android NDK could be found based on probing `$PATH` for `ndk-stack`. Update `AndroidSdkInfoTests` to ensure that the NDK to be found based on `$PATH`, as well as the Android SDK and JDK. Additionally, JDK-via-$PATH detection hit a few hiccups: 1. `JdkInfo.GetKnownSystemJdkInfos()` would always check `/usr/libexec/java_home` before `$PATH`, meaning it wasn't possible to test JDK-via-$PATH! Alter the ordering of `JdkInfo.GetKnownSystemJdkInfos()` so that we probe `$PATH` before hitting `/usr/libexec/java_home`. 2. `JdkInfo` requires that the `java.home` property be printed, which `JdkInfoTests.CreateFauxJdk()` didn't print, which caused the fake JDK to be skipped. Fix `JdkInfoTests.CreateFauxJdk()` so that the resulting `java` is acceptable by `JdkInfo`. Additionally, for greater `monodroid-config.xml` sanity (see also a4aad18 and b42c217), instead of backing up the *global* `monodroid-config.xml` file, instead allow the location of `monodroid-config.xml` to be overridden by the unit tests by setting a value accessible by `AppDomain.GetData()`, a'la a4aad18. Finally, allow the `logger` parameter to `JdkInfo.GetKnownSystemJdkInfos()` to be optional; if not provided, it will print to the Console.
1 parent dbc517b commit 7427692

File tree

5 files changed

+140
-43
lines changed

5 files changed

+140
-43
lines changed

src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public static void SetPreferredAndroidNdkPath (string path, Action<TraceLevel, s
144144
sdk.SetPreferredAndroidNdkPath(path);
145145
}
146146

147-
static void DefaultConsoleLogger (TraceLevel level, string message)
147+
internal static void DefaultConsoleLogger (TraceLevel level, string message)
148148
{
149149
switch (level) {
150150
case TraceLevel.Error:

src/Xamarin.Android.Tools.AndroidSdk/JdkInfo.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,16 @@ static Dictionary<string, List<string>> GetJavaProperties (string java)
207207
return props;
208208
}
209209

210-
public static IEnumerable<JdkInfo> GetKnownSystemJdkInfos (Action<TraceLevel, string> logger)
210+
public static IEnumerable<JdkInfo> GetKnownSystemJdkInfos (Action<TraceLevel, string> logger = null)
211211
{
212+
logger = logger ?? AndroidSdkInfo.DefaultConsoleLogger;
213+
212214
return GetWindowsJdks (logger)
213215
.Concat (GetConfiguredJdks (logger))
214216
.Concat (GetMacOSMicrosoftJdks (logger))
215217
.Concat (GetJavaHomeEnvironmentJdks (logger))
216-
.Concat (GetLibexecJdks (logger))
217218
.Concat (GetPathEnvironmentJdks (logger))
219+
.Concat (GetLibexecJdks (logger))
218220
.Concat (GetJavaAlternativesJdks (logger))
219221
;
220222
}

src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ void AddToList (string path)
205205
}
206206
}
207207

208+
static readonly string GetUnixConfigDirOverrideName = $"UnixConfigPath directory override! {typeof (AndroidSdkInfo).AssemblyQualifiedName}";
209+
208210
// There's a small problem with the code below. Namely, if it runs under `sudo` the folder location
209211
// returned by Environment.GetFolderPath will depend on how sudo was invoked:
210212
//
@@ -231,8 +233,12 @@ void AddToList (string path)
231233
//
232234
private static string UnixConfigPath {
233235
get {
234-
var p = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
235-
return Path.Combine (Path.Combine (p, "xbuild"), "monodroid-config.xml");
236+
var p = AppDomain.CurrentDomain.GetData (GetUnixConfigDirOverrideName)?.ToString ();
237+
if (string.IsNullOrEmpty (p)) {
238+
p = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
239+
p = Path.Combine (p, "xbuild");
240+
}
241+
return Path.Combine (p, "monodroid-config.xml");
236242
}
237243
}
238244

src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs

Lines changed: 112 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
5+
using System.Linq;
56
using System.Text;
67
using System.Xml.Linq;
78

@@ -12,6 +13,35 @@ namespace Xamarin.Android.Tools.Tests
1213
[TestFixture]
1314
public class AndroidSdkInfoTests
1415
{
16+
string UnixConfigDirOverridePath;
17+
string PreferredJdksOverridePath;
18+
19+
static readonly string GetMacOSMicrosoftJdkPathsOverrideName = $"GetMacOSMicrosoftJdkPaths jdks override! {typeof (JdkInfo).AssemblyQualifiedName}";
20+
static readonly string GetUnixConfigDirOverrideName = $"UnixConfigPath directory override! {typeof (AndroidSdkInfo).AssemblyQualifiedName}";
21+
22+
[OneTimeSetUp]
23+
public void FixtureSetUp ()
24+
{
25+
UnixConfigDirOverridePath = Path.GetTempFileName ();
26+
File.Delete (UnixConfigDirOverridePath);
27+
Directory.CreateDirectory (UnixConfigDirOverridePath);
28+
AppDomain.CurrentDomain.SetData (GetUnixConfigDirOverrideName, UnixConfigDirOverridePath);
29+
30+
PreferredJdksOverridePath = Path.GetTempFileName ();
31+
File.Delete (PreferredJdksOverridePath);
32+
Directory.CreateDirectory (PreferredJdksOverridePath);
33+
AppDomain.CurrentDomain.SetData (GetMacOSMicrosoftJdkPathsOverrideName, PreferredJdksOverridePath);
34+
}
35+
36+
[OneTimeTearDown]
37+
public void FixtureTearDown ()
38+
{
39+
AppDomain.CurrentDomain.SetData (GetMacOSMicrosoftJdkPathsOverrideName, null);
40+
AppDomain.CurrentDomain.SetData (GetUnixConfigDirOverrideName, null);
41+
Directory.Delete (UnixConfigDirOverridePath, recursive: true);
42+
Directory.Delete (PreferredJdksOverridePath, recursive: true);
43+
}
44+
1545
[Test]
1646
public void Constructor_NullLogger ()
1747
{
@@ -22,27 +52,17 @@ public void Constructor_NullLogger ()
2252
[Test]
2353
public void Constructor_Paths ()
2454
{
25-
var root = Path.GetTempFileName ();
26-
File.Delete (root);
27-
Directory.CreateDirectory (root);
28-
29-
var sdk = Path.Combine (root, "sdk");
30-
var jdk = Path.Combine (root, "jdk");
31-
32-
Directory.CreateDirectory (sdk);
33-
Directory.CreateDirectory (jdk);
34-
35-
CreateFauxAndroidSdkDirectory (sdk, "26.0.0");
36-
CreateFauxJavaSdkDirectory (jdk, "1.8.0", out var _, out var _);
55+
CreateSdks (out string root, out string jdk, out string ndk, out string sdk);
3756

3857
var logs = new StringWriter ();
3958
Action<TraceLevel, string> logger = (level, message) => {
4059
logs.WriteLine ($"[{level}] {message}");
4160
};
4261

4362
try {
44-
var info = new AndroidSdkInfo (logger, androidSdkPath: sdk, javaSdkPath: jdk, androidNdkPath: null);
63+
var info = new AndroidSdkInfo (logger, androidSdkPath: sdk, androidNdkPath: ndk, javaSdkPath: jdk);
4564

65+
Assert.AreEqual (ndk, info.AndroidNdkPath, "AndroidNdkPath not preserved!");
4666
Assert.AreEqual (sdk, info.AndroidSdkPath, "AndroidSdkPath not preserved!");
4767
Assert.AreEqual (jdk, info.JavaSdkPath, "JavaSdkPath not preserved!");
4868
}
@@ -51,8 +71,58 @@ public void Constructor_Paths ()
5171
}
5272
}
5373

74+
[Test]
75+
public void Constructor_SetValuesFromPath ()
76+
{
77+
CreateSdks (out string root, out string jdk, out string ndk, out string sdk);
78+
JdkInfoTests.CreateFauxJdk (jdk, "1.8.0");
79+
80+
Action<TraceLevel, string> logger = (level, message) => {
81+
Console.WriteLine ($"[{level}] {message}");
82+
};
83+
var oldPath = Environment.GetEnvironmentVariable ("PATH");
84+
try {
85+
var paths = new List<string> () {
86+
Path.Combine (jdk, "bin"),
87+
ndk,
88+
Path.Combine (sdk, "platform-tools"),
89+
};
90+
paths.AddRange (oldPath.Split (new[]{Path.PathSeparator}, StringSplitOptions.RemoveEmptyEntries));
91+
Environment.SetEnvironmentVariable ("PATH", string.Join (Path.PathSeparator.ToString (), paths));
92+
93+
var info = new AndroidSdkInfo (logger);
94+
95+
Assert.AreEqual (ndk, info.AndroidNdkPath, "AndroidNdkPath not set from $PATH!");
96+
Assert.AreEqual (sdk, info.AndroidSdkPath, "AndroidSdkPath not set from $PATH!");
97+
Assert.AreEqual (jdk, info.JavaSdkPath, "JavaSdkPath not set from $PATH!");
98+
}
99+
finally {
100+
Environment.SetEnvironmentVariable ("PATH", oldPath);
101+
Directory.Delete (root, recursive: true);
102+
}
103+
}
104+
54105
static bool IsWindows => OS.IsWindows;
55106

107+
static void CreateSdks (out string root, out string jdk, out string ndk, out string sdk)
108+
{
109+
root = Path.GetTempFileName ();
110+
File.Delete (root);
111+
Directory.CreateDirectory (root);
112+
113+
ndk = Path.Combine (root, "ndk");
114+
sdk = Path.Combine (root, "sdk");
115+
jdk = Path.Combine (root, "jdk");
116+
117+
Directory.CreateDirectory (sdk);
118+
Directory.CreateDirectory (ndk);
119+
Directory.CreateDirectory (jdk);
120+
121+
CreateFauxAndroidSdkDirectory (sdk, "26.0.0");
122+
CreateFauxAndroidNdkDirectory (ndk);
123+
CreateFauxJavaSdkDirectory (jdk, "1.8.0", out var _, out var _);
124+
}
125+
56126
static void CreateFauxAndroidSdkDirectory (string androidSdkDirectory, string buildToolsVersion, ApiInfo [] apiLevels = null)
57127
{
58128
var androidSdkToolsPath = Path.Combine (androidSdkDirectory, "tools");
@@ -90,7 +160,28 @@ struct ApiInfo {
90160
public string Id;
91161
}
92162

93-
protected string CreateFauxJavaSdkDirectory (string javaPath, string javaVersion, out string javaExe, out string javacExe)
163+
static void CreateFauxAndroidNdkDirectory (string androidNdkDirectory)
164+
{
165+
File.WriteAllText (Path.Combine (androidNdkDirectory, "ndk-stack"), "");
166+
File.WriteAllText (Path.Combine (androidNdkDirectory, "ndk-stack.cmd"), "");
167+
168+
string prebuiltHostName = "";
169+
if (OS.IsWindows)
170+
prebuiltHostName = "windows-x86_64";
171+
else if (OS.IsMac)
172+
prebuiltHostName = "darwin-x86_64";
173+
else
174+
prebuiltHostName = "linux-x86_64";
175+
176+
177+
var toolchainsDir = Path.Combine (androidNdkDirectory, "toolchains");
178+
var armToolchainDir = Path.Combine (toolchainsDir, "arm-linux-androideabi-4.9");
179+
var armPrebuiltDir = Path.Combine (armToolchainDir, "prebuilt", prebuiltHostName);
180+
181+
Directory.CreateDirectory (armPrebuiltDir);
182+
}
183+
184+
static string CreateFauxJavaSdkDirectory (string javaPath, string javaVersion, out string javaExe, out string javacExe)
94185
{
95186
javaExe = IsWindows ? "Java.cmd" : "java.bash";
96187
javacExe = IsWindows ? "Javac.cmd" : "javac.bash";
@@ -106,7 +197,7 @@ protected string CreateFauxJavaSdkDirectory (string javaPath, string javaVersion
106197
return javaPath;
107198
}
108199

109-
void CreateFauxJavaExe (string javaExeFullPath, string version)
200+
static void CreateFauxJavaExe (string javaExeFullPath, string version)
110201
{
111202
var sb = new StringBuilder ();
112203
if (IsWindows) {
@@ -126,7 +217,7 @@ void CreateFauxJavaExe (string javaExeFullPath, string version)
126217
}
127218
}
128219

129-
void CreateFauxJavacExe (string javacExeFullPath, string version)
220+
static void CreateFauxJavacExe (string javacExeFullPath, string version)
130221
{
131222
var sb = new StringBuilder ();
132223
if (IsWindows) {
@@ -142,7 +233,7 @@ void CreateFauxJavacExe (string javacExeFullPath, string version)
142233
}
143234
}
144235

145-
protected void Exec (string exe, string args)
236+
static void Exec (string exe, string args)
146237
{
147238
var psi = new ProcessStartInfo {
148239
FileName = exe,
@@ -168,10 +259,6 @@ public void DetectAndSetPreferredJavaSdkPathToLatest ()
168259
Action<TraceLevel, string> logger = (level, message) => {
169260
Console.WriteLine ($"[{level}] {message}");
170261
};
171-
var jdks = Path.GetTempFileName ();
172-
File.Delete (jdks);
173-
Directory.CreateDirectory (jdks);
174-
AppDomain.CurrentDomain.SetData ($"GetMacOSMicrosoftJdkPaths jdks override! {typeof (JdkInfo).AssemblyQualifiedName}", jdks);
175262

176263
var backupConfig = UnixConfigPath + "." + Path.GetRandomFileName ();
177264
try {
@@ -180,7 +267,7 @@ public void DetectAndSetPreferredJavaSdkPathToLatest ()
180267
return;
181268
}
182269
Assert.Throws<NotSupportedException>(() => AndroidSdkInfo.DetectAndSetPreferredJavaSdkPathToLatest (logger));
183-
var newJdkPath = Path.Combine (jdks, "microsoft_dist_openjdk_1.8.999");
270+
var newJdkPath = Path.Combine (PreferredJdksOverridePath, "microsoft_dist_openjdk_1.8.999");
184271
JdkInfoTests.CreateFauxJdk (newJdkPath, "1.8.999");
185272

186273
if (File.Exists (UnixConfigPath))
@@ -190,16 +277,14 @@ public void DetectAndSetPreferredJavaSdkPathToLatest ()
190277
AssertJdkPath (newJdkPath);
191278
}
192279
finally {
193-
AppDomain.CurrentDomain.SetData ($"GetMacOSMicrosoftJdkPaths jdks override! {typeof (JdkInfo).AssemblyQualifiedName}", null);
194-
Directory.Delete (jdks, recursive: true);
195280
if (File.Exists (backupConfig)) {
196281
File.Delete (UnixConfigPath);
197282
File.Move (backupConfig, UnixConfigPath);
198283
}
199284
}
200285
}
201286

202-
static void AssertJdkPath (string expectedJdkPath)
287+
void AssertJdkPath (string expectedJdkPath)
203288
{
204289
var config_file = XDocument.Load (UnixConfigPath);
205290
var javaEl = config_file.Root.Element ("java-sdk");
@@ -208,10 +293,9 @@ static void AssertJdkPath (string expectedJdkPath)
208293
Assert.AreEqual (expectedJdkPath, actualJdkPath);
209294
}
210295

211-
static string UnixConfigPath {
296+
string UnixConfigPath {
212297
get {
213-
var p = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
214-
return Path.Combine (Path.Combine (p, "xbuild"), "monodroid-config.xml");
298+
return Path.Combine (UnixConfigDirOverridePath, "monodroid-config.xml");
215299
}
216300
}
217301
}

src/Xamarin.Android.Tools.AndroidSdk/Tests/JdkInfoTests.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,18 @@ internal static void CreateFauxJdk (string dir, string version)
5858
Directory.CreateDirectory (jli);
5959
Directory.CreateDirectory (jre);
6060

61+
62+
string java =
63+
$"echo Property settings:{Environment.NewLine}" +
64+
$"echo \" java.home = {dir}\"{Environment.NewLine}" +
65+
$"echo \" java.vendor = Xamarin.Android Unit Tests\"{Environment.NewLine}" +
66+
$"echo \" java.version = 100.100.100\"{Environment.NewLine}" +
67+
$"echo \" xamarin.multi-line = line the first\"{Environment.NewLine}" +
68+
$"echo \" line the second\"{Environment.NewLine}" +
69+
$"echo \" .\"{Environment.NewLine}";
70+
6171
CreateShellScript (Path.Combine (bin, "jar"), "");
62-
CreateShellScript (Path.Combine (bin, "java"), JavaScript);
72+
CreateShellScript (Path.Combine (bin, "java"), java);
6373
CreateShellScript (Path.Combine (bin, "javac"), "");
6474
CreateShellScript (Path.Combine (dir, "jli", "libjli.dylib"), "");
6575
CreateShellScript (Path.Combine (jre, "libjvm.so"), "");
@@ -72,14 +82,6 @@ public void DeleteFauxJdk ()
7282
Directory.Delete (FauxJdkDir, recursive: true);
7383
}
7484

75-
static readonly string JavaScript =
76-
$"echo Property settings:{Environment.NewLine}" +
77-
$"echo \" java.vendor = Xamarin.Android Unit Tests\"{Environment.NewLine}" +
78-
$"echo \" java.version = 100.100.100\"{Environment.NewLine}" +
79-
$"echo \" xamarin.multi-line = line the first\"{Environment.NewLine}" +
80-
$"echo \" line the second\"{Environment.NewLine}" +
81-
$"echo \" .\"{Environment.NewLine}";
82-
8385
static void CreateShellScript (string path, string contents)
8486
{
8587
if (OS.IsWindows)
@@ -142,11 +144,14 @@ public void JavaSettingsProperties ()
142144
{
143145
var jdk = new JdkInfo (FauxJdkDir);
144146

145-
Assert.AreEqual (3, jdk.JavaSettingsPropertyKeys.Count ());
147+
Assert.AreEqual (4, jdk.JavaSettingsPropertyKeys.Count ());
146148

147149
Assert.IsFalse(jdk.GetJavaSettingsPropertyValue ("does-not-exist", out var _));
148150
Assert.IsFalse(jdk.GetJavaSettingsPropertyValues ("does-not-exist", out var _));
149151

152+
Assert.IsTrue (jdk.GetJavaSettingsPropertyValue ("java.home", out var home));
153+
Assert.AreEqual (FauxJdkDir, home);
154+
150155
Assert.IsTrue (jdk.GetJavaSettingsPropertyValue ("java.version", out var version));
151156
Assert.AreEqual ("100.100.100", version);
152157

0 commit comments

Comments
 (0)