ReadStaticWebAssetsManifestFileTest.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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.Text.Json;
  4. using Microsoft.AspNetCore.StaticWebAssets.Tasks;
  5. using Microsoft.Build.Framework;
  6. using Microsoft.NET.Sdk.StaticWebAssets.Tasks;
  7. using Moq;
  8. namespace Microsoft.NET.Sdk.Razor.Tests
  9. {
  10. public class ReadStaticWebAssetsManifestFileTest
  11. {
  12. public ReadStaticWebAssetsManifestFileTest()
  13. {
  14. Directory.CreateDirectory(Path.Combine(TestContext.Current.TestExecutionDirectory, nameof(ReadStaticWebAssetsManifestFileTest)));
  15. TempFilePath = Path.Combine(TestContext.Current.TestExecutionDirectory, nameof(ReadStaticWebAssetsManifestFileTest), Guid.NewGuid().ToString("N") + ".json");
  16. }
  17. public string TempFilePath { get; }
  18. [Fact]
  19. public void CanReadManifestWithoutProperties()
  20. {
  21. var errorMessages = new List<string>();
  22. var buildEngine = new Mock<IBuildEngine>();
  23. buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
  24. .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
  25. var emptyManifest = "{}";
  26. File.WriteAllText(TempFilePath, emptyManifest);
  27. var task = new ReadStaticWebAssetsManifestFile
  28. {
  29. BuildEngine = buildEngine.Object,
  30. ManifestPath = TempFilePath
  31. };
  32. // Act
  33. var result = task.Execute();
  34. // Assert
  35. result.Should().Be(true);
  36. task.Assets.Should().BeEmpty();
  37. task.Endpoints.Should().BeEmpty();
  38. task.DiscoveryPatterns.Should().BeEmpty();
  39. task.ReferencedProjectsConfiguration.Should().BeEmpty();
  40. }
  41. [Fact]
  42. public void CanReadEmptyManifest()
  43. {
  44. var errorMessages = new List<string>();
  45. var buildEngine = new Mock<IBuildEngine>();
  46. buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
  47. .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
  48. var emptyManifest = @"{
  49. ""Version"": 1,
  50. ""Hash"": ""__hash__"",
  51. ""Source"": ""ComponentApp"",
  52. ""BasePath"": ""_content/ComponentApp"",
  53. ""Mode"": ""Default"",
  54. ""ManifestType"": ""Build"",
  55. ""ReferencedProjectsConfiguration"": [],
  56. ""DiscoveryPatterns"": [],
  57. ""Assets"": [],
  58. ""Endpoints"": []
  59. }";
  60. File.WriteAllText(TempFilePath, emptyManifest);
  61. var task = new ReadStaticWebAssetsManifestFile
  62. {
  63. BuildEngine = buildEngine.Object,
  64. ManifestPath = TempFilePath
  65. };
  66. // Act
  67. var result = task.Execute();
  68. // Assert
  69. result.Should().Be(true);
  70. task.Assets.Should().BeEmpty();
  71. task.Endpoints.Should().BeEmpty();
  72. task.DiscoveryPatterns.Should().BeEmpty();
  73. task.ReferencedProjectsConfiguration.Should().BeEmpty();
  74. }
  75. [Fact]
  76. public void ConvertsAssetsToTaskItems()
  77. {
  78. var errorMessages = new List<string>();
  79. var buildEngine = new Mock<IBuildEngine>();
  80. buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
  81. .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
  82. var contentRoot = Path.GetFullPath(".");
  83. var encodedContentRoot = JsonEncodedText.Encode(contentRoot);
  84. var identity = Path.Combine(contentRoot, "ComponentApp.styles.css");
  85. var encodedIdentity = JsonEncodedText.Encode(identity);
  86. var manifest = $@"{{
  87. ""Version"": 1,
  88. ""Hash"": ""__hash__"",
  89. ""Source"": ""ComponentApp"",
  90. ""BasePath"": ""_content/ComponentApp"",
  91. ""Mode"": ""Default"",
  92. ""ManifestType"": ""Build"",
  93. ""ReferencedProjectsConfiguration"": [],
  94. ""DiscoveryPatterns"": [],
  95. ""Assets"": [
  96. {{
  97. ""Identity"": ""{encodedIdentity}"",
  98. ""SourceId"": ""ComponentApp"",
  99. ""SourceType"": ""Computed"",
  100. ""ContentRoot"": ""{encodedContentRoot}"",
  101. ""BasePath"": ""_content/ComponentApp"",
  102. ""RelativePath"": ""ComponentApp.styles.css"",
  103. ""AssetKind"": ""All"",
  104. ""AssetMode"": ""CurrentProject"",
  105. ""AssetRole"": ""Primary"",
  106. ""RelatedAsset"": """",
  107. ""AssetTraitName"": ""ScopedCss"",
  108. ""AssetTraitValue"": ""ApplicationBundle"",
  109. ""CopyToOutputDirectory"": ""Never"",
  110. ""CopyToPublishDirectory"": ""PreserveNewest"",
  111. ""OriginalItemSpec"": ""{encodedIdentity}""
  112. }}
  113. ],
  114. ""Endpoints"": [
  115. {{
  116. ""AssetFile"": ""{encodedIdentity}"",
  117. ""Route"": ""_content/ComponentApp/ComponentApp.styles.css"",
  118. ""Selectors"": [
  119. {{
  120. ""Name"": ""Content-Encoding"",
  121. ""Value"": ""gzip"",
  122. ""Quality"": ""0.9""
  123. }}
  124. ],
  125. ""ResponseHeaders"": [
  126. {{
  127. ""Name"": ""Accept-Ranges"",
  128. ""Value"": ""bytes""
  129. }},
  130. {{
  131. ""Name"": ""Content-Length"",
  132. ""Value"": ""__content-length__""
  133. }},
  134. {{
  135. ""Name"": ""Content-Type"",
  136. ""Value"": ""text/css""
  137. }},
  138. {{
  139. ""Name"": ""ETag"",
  140. ""Value"": ""__etag__""
  141. }},
  142. {{
  143. ""Name"": ""Last-Modified"",
  144. ""Value"": ""__last-modified__""
  145. }}
  146. ]
  147. }}
  148. ]
  149. }}";
  150. File.WriteAllText(TempFilePath, manifest);
  151. var task = new ReadStaticWebAssetsManifestFile
  152. {
  153. BuildEngine = buildEngine.Object,
  154. ManifestPath = TempFilePath
  155. };
  156. // Act
  157. var result = task.Execute();
  158. // Assert
  159. result.Should().Be(true);
  160. task.ReferencedProjectsConfiguration.Should().BeEmpty();
  161. task.DiscoveryPatterns.Should().BeEmpty();
  162. task.Assets.Length.Should().Be(1);
  163. var asset = task.Assets[0];
  164. asset.GetMetadata(nameof(StaticWebAsset.Identity)).Should().BeEquivalentTo($"{identity}");
  165. asset.GetMetadata(nameof(StaticWebAsset.SourceId)).Should().BeEquivalentTo("ComponentApp");
  166. asset.GetMetadata(nameof(StaticWebAsset.SourceType)).Should().BeEquivalentTo("Computed");
  167. asset.GetMetadata(nameof(StaticWebAsset.ContentRoot)).Should().BeEquivalentTo($"{contentRoot}");
  168. asset.GetMetadata(nameof(StaticWebAsset.BasePath)).Should().BeEquivalentTo("_content/ComponentApp");
  169. asset.GetMetadata(nameof(StaticWebAsset.RelativePath)).Should().BeEquivalentTo("ComponentApp.styles.css");
  170. asset.GetMetadata(nameof(StaticWebAsset.AssetKind)).Should().BeEquivalentTo("All");
  171. asset.GetMetadata(nameof(StaticWebAsset.AssetMode)).Should().BeEquivalentTo("CurrentProject");
  172. asset.GetMetadata(nameof(StaticWebAsset.AssetRole)).Should().BeEquivalentTo("Primary");
  173. asset.GetMetadata(nameof(StaticWebAsset.RelatedAsset)).Should().BeEquivalentTo("");
  174. asset.GetMetadata(nameof(StaticWebAsset.AssetTraitName)).Should().BeEquivalentTo("ScopedCss");
  175. asset.GetMetadata(nameof(StaticWebAsset.AssetTraitValue)).Should().BeEquivalentTo("ApplicationBundle");
  176. asset.GetMetadata(nameof(StaticWebAsset.CopyToOutputDirectory)).Should().BeEquivalentTo("Never");
  177. asset.GetMetadata(nameof(StaticWebAsset.CopyToPublishDirectory)).Should().BeEquivalentTo("PreserveNewest");
  178. asset.GetMetadata(nameof(StaticWebAsset.OriginalItemSpec)).Should().BeEquivalentTo($"{identity}");
  179. task.Endpoints.Length.Should().Be(1);
  180. var endpoint = task.Endpoints[0];
  181. endpoint.ItemSpec.Should().BeEquivalentTo("_content/ComponentApp/ComponentApp.styles.css");
  182. endpoint.GetMetadata(nameof(StaticWebAssetEndpoint.AssetFile)).Should().BeEquivalentTo($"{identity}");
  183. endpoint.GetMetadata(nameof(StaticWebAssetEndpoint.Selectors)).Should().BeEquivalentTo("""[{"Name":"Content-Encoding","Value":"gzip","Quality":"0.9"}]""");
  184. endpoint.GetMetadata(nameof(StaticWebAssetEndpoint.ResponseHeaders))
  185. .Should()
  186. .BeEquivalentTo("""[{"Name":"Accept-Ranges","Value":"bytes"},{"Name":"Content-Length","Value":"__content-length__"},{"Name":"Content-Type","Value":"text/css"},{"Name":"ETag","Value":"__etag__"},{"Name":"Last-Modified","Value":"__last-modified__"}]""");
  187. }
  188. [Fact]
  189. public void ConvertsReferencedProjectsConfigurationsToTaskItems()
  190. {
  191. var errorMessages = new List<string>();
  192. var buildEngine = new Mock<IBuildEngine>();
  193. buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
  194. .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
  195. var contentRoot = Path.GetFullPath(".");
  196. var identity = Path.Combine(contentRoot, "AnotherClassLib", "AnotherClassLib.csproj");
  197. var encodedIdentity = JsonEncodedText.Encode(identity);
  198. var manifest = $@"{{
  199. ""Version"": 1,
  200. ""Hash"": ""__hash__"",
  201. ""Source"": ""ComponentApp"",
  202. ""BasePath"": ""_content/ComponentApp"",
  203. ""Mode"": ""Default"",
  204. ""ManifestType"": ""Build"",
  205. ""ReferencedProjectsConfiguration"": [
  206. {{
  207. ""Identity"": ""{encodedIdentity}"",
  208. ""Version"": 2,
  209. ""Source"": ""AnotherClassLib"",
  210. ""GetPublishAssetsTargets"": ""ComputeReferencedStaticWebAssetsPublishManifest;GetCurrentProjectPublishStaticWebAssetItems"",
  211. ""AdditionalPublishProperties"": "";"",
  212. ""AdditionalPublishPropertiesToRemove"": "";WebPublishProfileFile"",
  213. ""GetBuildAssetsTargets"": ""GetCurrentProjectBuildStaticWebAssetItems"",
  214. ""AdditionalBuildProperties"": "";"",
  215. ""AdditionalBuildPropertiesToRemove"": "";WebPublishProfileFile""
  216. }}
  217. ],
  218. ""DiscoveryPatterns"": [],
  219. ""Assets"": [],
  220. ""Endpoints"": []
  221. }}";
  222. File.WriteAllText(TempFilePath, manifest);
  223. var task = new ReadStaticWebAssetsManifestFile
  224. {
  225. BuildEngine = buildEngine.Object,
  226. ManifestPath = TempFilePath
  227. };
  228. // Act
  229. var result = task.Execute();
  230. // Assert
  231. result.Should().Be(true);
  232. task.ReferencedProjectsConfiguration.Length.Should().Be(1);
  233. task.Assets.Should().BeEmpty();
  234. task.Endpoints.Should().BeEmpty();
  235. task.DiscoveryPatterns.Should().BeEmpty();
  236. var projectConfiguration = task.ReferencedProjectsConfiguration[0];
  237. projectConfiguration.ItemSpec.Should().BeEquivalentTo(identity);
  238. projectConfiguration.GetMetadata(nameof(StaticWebAssetsManifest.ReferencedProjectConfiguration.Version)).Should().BeEquivalentTo("2");
  239. projectConfiguration.GetMetadata(nameof(StaticWebAssetsManifest.ReferencedProjectConfiguration.Source)).Should().BeEquivalentTo("AnotherClassLib");
  240. projectConfiguration.GetMetadata(nameof(StaticWebAssetsManifest.ReferencedProjectConfiguration.GetPublishAssetsTargets)).Should().BeEquivalentTo("ComputeReferencedStaticWebAssetsPublishManifest;GetCurrentProjectPublishStaticWebAssetItems");
  241. projectConfiguration.GetMetadata(nameof(StaticWebAssetsManifest.ReferencedProjectConfiguration.AdditionalPublishProperties)).Should().BeEquivalentTo(";");
  242. projectConfiguration.GetMetadata(nameof(StaticWebAssetsManifest.ReferencedProjectConfiguration.AdditionalPublishPropertiesToRemove)).Should().BeEquivalentTo(";WebPublishProfileFile");
  243. projectConfiguration.GetMetadata(nameof(StaticWebAssetsManifest.ReferencedProjectConfiguration.GetBuildAssetsTargets)).Should().BeEquivalentTo("GetCurrentProjectBuildStaticWebAssetItems");
  244. projectConfiguration.GetMetadata(nameof(StaticWebAssetsManifest.ReferencedProjectConfiguration.AdditionalBuildProperties)).Should().BeEquivalentTo(";");
  245. projectConfiguration.GetMetadata(nameof(StaticWebAssetsManifest.ReferencedProjectConfiguration.AdditionalBuildPropertiesToRemove)).Should().BeEquivalentTo(";WebPublishProfileFile");
  246. }
  247. [Fact]
  248. public void ConvertsDiscoveryPatternsToTaskItems()
  249. {
  250. var errorMessages = new List<string>();
  251. var buildEngine = new Mock<IBuildEngine>();
  252. buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
  253. .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
  254. var contentRoot = Path.Combine(Path.GetFullPath("."), "AnotherClassLib", "wwwroot");
  255. var encodedContentRoot = JsonEncodedText.Encode(contentRoot);
  256. var manifest = $@"{{
  257. ""Version"": 1,
  258. ""Hash"": ""__hash__"",
  259. ""Source"": ""ComponentApp"",
  260. ""BasePath"": ""_content/ComponentApp"",
  261. ""Mode"": ""Default"",
  262. ""ManifestType"": ""Build"",
  263. ""ReferencedProjectsConfiguration"": [ ],
  264. ""DiscoveryPatterns"": [
  265. {{
  266. ""Name"": ""AnotherClassLib\\wwwroot"",
  267. ""Source"": ""AnotherClassLib"",
  268. ""ContentRoot"": ""{encodedContentRoot}"",
  269. ""BasePath"": ""_content/AnotherClassLib"",
  270. ""Pattern"": ""**""
  271. }}
  272. ],
  273. ""Assets"": [],
  274. ""Endpoints"": []
  275. }}";
  276. File.WriteAllText(TempFilePath, manifest);
  277. var task = new ReadStaticWebAssetsManifestFile
  278. {
  279. BuildEngine = buildEngine.Object,
  280. ManifestPath = TempFilePath
  281. };
  282. // Act
  283. var result = task.Execute();
  284. // Assert
  285. result.Should().Be(true);
  286. task.DiscoveryPatterns.Length.Should().Be(1);
  287. task.ReferencedProjectsConfiguration.Should().BeEmpty();
  288. task.Assets.Should().BeEmpty();
  289. task.Endpoints.Should().BeEmpty();
  290. var discoveryPattern = task.DiscoveryPatterns[0];
  291. discoveryPattern.ItemSpec.Should().BeEquivalentTo(Path.Combine("AnotherClassLib", "wwwroot"));
  292. discoveryPattern.GetMetadata(nameof(StaticWebAssetsDiscoveryPattern.Source)).Should().BeEquivalentTo("AnotherClassLib");
  293. discoveryPattern.GetMetadata(nameof(StaticWebAssetsDiscoveryPattern.ContentRoot)).Should().BeEquivalentTo($"{contentRoot}");
  294. discoveryPattern.GetMetadata(nameof(StaticWebAssetsDiscoveryPattern.BasePath)).Should().BeEquivalentTo("_content/AnotherClassLib");
  295. discoveryPattern.GetMetadata(nameof(StaticWebAssetsDiscoveryPattern.Pattern)).Should().BeEquivalentTo("**");
  296. }
  297. [Fact]
  298. public void ReturnsErrorwhenManifestDoesNotExist()
  299. {
  300. var errorMessages = new List<string>();
  301. var buildEngine = new Mock<IBuildEngine>();
  302. buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
  303. .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
  304. var task = new ReadStaticWebAssetsManifestFile
  305. {
  306. BuildEngine = buildEngine.Object,
  307. ManifestPath = "nonexisting.staticwebassets.json"
  308. };
  309. // Act
  310. var result = task.Execute();
  311. // Assert
  312. result.Should().Be(false);
  313. errorMessages.Count.Should().Be(1);
  314. errorMessages[0].Should().Be("Manifest file at 'nonexisting.staticwebassets.json' not found.");
  315. task.Assets.Should().BeNull();
  316. task.DiscoveryPatterns.Should().BeNull();
  317. task.ReferencedProjectsConfiguration.Should().BeNull();
  318. }
  319. [Fact]
  320. public void ReturnsErrorwhenManifestIsMalformed()
  321. {
  322. var errorMessages = new List<string>();
  323. var buildEngine = new Mock<IBuildEngine>();
  324. buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
  325. .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
  326. var manifest = "{";
  327. File.WriteAllText(TempFilePath, manifest);
  328. var task = new ReadStaticWebAssetsManifestFile
  329. {
  330. BuildEngine = buildEngine.Object,
  331. ManifestPath = TempFilePath
  332. };
  333. // Act
  334. var result = task.Execute();
  335. // Assert
  336. result.Should().Be(false);
  337. errorMessages.Count.Should().Be(1);
  338. task.Assets.Should().BeNull();
  339. task.Endpoints.Should().BeNull();
  340. task.DiscoveryPatterns.Should().BeNull();
  341. task.ReferencedProjectsConfiguration.Should().BeNull();
  342. }
  343. }
  344. }