remove cdn tests
This commit is contained in:
parent
13ebb41fa9
commit
d1b9d14eef
|
|
@ -1,293 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using AngleSharp;
|
|
||||||
using AngleSharp.Dom;
|
|
||||||
using AngleSharp.Dom.Html;
|
|
||||||
using AngleSharp.Parser.Html;
|
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Templates.Test.Helpers;
|
|
||||||
using Xunit;
|
|
||||||
using Xunit.Abstractions;
|
|
||||||
|
|
||||||
namespace Templates.Test
|
|
||||||
{
|
|
||||||
public class CdnScriptTagTests : IDisposable
|
|
||||||
{
|
|
||||||
private readonly ITestOutputHelper _output;
|
|
||||||
private readonly HttpClient _httpClient;
|
|
||||||
private static List<ScriptTag> _scriptTags;
|
|
||||||
private static List<LinkTag> _linkTags;
|
|
||||||
private static readonly string[] _packages;
|
|
||||||
|
|
||||||
static CdnScriptTagTests()
|
|
||||||
{
|
|
||||||
var searchPattern = "*.nupkg";
|
|
||||||
_packages = Directory.EnumerateFiles(
|
|
||||||
ResolveFolder("ArtifactsShippingPackagesDir"),
|
|
||||||
searchPattern)
|
|
||||||
.Concat(Directory.EnumerateFiles(
|
|
||||||
ResolveFolder("ArtifactsNonShippingPackagesDir"),
|
|
||||||
searchPattern))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
_scriptTags = new List<ScriptTag>();
|
|
||||||
_linkTags = new List<LinkTag>();
|
|
||||||
foreach (var packagePath in _packages)
|
|
||||||
{
|
|
||||||
var tags = GetTags(packagePath);
|
|
||||||
_scriptTags.AddRange(tags.scripts);
|
|
||||||
_linkTags.AddRange(tags.links);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ResolveFolder(string folder) =>
|
|
||||||
typeof(CdnScriptTagTests).Assembly
|
|
||||||
.GetCustomAttributes<AssemblyMetadataAttribute>()
|
|
||||||
.Single(a => a.Key == folder).Value;
|
|
||||||
|
|
||||||
public CdnScriptTagTests(ITestOutputHelper output)
|
|
||||||
{
|
|
||||||
_output = output;
|
|
||||||
_httpClient = new HttpClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<object[]> SubresourceIntegrityCheckScriptData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var scriptTags = _scriptTags
|
|
||||||
.Where(st => st.FallbackSrc != null)
|
|
||||||
.Select(st => new object[] { st });
|
|
||||||
Assert.NotEmpty(scriptTags);
|
|
||||||
return scriptTags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<object[]> SubresourceIntegrityCheckLinkData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var linkTags = _linkTags
|
|
||||||
.Where(st => st.FallbackHRef != null)
|
|
||||||
.Select(st => new object[] { st });
|
|
||||||
Assert.NotEmpty(linkTags);
|
|
||||||
return linkTags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(SubresourceIntegrityCheckScriptData))]
|
|
||||||
public async Task CheckScriptSubresourceIntegrity(ScriptTag scriptTag)
|
|
||||||
{
|
|
||||||
var expectedIntegrity = await GetShaIntegrity(scriptTag);
|
|
||||||
if (!string.Equals(expectedIntegrity, scriptTag.Integrity, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
Assert.False(true, $"Expected {scriptTag.Src} to have Integrity '{expectedIntegrity}' but it had '{scriptTag.Integrity}'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(SubresourceIntegrityCheckLinkData))]
|
|
||||||
public async Task CheckLinkSubresourceIntegrity(LinkTag linkTag)
|
|
||||||
{
|
|
||||||
string expectedIntegrity = await GetShaIntegrity(linkTag);
|
|
||||||
if (!expectedIntegrity.Equals(linkTag.Integrity, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
Assert.False(true, $"Expected {linkTag.HRef} to have Integrity '{expectedIntegrity}' but it had '{linkTag.Integrity}'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<object[]> FallbackSrcCheckData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var scriptTags = _scriptTags
|
|
||||||
.Where(st => st.FallbackSrc != null)
|
|
||||||
.Select(st => new object[] { st });
|
|
||||||
Assert.NotEmpty(scriptTags);
|
|
||||||
return scriptTags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(FallbackSrcCheckData))]
|
|
||||||
public async Task FallbackSrcContent_Matches_CDNContent(ScriptTag scriptTag)
|
|
||||||
{
|
|
||||||
var fallbackSrc = scriptTag.FallbackSrc
|
|
||||||
.TrimStart('~')
|
|
||||||
.TrimStart('/');
|
|
||||||
|
|
||||||
var cdnContent = await GetStringFromCDN(scriptTag.Src);
|
|
||||||
var fallbackSrcContent = GetFileContentFromArchive(scriptTag, fallbackSrc);
|
|
||||||
|
|
||||||
Assert.Equal(RemoveLineEndings(cdnContent), RemoveLineEndings(fallbackSrcContent));
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct LinkTag
|
|
||||||
{
|
|
||||||
public string Rel;
|
|
||||||
public string HRef;
|
|
||||||
public string FallbackHRef;
|
|
||||||
public string Integrity;
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{HRef}, {Integrity}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct ScriptTag
|
|
||||||
{
|
|
||||||
public string Src;
|
|
||||||
public string Integrity;
|
|
||||||
public string FallbackSrc;
|
|
||||||
public string FileName;
|
|
||||||
public string Entry;
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{Src}, {Entry}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetStringFromCDN(string src)
|
|
||||||
{
|
|
||||||
var response = await GetFromCDN(src);
|
|
||||||
return await response.Content.ReadAsStringAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<byte[]> GetByteArrayFromCDN(string src)
|
|
||||||
{
|
|
||||||
var response = await GetFromCDN(src);
|
|
||||||
return await response.Content.ReadAsByteArrayAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<HttpResponseMessage> GetFromCDN(string src)
|
|
||||||
{
|
|
||||||
var logger = NullLogger.Instance;
|
|
||||||
return await RetryHelper.RetryRequest(async () =>
|
|
||||||
{
|
|
||||||
var request = new HttpRequestMessage(HttpMethod.Get, new Uri(src));
|
|
||||||
return await _httpClient.SendAsync(request);
|
|
||||||
}, logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<string> GetShaIntegrity(ScriptTag scriptTag)
|
|
||||||
{
|
|
||||||
return GetShaIntegrity(scriptTag.Integrity, scriptTag.Src);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<string> GetShaIntegrity(LinkTag linkTag)
|
|
||||||
{
|
|
||||||
return GetShaIntegrity(linkTag.Integrity, linkTag.HRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetShaIntegrity(string integrity, string src)
|
|
||||||
{
|
|
||||||
var prefix = integrity.Substring(0, 6);
|
|
||||||
var respStream = await GetByteArrayFromCDN(src);
|
|
||||||
using (HashAlgorithm alg = string.Equals(prefix, "sha256") ? (HashAlgorithm)SHA256.Create() : (HashAlgorithm)SHA384.Create())
|
|
||||||
{
|
|
||||||
var hash = alg.ComputeHash(respStream);
|
|
||||||
return $"{prefix}-" + Convert.ToBase64String(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetFileContentFromArchive(ScriptTag scriptTag, string relativeFilePath)
|
|
||||||
{
|
|
||||||
var file = _packages.Single(f => f.EndsWith(scriptTag.FileName));
|
|
||||||
using (var zip = new ZipArchive(File.OpenRead(file), ZipArchiveMode.Read, leaveOpen: false))
|
|
||||||
{
|
|
||||||
var entry = zip.Entries
|
|
||||||
.Where(e => e.FullName.EndsWith(relativeFilePath, StringComparison.OrdinalIgnoreCase))
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
if (entry != null)
|
|
||||||
{
|
|
||||||
using (var reader = new StreamReader(entry.Open()))
|
|
||||||
{
|
|
||||||
return reader.ReadToEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (List<ScriptTag> scripts, List<LinkTag> links) GetTags(string zipFile)
|
|
||||||
{
|
|
||||||
var scriptTags = new List<ScriptTag>();
|
|
||||||
var linkTags = new List<LinkTag>();
|
|
||||||
using (var zip = new ZipArchive(File.OpenRead(zipFile), ZipArchiveMode.Read, leaveOpen: false))
|
|
||||||
{
|
|
||||||
foreach (var entry in zip.Entries)
|
|
||||||
{
|
|
||||||
if (!string.Equals(".cshtml", Path.GetExtension(entry.Name), StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IHtmlDocument htmlDocument;
|
|
||||||
var options = new HtmlParserOptions
|
|
||||||
{
|
|
||||||
IsStrictMode = false,
|
|
||||||
IsEmbedded = false,
|
|
||||||
};
|
|
||||||
var config = Configuration.Default;
|
|
||||||
var htmlParser = new HtmlParser(options, config);
|
|
||||||
using (var reader = new StreamReader(entry.Open()))
|
|
||||||
{
|
|
||||||
htmlDocument = htmlParser.Parse(entry.Open());
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IElement link in htmlDocument.Body.GetElementsByTagName("link"))
|
|
||||||
{
|
|
||||||
linkTags.Add(new LinkTag
|
|
||||||
{
|
|
||||||
HRef = link.GetAttribute("href"),
|
|
||||||
Integrity = link.GetAttribute("integrity"),
|
|
||||||
FallbackHRef = link.GetAttribute("asp-fallback-href"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var scriptElement in htmlDocument.Scripts)
|
|
||||||
{
|
|
||||||
var fallbackSrcAttribute = scriptElement.Attributes
|
|
||||||
.FirstOrDefault(attr => string.Equals("asp-fallback-src", attr.Name, StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
scriptTags.Add(new ScriptTag
|
|
||||||
{
|
|
||||||
Src = scriptElement.Source,
|
|
||||||
Integrity = scriptElement.Integrity,
|
|
||||||
FallbackSrc = fallbackSrcAttribute?.Value,
|
|
||||||
FileName = Path.GetFileName(zipFile),
|
|
||||||
Entry = entry.FullName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (scriptTags, linkTags);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string RemoveLineEndings(string originalString)
|
|
||||||
{
|
|
||||||
return originalString.Replace("\r\n", "").Replace("\n", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_httpClient.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue