SdkDirectoryWorkloadManifestProviderTests.cs 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460
  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. using System.Diagnostics.CodeAnalysis;
  4. using System.Runtime.CompilerServices;
  5. using Microsoft.DotNet.Cli;
  6. using Microsoft.NET.Sdk.Localization;
  7. using Microsoft.NET.Sdk.WorkloadManifestReader;
  8. namespace ManifestReaderTests
  9. {
  10. public class SdkDirectoryWorkloadManifestProviderTests : SdkTest
  11. {
  12. private string? _testDirectory;
  13. private string? _manifestRoot;
  14. private string? _manifestVersionBandDirectory;
  15. private string? _fakeDotnetRootDirectory;
  16. public SdkDirectoryWorkloadManifestProviderTests(ITestOutputHelper logger) : base(logger)
  17. {
  18. }
  19. [MemberNotNull("_testDirectory", "_manifestRoot", "_manifestVersionBandDirectory", "_fakeDotnetRootDirectory")]
  20. void Initialize(string featureBand = "5.0.100", [CallerMemberName] string? testName = null, string? identifier = null)
  21. {
  22. _testDirectory = _testAssetsManager.CreateTestDirectory(testName, identifier).Path;
  23. _fakeDotnetRootDirectory = Path.Combine(_testDirectory, "dotnet");
  24. _manifestRoot = Path.Combine(_fakeDotnetRootDirectory, "sdk-manifests");
  25. _manifestVersionBandDirectory = Path.Combine(_manifestRoot, featureBand);
  26. Directory.CreateDirectory(_manifestVersionBandDirectory);
  27. }
  28. [Theory]
  29. [InlineData(true)]
  30. [InlineData(false)]
  31. public void ItShouldReturnTheWorkloadVersion(bool useWorkloadSet)
  32. {
  33. Initialize();
  34. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  35. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true);
  36. CreateMockManifest(_manifestRoot, "8.0.200-rc.2", "maui", "15.0.1-rc.456", true);
  37. if (useWorkloadSet)
  38. {
  39. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", @"
  40. {
  41. ""ios"": ""11.0.2/8.0.100"",
  42. ""android"": ""33.0.2-rc.1/8.0.200"",
  43. ""maui"": ""15.0.1-rc.456/8.0.200-rc.2""
  44. }
  45. ");
  46. }
  47. var sdkDirectoryWorkloadManifestProvider
  48. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  49. if (useWorkloadSet)
  50. {
  51. sdkDirectoryWorkloadManifestProvider.GetWorkloadVersion().Should().Be("8.0.200");
  52. }
  53. else
  54. {
  55. string[] manifests = sdkDirectoryWorkloadManifestProvider.GetManifests().OrderBy(m => m.ManifestId).Select(m => $"{m.ManifestId}.{m.ManifestFeatureBand}.{m.ManifestVersion}").ToArray();
  56. manifests.Length.Should().Be(1);
  57. manifests.Should().Contain("android.8.0.200.33.0.2-rc.1");
  58. sdkDirectoryWorkloadManifestProvider.GetWorkloadVersion().Should().Be("8.0.200-manifests.4ba11739");
  59. }
  60. Directory.Delete(Path.Combine(_manifestRoot, "8.0.100"), recursive: true);
  61. Directory.Delete(Path.Combine(_manifestRoot, "8.0.200"), recursive: true);
  62. Directory.Delete(Path.Combine(_manifestRoot, "8.0.200-rc.2"), recursive: true);
  63. }
  64. [Fact]
  65. public void ItShouldReturnListOfManifestFiles()
  66. {
  67. Initialize();
  68. string androidManifestFileContent = "Android";
  69. string iosManifestFileContent = "iOS";
  70. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android"));
  71. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), androidManifestFileContent);
  72. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "iOS"));
  73. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), iosManifestFileContent);
  74. var sdkDirectoryWorkloadManifestProvider
  75. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", userProfileDir: null, globalJsonPath: null);
  76. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  77. .Should()
  78. .BeEquivalentTo(iosManifestFileContent, androidManifestFileContent);
  79. }
  80. [Fact]
  81. public void GivenSDKVersionItShouldReturnListOfManifestFilesForThisVersionBand()
  82. {
  83. Initialize();
  84. string androidManifestFileContent = "Android";
  85. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android"));
  86. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), androidManifestFileContent);
  87. var sdkDirectoryWorkloadManifestProvider
  88. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", userProfileDir: null, globalJsonPath: null);
  89. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  90. .Should()
  91. .BeEquivalentTo(androidManifestFileContent);
  92. }
  93. [Fact]
  94. public void GivenNoManifestDirectoryItShouldReturnEmpty()
  95. {
  96. Initialize();
  97. var sdkDirectoryWorkloadManifestProvider
  98. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", userProfileDir: null, globalJsonPath: null);
  99. sdkDirectoryWorkloadManifestProvider.GetManifests().Should().BeEmpty();
  100. }
  101. [Fact]
  102. public void GivenNoManifestJsonFileInDirectoryItShouldIgnoreIt()
  103. {
  104. Initialize();
  105. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android"));
  106. var sdkDirectoryWorkloadManifestProvider
  107. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", userProfileDir: null, globalJsonPath: null);
  108. sdkDirectoryWorkloadManifestProvider.GetManifests()
  109. .Should()
  110. .BeEmpty();
  111. }
  112. [Fact]
  113. public void ItReturnsLatestManifestVersion()
  114. {
  115. Initialize();
  116. CreateMockManifest(_manifestRoot, "5.0.100-preview.5", "ios", "11.0.3", true);
  117. CreateMockManifest(_manifestRoot, "5.0.100", "ios", "11.0.1", true);
  118. CreateMockManifest(_manifestRoot, "5.0.100", "ios", "11.0.2", true);
  119. CreateMockManifest(_manifestRoot, "5.0.100", "ios", "11.0.2-rc.1", true);
  120. var sdkDirectoryWorkloadManifestProvider
  121. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", userProfileDir: null, globalJsonPath: null);
  122. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  123. .Should()
  124. .BeEquivalentTo("ios: 11.0.2/5.0.100");
  125. }
  126. [Fact]
  127. public void ItPrefersManifestsInSubfolders()
  128. {
  129. Initialize();
  130. CreateMockManifest(_manifestRoot, "5.0.100", "ios", "11.0.1", true);
  131. CreateMockManifest(_manifestRoot, "5.0.100", "ios", "11.0.2", true);
  132. // Even though this manifest has a higher version, it is not in a versioned subfolder so the other manifests will be preferred
  133. // In real use, we would expect the manifest outside the versioned subfolders to be a lower version
  134. CreateMockManifest(_manifestRoot, "5.0.100", "ios", "12.0.1", false);
  135. var sdkDirectoryWorkloadManifestProvider
  136. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", userProfileDir: null, globalJsonPath: null);
  137. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  138. .Should()
  139. .BeEquivalentTo("ios: 11.0.2/5.0.100");
  140. }
  141. [Fact]
  142. public void ItFallsBackToLatestManifestVersion()
  143. {
  144. Initialize("8.0.200");
  145. var knownWorkloadsFilePath = Path.Combine(_fakeDotnetRootDirectory, "sdk", "8.0.100", "IncludedWorkloadManifests.txt");
  146. Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!);
  147. File.WriteAllText(knownWorkloadsFilePath, "android\nios");
  148. CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.0", true);
  149. CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.1", true);
  150. CreateMockManifest(_manifestRoot, "7.0.400", "android", "32.0.1", true);
  151. CreateMockManifest(_manifestRoot, "7.0.400", "ios", "17.0.1", true);
  152. CreateMockManifest(_manifestRoot, "7.0.400", "ios", "18.0.1", true);
  153. var sdkDirectoryWorkloadManifestProvider
  154. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.100", userProfileDir: null, globalJsonPath: null);
  155. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  156. .Should()
  157. .BeEquivalentTo("android: 33.0.1/8.0.100",
  158. "ios: 18.0.1/7.0.400");
  159. }
  160. [Fact]
  161. public void ItUsesManifestsFromWorkloadSet()
  162. {
  163. Initialize("8.0.200");
  164. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  165. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  166. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  167. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.1", true);
  168. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true);
  169. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2", true);
  170. CreateMockManifest(_manifestRoot, "8.0.200-rc.1", "maui", "15.0.1-preview.123", true);
  171. CreateMockManifest(_manifestRoot, "8.0.200-rc.2", "maui", "15.0.1-rc.456", true);
  172. CreateMockManifest(_manifestRoot, "8.0.200", "maui", "15.0.1", true);
  173. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """
  174. {
  175. "ios": "11.0.2/8.0.100",
  176. "android": "33.0.2-rc.1/8.0.200",
  177. "maui": "15.0.1-rc.456/8.0.200-rc.2"
  178. }
  179. """);
  180. var sdkDirectoryWorkloadManifestProvider
  181. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  182. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  183. .Should()
  184. .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2-rc.1/8.0.200", "maui: 15.0.1-rc.456/8.0.200-rc.2");
  185. }
  186. [Fact]
  187. public void WorkloadSetCanHaveTrailingCommasInJson()
  188. {
  189. Initialize("8.0.200");
  190. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  191. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true);
  192. CreateMockManifest(_manifestRoot, "8.0.200-rc.2", "maui", "15.0.1-rc.456", true);
  193. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """
  194. {
  195. "ios": "11.0.2/8.0.100",
  196. "android": "33.0.2-rc.1/8.0.200",
  197. "maui": "15.0.1-rc.456/8.0.200-rc.2",
  198. }
  199. """);
  200. var sdkDirectoryWorkloadManifestProvider
  201. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  202. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  203. .Should()
  204. .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2-rc.1/8.0.200", "maui: 15.0.1-rc.456/8.0.200-rc.2");
  205. }
  206. [Theory]
  207. [InlineData(false)]
  208. [InlineData(true)]
  209. public void ItUsesLatestWorkloadSet(bool globalJsonExists)
  210. {
  211. Initialize("8.0.200", identifier: globalJsonExists.ToString());
  212. string? globalJsonPath;
  213. if (globalJsonExists)
  214. {
  215. globalJsonPath = Path.Combine(_testDirectory, "global.json");
  216. File.WriteAllText(globalJsonPath, """
  217. {
  218. "sdk": {
  219. "version": "1.0.42",
  220. },
  221. "msbuild-sdks": {
  222. "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2",
  223. }
  224. }
  225. """);
  226. }
  227. else
  228. {
  229. globalJsonPath = null;
  230. }
  231. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  232. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  233. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  234. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.2", true);
  235. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  236. {
  237. "ios": "11.0.2/8.0.100"
  238. }
  239. """);
  240. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  241. {
  242. "ios": "12.0.1/8.0.200"
  243. }
  244. """);
  245. var sdkDirectoryWorkloadManifestProvider
  246. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath);
  247. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  248. .Should()
  249. .BeEquivalentTo("ios: 12.0.1/8.0.200");
  250. }
  251. [Fact]
  252. public void ItUsesLatestManifestThatIsNotInWorkloadSet()
  253. {
  254. Initialize("8.0.200");
  255. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  256. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  257. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  258. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.1", true);
  259. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true);
  260. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2", true);
  261. CreateMockManifest(_manifestRoot, "8.0.200-rc.1", "maui", "15.0.1-preview.123", true);
  262. CreateMockManifest(_manifestRoot, "8.0.200-rc.2", "maui", "15.0.1-rc.456", true);
  263. CreateMockManifest(_manifestRoot, "8.0.200", "maui", "15.0.1", true);
  264. CreateMockManifest(_manifestRoot, "8.0.200", "maui", "15.0.2", true);
  265. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """
  266. {
  267. "ios": "11.0.2/8.0.100",
  268. "android": "33.0.2-rc.1/8.0.200"
  269. }
  270. """);
  271. var sdkDirectoryWorkloadManifestProvider
  272. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  273. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  274. .Should()
  275. .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2-rc.1/8.0.200", "maui: 15.0.2/8.0.200");
  276. }
  277. [Fact]
  278. public void ItFallsBackForManifestNotInWorkloadSet()
  279. {
  280. Initialize("8.0.200");
  281. var knownWorkloadsFilePath = Path.Combine(_fakeDotnetRootDirectory, "sdk", "8.0.201", "IncludedWorkloadManifests.txt");
  282. Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!);
  283. File.WriteAllText(knownWorkloadsFilePath, "android\nios\nmaui");
  284. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  285. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  286. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  287. CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.1", true);
  288. CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.2-rc.1", true);
  289. CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.2", true);
  290. CreateMockManifest(_manifestRoot, "8.0.200-rc.1", "maui", "15.0.1-preview.123", true);
  291. CreateMockManifest(_manifestRoot, "8.0.200-rc.2", "maui", "15.0.1-rc.456", true);
  292. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  293. {
  294. "ios": "11.0.2/8.0.100"
  295. }
  296. """);
  297. var sdkDirectoryWorkloadManifestProvider
  298. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.201", userProfileDir: null, globalJsonPath: null);
  299. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  300. .Should()
  301. .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2/8.0.100", "maui: 15.0.1-rc.456/8.0.200-rc.2");
  302. }
  303. [Fact]
  304. public void ItThrowsIfWorkloadSetHasInvalidVersion()
  305. {
  306. Initialize("8.0.200");
  307. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  308. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  309. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  310. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200.1", """
  311. {
  312. "ios": "11.0.2/8.0.100"
  313. }
  314. """);
  315. Assert.Throws<FormatException>(() => new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null));
  316. }
  317. [Fact]
  318. public void ItThrowsIfManifestFromWorkloadSetIsNotFound()
  319. {
  320. Initialize("8.0.200");
  321. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  322. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  323. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  324. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """
  325. {
  326. "ios": "12.0.2/8.0.200"
  327. }
  328. """);
  329. var sdkDirectoryWorkloadManifestProvider
  330. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  331. Assert.Throws<FileNotFoundException>(() => GetManifestContents(sdkDirectoryWorkloadManifestProvider).ToList());
  332. }
  333. [Fact]
  334. public void WorkloadSetCanIncludeMultipleJsonFiles()
  335. {
  336. Initialize("8.0.200");
  337. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  338. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  339. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  340. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.1", true);
  341. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true);
  342. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2", true);
  343. var workloadSetDirectory = Path.Combine(_manifestRoot, "8.0.200", "workloadsets", "8.0.200");
  344. Directory.CreateDirectory(workloadSetDirectory);
  345. File.WriteAllText(Path.Combine(workloadSetDirectory, "1.workloadset.json"), """
  346. {
  347. "ios": "11.0.2/8.0.100"
  348. }
  349. """);
  350. File.WriteAllText(Path.Combine(workloadSetDirectory, "2.workloadset.json"), """
  351. {
  352. "android": "33.0.2-rc.1/8.0.200"
  353. }
  354. """);
  355. var sdkDirectoryWorkloadManifestProvider
  356. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  357. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  358. .Should()
  359. .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2-rc.1/8.0.200");
  360. }
  361. [Fact]
  362. public void ItThrowsExceptionIfWorkloadSetJsonFilesHaveDuplicateManifests()
  363. {
  364. Initialize("8.0.200");
  365. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  366. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  367. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  368. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.1", true);
  369. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true);
  370. CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2", true);
  371. var workloadSetDirectory = Path.Combine(_manifestRoot, "8.0.200", "workloadsets", "8.0.200");
  372. Directory.CreateDirectory(workloadSetDirectory);
  373. File.WriteAllText(Path.Combine(workloadSetDirectory, "1.workloadset.json"), """
  374. {
  375. "ios": "11.0.2/8.0.100"
  376. }
  377. """);
  378. File.WriteAllText(Path.Combine(workloadSetDirectory, "2.workloadset.json"), """
  379. {
  380. "android": "33.0.2-rc.1/8.0.200",
  381. "ios": "11.0.2/8.0.100"
  382. }
  383. """);
  384. Assert.Throws<ArgumentException>(() =>
  385. new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null));
  386. }
  387. [Fact]
  388. public void ItUsesWorkloadSetFromGlobalJson()
  389. {
  390. Initialize("8.0.200");
  391. string? globalJsonPath = Path.Combine(_testDirectory, "global.json");
  392. File.WriteAllText(globalJsonPath, """
  393. {
  394. "sdk": {
  395. "version": "8.0.200",
  396. "workloadVersion": "8.0.201"
  397. },
  398. "msbuild-sdks": {
  399. "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2",
  400. }
  401. }
  402. """);
  403. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  404. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  405. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  406. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  407. {
  408. "ios": "11.0.2/8.0.100"
  409. }
  410. """);
  411. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  412. {
  413. "ios": "12.0.1/8.0.200"
  414. }
  415. """);
  416. var sdkDirectoryWorkloadManifestProvider
  417. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath);
  418. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  419. .Should()
  420. .BeEquivalentTo("ios: 11.0.2/8.0.100");
  421. }
  422. [Fact]
  423. public void ItFailsIfWorkloadSetFromGlobalJsonIsNotInstalled()
  424. {
  425. Initialize("8.0.200");
  426. string? globalJsonPath = Path.Combine(_testDirectory, "global.json");
  427. File.WriteAllText(globalJsonPath, """
  428. {
  429. "sdk": {
  430. "version": "8.0.200",
  431. "workloadVersion": "8.0.201"
  432. },
  433. "msbuild-sdks": {
  434. "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2",
  435. }
  436. }
  437. """);
  438. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  439. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  440. {
  441. "ios": "12.0.1/8.0.200"
  442. }
  443. """);
  444. var manifestProvider = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath);
  445. var ex = Assert.Throws<FileNotFoundException>(() => manifestProvider.GetManifests());
  446. ex.Message.Should().Be(string.Format(Strings.WorkloadVersionFromGlobalJsonNotFound, "8.0.201", globalJsonPath));
  447. }
  448. [Fact]
  449. public void ItFailsIfGlobalJsonIsMalformed()
  450. {
  451. Initialize("8.0.200");
  452. string? globalJsonPath = Path.Combine(_testDirectory, "global.json");
  453. File.WriteAllText(globalJsonPath, """
  454. {
  455. "sdk": {
  456. "workloadVersion": [ "8.0.202" ]
  457. }
  458. }
  459. """);
  460. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  461. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  462. {
  463. "ios": "12.0.1/8.0.200"
  464. }
  465. """);
  466. var ex = Assert.Throws<SdkDirectoryWorkloadManifestProvider.JsonFormatException>(
  467. () => new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath));
  468. }
  469. [Fact]
  470. public void ItUsesWorkloadSetFromInstallState()
  471. {
  472. Initialize("8.0.200");
  473. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  474. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  475. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  476. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  477. {
  478. "ios": "11.0.2/8.0.100"
  479. }
  480. """);
  481. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  482. {
  483. "ios": "12.0.1/8.0.200"
  484. }
  485. """);
  486. CreateMockInstallState("8.0.200",
  487. """
  488. {
  489. "workloadVersion": "8.0.201"
  490. }
  491. """);
  492. var sdkDirectoryWorkloadManifestProvider
  493. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  494. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  495. .Should()
  496. .BeEquivalentTo("ios: 11.0.2/8.0.100");
  497. }
  498. [Fact]
  499. public void ItFailsIfWorkloadSetFromInstallStateIsNotInstalled()
  500. {
  501. Initialize("8.0.200");
  502. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  503. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  504. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  505. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  506. {
  507. "ios": "11.0.2/8.0.100"
  508. }
  509. """);
  510. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  511. {
  512. "ios": "12.0.1/8.0.200"
  513. }
  514. """);
  515. var installStatePath = CreateMockInstallState("8.0.200",
  516. """
  517. {
  518. "workloadVersion": "8.0.203"
  519. }
  520. """);
  521. var ex = Assert.Throws<FileNotFoundException>(
  522. () => new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null));
  523. ex.Message.Should().Be(string.Format(Strings.WorkloadVersionFromInstallStateNotFound, "8.0.203", installStatePath));
  524. }
  525. [Fact]
  526. public void ItFailsIfManifestFromWorkloadSetFromInstallStateIsNotInstalled()
  527. {
  528. Initialize("8.0.200");
  529. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  530. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  531. {
  532. "ios": "11.0.2/8.0.100"
  533. }
  534. """);
  535. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  536. {
  537. "ios": "12.0.1/8.0.200"
  538. }
  539. """);
  540. var installStatePath = CreateMockInstallState("8.0.200",
  541. """
  542. {
  543. "workloadVersion": "8.0.201"
  544. }
  545. """);
  546. var sdkDirectoryWorkloadManifestProvider
  547. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  548. var ex = Assert.Throws<FileNotFoundException>(() => sdkDirectoryWorkloadManifestProvider.GetManifests().ToList());
  549. ex.Message.Should().Be(string.Format(Strings.ManifestFromWorkloadSetNotFound, "ios: 11.0.2/8.0.100", "8.0.201"));
  550. }
  551. [Fact]
  552. public void ItUsesWorkloadManifestFromInstallState()
  553. {
  554. Initialize("8.0.200");
  555. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  556. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  557. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  558. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  559. {
  560. "ios": "11.0.2/8.0.100"
  561. }
  562. """);
  563. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  564. {
  565. "ios": "12.0.1/8.0.200"
  566. }
  567. """);
  568. CreateMockInstallState("8.0.200",
  569. """
  570. {
  571. "manifests": {
  572. "ios": "11.0.1/8.0.100",
  573. }
  574. }
  575. """);
  576. var sdkDirectoryWorkloadManifestProvider
  577. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  578. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  579. .Should()
  580. .BeEquivalentTo("ios: 11.0.1/8.0.100");
  581. }
  582. [Fact]
  583. public void ItFailsIfManifestFromInstallStateIsNotInstalled()
  584. {
  585. Initialize("8.0.200");
  586. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  587. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  588. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  589. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  590. {
  591. "ios": "11.0.2/8.0.100"
  592. }
  593. """);
  594. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  595. {
  596. "ios": "12.0.1/8.0.200"
  597. }
  598. """);
  599. var installStatePath = CreateMockInstallState("8.0.200",
  600. """
  601. {
  602. "manifests": {
  603. "ios": "12.0.2/8.0.200",
  604. }
  605. }
  606. """);
  607. var sdkDirectoryWorkloadManifestProvider
  608. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  609. var ex = Assert.Throws<FileNotFoundException>(() => sdkDirectoryWorkloadManifestProvider.GetManifests().ToList());
  610. ex.Message.Should().Be(string.Format(Strings.ManifestFromInstallStateNotFound, "ios: 12.0.2/8.0.200", installStatePath));
  611. }
  612. [Fact]
  613. public void ItUsesWorkloadSetAndManifestFromInstallState()
  614. {
  615. Initialize("8.0.200");
  616. CreateMockManifest(_manifestRoot, "8.0.200", "tizen", "8.0.0", true);
  617. CreateMockManifest(_manifestRoot, "8.0.200", "tizen", "8.0.1", true);
  618. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  619. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  620. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  621. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  622. {
  623. "ios": "11.0.2/8.0.100"
  624. }
  625. """);
  626. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  627. {
  628. "ios": "12.0.1/8.0.200"
  629. }
  630. """);
  631. CreateMockInstallState("8.0.200",
  632. """
  633. {
  634. "workloadVersion": "8.0.201",
  635. "manifests": {
  636. "tizen": "8.0.0/8.0.200",
  637. }
  638. }
  639. """);
  640. var sdkDirectoryWorkloadManifestProvider
  641. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  642. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  643. .Should()
  644. .BeEquivalentTo("ios: 11.0.2/8.0.100", "tizen: 8.0.0/8.0.200");
  645. }
  646. [Fact]
  647. public void WorkloadManifestFromInstallStateOverridesWorkloadSetFromInstallState()
  648. {
  649. Initialize("8.0.200");
  650. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  651. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  652. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  653. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  654. {
  655. "ios": "11.0.2/8.0.100"
  656. }
  657. """);
  658. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  659. {
  660. "ios": "12.0.1/8.0.200"
  661. }
  662. """);
  663. CreateMockInstallState("8.0.200",
  664. """
  665. {
  666. "workloadVersion": "8.0.201",
  667. "manifests": {
  668. "ios": "11.0.1/8.0.100",
  669. }
  670. }
  671. """);
  672. var sdkDirectoryWorkloadManifestProvider
  673. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  674. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  675. .Should()
  676. .BeEquivalentTo("ios: 11.0.1/8.0.100");
  677. }
  678. // Falls back for manifest not in install state
  679. [Fact]
  680. public void ItFallsBackForManifestNotInInstallState()
  681. {
  682. Initialize("8.0.200");
  683. var knownWorkloadsFilePath = Path.Combine(_fakeDotnetRootDirectory, "sdk", "8.0.201", "IncludedWorkloadManifests.txt");
  684. Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!);
  685. File.WriteAllText(knownWorkloadsFilePath, "android\nios\nmaui");
  686. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  687. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  688. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  689. CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.1", true);
  690. CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.2-rc.1", true);
  691. CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.2", true);
  692. CreateMockInstallState("8.0.200",
  693. """
  694. {
  695. "manifests": {
  696. "ios": "12.0.1/8.0.200"
  697. }
  698. }
  699. """);
  700. var sdkDirectoryWorkloadManifestProvider
  701. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.201", userProfileDir: null, globalJsonPath: null);
  702. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  703. .Should()
  704. .BeEquivalentTo("ios: 12.0.1/8.0.200", "android: 33.0.2/8.0.100");
  705. }
  706. [Fact]
  707. public void GlobalJsonOverridesInstallState()
  708. {
  709. Initialize("8.0.200");
  710. string? globalJsonPath = Path.Combine(_testDirectory, "global.json");
  711. File.WriteAllText(globalJsonPath, """
  712. {
  713. "sdk": {
  714. "version": "8.0.200",
  715. "workloadVersion": "8.0.201"
  716. },
  717. "msbuild-sdks": {
  718. "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2",
  719. }
  720. }
  721. """);
  722. CreateMockInstallState("8.0.200",
  723. """
  724. {
  725. "workloadVersion": "8.0.202",
  726. }
  727. """);
  728. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  729. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  730. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  731. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  732. {
  733. "ios": "11.0.2/8.0.100"
  734. }
  735. """);
  736. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  737. {
  738. "ios": "12.0.1/8.0.200"
  739. }
  740. """);
  741. var sdkDirectoryWorkloadManifestProvider
  742. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath);
  743. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  744. .Should()
  745. .BeEquivalentTo("ios: 11.0.2/8.0.100");
  746. }
  747. [Fact]
  748. public void GlobalJsonWithoutWorkloadVersionDoesNotOverrideInstallState()
  749. {
  750. Initialize("8.0.200");
  751. string? globalJsonPath = Path.Combine(_testDirectory, "global.json");
  752. File.WriteAllText(globalJsonPath, "{}");
  753. CreateMockInstallState("8.0.200",
  754. """
  755. {
  756. "workloadVersion": "8.0.200",
  757. }
  758. """);
  759. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true);
  760. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true);
  761. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true);
  762. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """
  763. {
  764. "ios": "11.0.1/8.0.100"
  765. }
  766. """);
  767. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """
  768. {
  769. "ios": "11.0.2/8.0.100"
  770. }
  771. """);
  772. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """
  773. {
  774. "ios": "12.0.1/8.0.200"
  775. }
  776. """);
  777. var sdkDirectoryWorkloadManifestProvider
  778. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath);
  779. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  780. .Should()
  781. .BeEquivalentTo("ios: 11.0.1/8.0.100");
  782. }
  783. [Fact]
  784. public void ItShouldReturnManifestsFromTestHook()
  785. {
  786. Initialize();
  787. string sdkVersion = "5.0.100";
  788. var additionalManifestDirectory = Path.Combine(_testDirectory, "AdditionalManifests");
  789. Directory.CreateDirectory(additionalManifestDirectory);
  790. var environmentMock = new EnvironmentMock();
  791. environmentMock.Add(EnvironmentVariableNames.WORKLOAD_MANIFEST_ROOTS, additionalManifestDirectory);
  792. // Manifest in test hook directory
  793. Directory.CreateDirectory(Path.Combine(additionalManifestDirectory, sdkVersion, "Android"));
  794. File.WriteAllText(Path.Combine(additionalManifestDirectory, sdkVersion, "Android", "WorkloadManifest.json"), "Android: AndroidContent");
  795. // Manifest in default directory
  796. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "iOS"));
  797. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOS: iOSContent");
  798. var sdkDirectoryWorkloadManifestProvider
  799. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: sdkVersion, environmentMock.GetEnvironmentVariable, userProfileDir: null);
  800. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  801. .Should()
  802. .BeEquivalentTo("Android: AndroidContent", "iOS: iOSContent");
  803. }
  804. [Fact]
  805. public void ManifestFromTestHookShouldOverrideDefault()
  806. {
  807. Initialize();
  808. string sdkVersion = "5.0.100";
  809. var additionalManifestDirectory = Path.Combine(_testDirectory, "AdditionalManifests");
  810. Directory.CreateDirectory(additionalManifestDirectory);
  811. var environmentMock = new EnvironmentMock();
  812. environmentMock.Add(EnvironmentVariableNames.WORKLOAD_MANIFEST_ROOTS, additionalManifestDirectory);
  813. // Manifest in test hook directory
  814. Directory.CreateDirectory(Path.Combine(additionalManifestDirectory, sdkVersion, "Android"));
  815. File.WriteAllText(Path.Combine(additionalManifestDirectory, sdkVersion, "Android", "WorkloadManifest.json"), "Android: OverridingAndroidContent");
  816. // Manifest in default directory
  817. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android"));
  818. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "Android: OverriddenAndroidContent");
  819. var sdkDirectoryWorkloadManifestProvider
  820. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: sdkVersion, environmentMock.GetEnvironmentVariable, userProfileDir: null);
  821. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  822. .Should()
  823. .BeEquivalentTo("Android: OverridingAndroidContent");
  824. }
  825. [Fact]
  826. public void ItSupportsMultipleTestHookFolders()
  827. {
  828. Initialize();
  829. string sdkVersion = "5.0.100";
  830. var additionalManifestDirectory1 = Path.Combine(_testDirectory, "AdditionalManifests1");
  831. Directory.CreateDirectory(additionalManifestDirectory1);
  832. var additionalManifestDirectory2 = Path.Combine(_testDirectory, "AdditionalManifests2");
  833. Directory.CreateDirectory(additionalManifestDirectory2);
  834. var environmentMock = new EnvironmentMock();
  835. environmentMock.Add(EnvironmentVariableNames.WORKLOAD_MANIFEST_ROOTS, additionalManifestDirectory1 + Path.PathSeparator + additionalManifestDirectory2);
  836. // Manifests in default directory
  837. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "iOS"));
  838. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOS: iOSContent");
  839. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android"));
  840. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "Android: DefaultAndroidContent");
  841. // Manifests in first additional directory
  842. Directory.CreateDirectory(Path.Combine(additionalManifestDirectory1, sdkVersion, "Android"));
  843. File.WriteAllText(Path.Combine(additionalManifestDirectory1, sdkVersion, "Android", "WorkloadManifest.json"), "Android: AndroidContent1");
  844. // Manifests in second additional directory
  845. Directory.CreateDirectory(Path.Combine(additionalManifestDirectory2, sdkVersion, "Android"));
  846. File.WriteAllText(Path.Combine(additionalManifestDirectory2, sdkVersion, "Android", "WorkloadManifest.json"), "Android: AndroidContent2");
  847. Directory.CreateDirectory(Path.Combine(additionalManifestDirectory2, sdkVersion, "Test"));
  848. File.WriteAllText(Path.Combine(additionalManifestDirectory2, sdkVersion, "Test", "WorkloadManifest.json"), "Test: TestContent2");
  849. var sdkDirectoryWorkloadManifestProvider
  850. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: sdkVersion, environmentMock.GetEnvironmentVariable, userProfileDir: null);
  851. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  852. .Should()
  853. .BeEquivalentTo("Android: AndroidContent1", "iOS: iOSContent", "Test: TestContent2");
  854. }
  855. [Fact]
  856. public void IfTestHookFolderDoesNotExistItShouldBeIgnored()
  857. {
  858. Initialize();
  859. var additionalManifestDirectory = Path.Combine(_testDirectory, "AdditionalManifests");
  860. var environmentMock = new EnvironmentMock();
  861. environmentMock.Add(EnvironmentVariableNames.WORKLOAD_MANIFEST_ROOTS, additionalManifestDirectory);
  862. // Manifest in default directory
  863. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android"));
  864. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "Android: AndroidContent");
  865. var sdkDirectoryWorkloadManifestProvider
  866. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", environmentMock.GetEnvironmentVariable, userProfileDir: null);
  867. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  868. .Should()
  869. .BeEquivalentTo("Android: AndroidContent");
  870. }
  871. [Fact]
  872. public void ItShouldIgnoreOutdatedManifestIds()
  873. {
  874. Initialize();
  875. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "iOS"));
  876. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOS: iOSContent");
  877. Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Microsoft.NET.Workload.Android"));
  878. File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Microsoft.NET.Workload.Android", "WorkloadManifest.json"), "Microsoft.NET.Workload.Android: AndroidContent");
  879. var sdkDirectoryWorkloadManifestProvider
  880. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", userProfileDir: null, globalJsonPath: null);
  881. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  882. .Should()
  883. .BeEquivalentTo("iOS: iOSContent");
  884. }
  885. [Fact]
  886. public void ItShouldFallbackWhenFeatureBandHasNoManifests()
  887. {
  888. Initialize("6.0.100");
  889. // Write 4.0.100 manifests-> android only
  890. CreateMockManifest(_manifestRoot, "4.0.100", "Android", "1");
  891. // Write 5.0.100 manifests-> ios and android
  892. CreateMockManifest(_manifestRoot, "5.0.100", "Android", "2");
  893. CreateMockManifest(_manifestRoot, "5.0.100", "iOS", "3");
  894. // Write 6.0.100 manifests-> ios only
  895. CreateMockManifest(_manifestRoot, "6.0.100", "iOS", "4");
  896. // Write 7.0.100 manifests-> ios and android
  897. CreateMockManifest(_manifestRoot, "7.0.100", "Android", "5");
  898. CreateMockManifest(_manifestRoot, "7.0.100", "iOS", "6");
  899. var knownWorkloadsFilePath = Path.Combine(_fakeDotnetRootDirectory, "sdk", "6.0.100", "IncludedWorkloadManifests.txt");
  900. Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!);
  901. File.WriteAllText(knownWorkloadsFilePath, "Android\niOS");
  902. var sdkDirectoryWorkloadManifestProvider
  903. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "6.0.100", userProfileDir: null, globalJsonPath: null);
  904. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  905. .Should()
  906. .BeEquivalentTo("iOS: 4/6.0.100", "Android: 2/5.0.100");
  907. }
  908. [Fact]
  909. public void ItShouldFallbackWhenPreviewFeatureBandHasNoManifests()
  910. {
  911. Initialize("6.0.100");
  912. // Write 4.0.100 manifests-> android only
  913. CreateMockManifest(_manifestRoot, "4.0.100", "iOS", "1");
  914. // Write 5.0.100 manifests-> android
  915. CreateMockManifest(_manifestRoot, "5.0.100", "Android", "2");
  916. // Write 6.0.100-preview.2 manifests-> ios only
  917. CreateMockManifest(_manifestRoot, "6.0.100-preview.2", "iOS", "3");
  918. // Write 7.0.100 manifests-> ios and android
  919. CreateMockManifest(_manifestRoot, "7.0.100", "Android", "4");
  920. CreateMockManifest(_manifestRoot, "7.0.100", "iOS", " 5");
  921. var prev4Version = "6.0.100-preview.4.12345";
  922. var knownWorkloadsFilePath = Path.Combine(_fakeDotnetRootDirectory, "sdk", prev4Version, "IncludedWorkloadManifests.txt");
  923. Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!);
  924. File.WriteAllText(knownWorkloadsFilePath, "Android\niOS");
  925. var sdkDirectoryWorkloadManifestProvider
  926. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: prev4Version, userProfileDir: null, globalJsonPath: null);
  927. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  928. .Should()
  929. .BeEquivalentTo("iOS: 3/6.0.100-preview.2", "Android: 2/5.0.100");
  930. }
  931. [Fact]
  932. public void ItShouldRollForwardToNonPrereleaseWhenPreviewFeatureBandHasNoManifests()
  933. {
  934. Initialize("6.0.100");
  935. // Write 4.0.100 manifests-> android only
  936. CreateMockManifest(_manifestRoot, "4.0.100", "Android", "1");
  937. // Write 5.0.100 manifests-> ios and android
  938. CreateMockManifest(_manifestRoot, "5.0.100", "Android", "2");
  939. CreateMockManifest(_manifestRoot, "5.0.100", "iOS", "3");
  940. // Write 6.0.100-preview.4 manifests-> ios only
  941. CreateMockManifest(_manifestRoot, "6.0.100-preview.4", "iOS", "4");
  942. // Write 6.0.100 manifests-> android
  943. CreateMockManifest(_manifestRoot, "6.0.100", "Android", "5");
  944. var prev4Version = "6.0.100-preview.4.12345";
  945. var knownWorkloadsFilePath = Path.Combine(_fakeDotnetRootDirectory, "sdk", prev4Version, "IncludedWorkloadManifests.txt");
  946. Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!);
  947. File.WriteAllText(knownWorkloadsFilePath, "Android\niOS");
  948. var sdkDirectoryWorkloadManifestProvider
  949. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: prev4Version, userProfileDir: null, globalJsonPath: null);
  950. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  951. .Should()
  952. .BeEquivalentTo("iOS: 4/6.0.100-preview.4", "Android: 5/6.0.100");
  953. }
  954. [Fact]
  955. public void ItReturnsManifestsInOrderFromKnownWorkloadManifestsFile()
  956. {
  957. // microsoft.net.workload.mono.toolchain.net6, microsoft.net.workload.mono.toolchain.net7, microsoft.net.workload.emscripten.net6, microsoft.net.workload.emscripten.net7
  958. var currentSdkVersion = "7.0.100";
  959. var fallbackWorkloadBand = "7.0.100-rc.2";
  960. Initialize(currentSdkVersion);
  961. CreateMockManifest(_manifestRoot, currentSdkVersion, "NotInIncudedWorkloadsFile", "1");
  962. CreateMockManifest(_manifestRoot, currentSdkVersion, "Microsoft.Net.Workload.Mono.Toolchain.net6", "2");
  963. CreateMockManifest(_manifestRoot, fallbackWorkloadBand, "Microsoft.Net.Workload.Mono.Toolchain.net7", "3");
  964. CreateMockManifest(_manifestRoot, fallbackWorkloadBand, "Microsoft.Net.Workload.Emscripten.net6", "4");
  965. CreateMockManifest(_manifestRoot, currentSdkVersion, "Microsoft.Net.Workload.Emscripten.net7", "5");
  966. var knownWorkloadsFilePath = Path.Combine(_fakeDotnetRootDirectory, "sdk", currentSdkVersion, "IncludedWorkloadManifests.txt");
  967. Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!);
  968. File.WriteAllText(knownWorkloadsFilePath, @"
  969. Microsoft.Net.Workload.Mono.Toolchain.net6
  970. Microsoft.Net.Workload.Mono.Toolchain.net7
  971. Microsoft.Net.Workload.Emscripten.net6
  972. Microsoft.Net.Workload.Emscripten.net7"
  973. .Trim());
  974. var sdkDirectoryWorkloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: currentSdkVersion, userProfileDir: null, globalJsonPath: null);
  975. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  976. .Should()
  977. .Equal($"Microsoft.Net.Workload.Mono.Toolchain.net6: 2/{currentSdkVersion}",
  978. $"Microsoft.Net.Workload.Mono.Toolchain.net7: 3/{fallbackWorkloadBand}",
  979. $"Microsoft.Net.Workload.Emscripten.net6: 4/{fallbackWorkloadBand}",
  980. $"Microsoft.Net.Workload.Emscripten.net7: 5/{currentSdkVersion}",
  981. $"NotInIncudedWorkloadsFile: 1/{currentSdkVersion}");
  982. }
  983. private void CreateMockManifest(string manifestRoot, string featureBand, string manifestId, string manifestVersion, bool useVersionFolder = false, string? manifestContents = null)
  984. {
  985. var manifestDirectory = Path.Combine(manifestRoot, featureBand, manifestId);
  986. if (useVersionFolder)
  987. {
  988. manifestDirectory = Path.Combine(manifestDirectory, manifestVersion);
  989. }
  990. if (!Directory.Exists(manifestDirectory))
  991. {
  992. Directory.CreateDirectory(manifestDirectory);
  993. }
  994. if (manifestContents == null)
  995. {
  996. manifestContents = $"{manifestId}: {manifestVersion}/{featureBand}";
  997. }
  998. File.WriteAllText(Path.Combine(manifestDirectory, "WorkloadManifest.json"), manifestContents);
  999. }
  1000. private void CreateMockWorkloadSet(string manifestRoot, string featureBand, string workloadSetVersion, string workloadSetContents)
  1001. {
  1002. var workloadSetDirectory = Path.Combine(manifestRoot, featureBand, "workloadsets", workloadSetVersion);
  1003. if (!Directory.Exists(workloadSetDirectory))
  1004. {
  1005. Directory.CreateDirectory(workloadSetDirectory);
  1006. }
  1007. File.WriteAllText(Path.Combine(workloadSetDirectory, "workloadset.workloadset.json"), workloadSetContents);
  1008. }
  1009. private string CreateMockInstallState(string featureBand, string installStateContents)
  1010. {
  1011. var installStateFolder = Path.Combine(_fakeDotnetRootDirectory!, "metadata", "workloads", RuntimeInformation.ProcessArchitecture.ToString(), featureBand, "InstallState");
  1012. Directory.CreateDirectory(installStateFolder);
  1013. string installStatePath = Path.Combine(installStateFolder, "default.json");
  1014. File.WriteAllText(installStatePath, installStateContents);
  1015. return installStatePath;
  1016. }
  1017. [Fact]
  1018. public void ItShouldIgnoreManifestsNotFoundInFallback()
  1019. {
  1020. var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
  1021. var fakeDotnetRootDirectory = Path.Combine(testDirectory, "dotnet");
  1022. // Write 6.0.100 manifests-> ios only
  1023. var manifestDirectory6 = Path.Combine(fakeDotnetRootDirectory, "sdk-manifests", "6.0.100");
  1024. Directory.CreateDirectory(manifestDirectory6);
  1025. Directory.CreateDirectory(Path.Combine(manifestDirectory6, "iOS"));
  1026. File.WriteAllText(Path.Combine(manifestDirectory6, "iOS", "WorkloadManifest.json"), "iOS: iOS-6.0.100");
  1027. var knownWorkloadsFilePath = Path.Combine(fakeDotnetRootDirectory, "sdk", "6.0.100", "KnownWorkloadManifests.txt");
  1028. Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!);
  1029. File.WriteAllText(knownWorkloadsFilePath, "Android\niOS");
  1030. var sdkDirectoryWorkloadManifestProvider
  1031. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: fakeDotnetRootDirectory, sdkVersion: "6.0.100", userProfileDir: null, globalJsonPath: null);
  1032. GetManifestContents(sdkDirectoryWorkloadManifestProvider)
  1033. .Should()
  1034. .BeEquivalentTo("iOS: iOS-6.0.100");
  1035. }
  1036. [Fact]
  1037. public void WorkloadResolverUsesManifestsFromWorkloadSet()
  1038. {
  1039. Initialize("8.0.200");
  1040. string manifestContents1 = """
  1041. {
  1042. "version": "11.0.1",
  1043. "workloads": {
  1044. "ios": {
  1045. "description": "iOS workload",
  1046. "kind": "dev",
  1047. "packs": [ "Microsoft.NET.iOS.Workload" ]
  1048. },
  1049. },
  1050. "packs": {
  1051. "Microsoft.NET.iOS.Workload" : {
  1052. "kind": "sdk",
  1053. "version": "1"
  1054. }
  1055. }
  1056. }
  1057. """;
  1058. string manifestContents2 = """
  1059. {
  1060. "version": "11.0.2",
  1061. "workloads": {
  1062. "ios": {
  1063. "description": "iOS workload",
  1064. "kind": "dev",
  1065. "packs": [ "Microsoft.NET.iOS.Workload" ]
  1066. },
  1067. },
  1068. "packs": {
  1069. "Microsoft.NET.iOS.Workload" : {
  1070. "kind": "sdk",
  1071. "version": "2"
  1072. }
  1073. }
  1074. }
  1075. """;
  1076. string manifestContents3 = """
  1077. {
  1078. "version": "12.0.1",
  1079. "workloads": {
  1080. "ios": {
  1081. "description": "iOS workload",
  1082. "kind": "dev",
  1083. "packs": [ "Microsoft.NET.iOS.Workload" ]
  1084. },
  1085. },
  1086. "packs": {
  1087. "Microsoft.NET.iOS.Workload" : {
  1088. "kind": "sdk",
  1089. "version": "3"
  1090. }
  1091. }
  1092. }
  1093. """;
  1094. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true, manifestContents1);
  1095. CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true, manifestContents2);
  1096. CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true, manifestContents3);
  1097. CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """
  1098. {
  1099. "ios": "11.0.2/8.0.100"
  1100. }
  1101. """);
  1102. var sdkDirectoryWorkloadManifestProvider
  1103. = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null);
  1104. var workloadResolver = WorkloadResolver.CreateForTests(sdkDirectoryWorkloadManifestProvider, _fakeDotnetRootDirectory);
  1105. var workloads = workloadResolver.GetAvailableWorkloads();
  1106. workloads.Count().Should().Be(1);
  1107. var expectedPackId = new WorkloadPackId("Microsoft.NET.iOS.Workload");
  1108. workloadResolver.GetPacksInWorkload(workloads.Single().Id).Should().BeEquivalentTo(new[] { expectedPackId });
  1109. var packInfo = workloadResolver.TryGetPackInfo(expectedPackId);
  1110. packInfo.Should().NotBeNull();
  1111. packInfo!.Version.Should().Be("2");
  1112. workloadResolver.GetInstalledManifests().Count().Should().Be(1);
  1113. var manifestInfo = workloadResolver.GetInstalledManifests().Single();
  1114. manifestInfo.Id.Should().Be("ios");
  1115. manifestInfo.Version.Should().Be("11.0.2");
  1116. manifestInfo.ManifestFeatureBand.Should().Be("8.0.100");
  1117. manifestInfo.ManifestDirectory.Should().Be(Path.Combine(_manifestRoot, "8.0.100", "ios", "11.0.2"));
  1118. }
  1119. private IEnumerable<string> GetManifestContents(SdkDirectoryWorkloadManifestProvider manifestProvider)
  1120. {
  1121. return manifestProvider.GetManifests().Select(manifest =>
  1122. {
  1123. var contents = new StreamReader(manifest.OpenManifestStream()).ReadToEnd();
  1124. string manifestId = contents.Split(':')[0];
  1125. manifest.ManifestId.Should().Be(manifestId);
  1126. return contents;
  1127. });
  1128. }
  1129. private class EnvironmentMock
  1130. {
  1131. Dictionary<string, string> _mockedEnvironmentVariables = new(StringComparer.OrdinalIgnoreCase);
  1132. public void Add(string variable, string value)
  1133. {
  1134. _mockedEnvironmentVariables[variable] = value;
  1135. }
  1136. public string? GetEnvironmentVariable(string variable)
  1137. {
  1138. if (_mockedEnvironmentVariables.TryGetValue(variable, out string? value))
  1139. {
  1140. return value;
  1141. }
  1142. return Environment.GetEnvironmentVariable(variable);
  1143. }
  1144. }
  1145. }
  1146. }
  1147. #if NETFRAMEWORK
  1148. namespace System.Diagnostics.CodeAnalysis
  1149. {
  1150. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
  1151. sealed class MemberNotNullAttribute : Attribute
  1152. {
  1153. public MemberNotNullAttribute(params string[] members)
  1154. {
  1155. Members = members;
  1156. }
  1157. public MemberNotNullAttribute(string member)
  1158. {
  1159. Members = new[] { member };
  1160. }
  1161. public string[] Members { get; }
  1162. }
  1163. }
  1164. #endif