Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'tests/CoreFX/runtest/src/TestUtils/TestFileSetup/TestFileSetup.cs')
-rw-r--r--tests/CoreFX/runtest/src/TestUtils/TestFileSetup/TestFileSetup.cs329
1 files changed, 329 insertions, 0 deletions
diff --git a/tests/CoreFX/runtest/src/TestUtils/TestFileSetup/TestFileSetup.cs b/tests/CoreFX/runtest/src/TestUtils/TestFileSetup/TestFileSetup.cs
new file mode 100644
index 000000000..50e89c5ad
--- /dev/null
+++ b/tests/CoreFX/runtest/src/TestUtils/TestFileSetup/TestFileSetup.cs
@@ -0,0 +1,329 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.CommandLine;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Schema;
+using Newtonsoft.Json.Schema.Generation;
+
+namespace CoreFX.TestUtils.TestFileSetup
+{
+ /// <summary>
+ /// Defines the set of flags that represent exit codes
+ /// </summary>
+ [Flags]
+ public enum ExitCode : int
+ {
+ Success = 0,
+ HttpError = 1,
+ IOError = 2,
+ JsonSchemaValidationError = 3,
+ UnknownError = 10
+
+ }
+
+ /// <summary>
+ /// This helper class is used to fetch CoreFX tests from a specified URL, unarchive them and create a flat directory structure
+ /// through which to iterate.
+ /// </summary>
+ public static class TestFileSetup
+ {
+ private static HttpClient httpClient;
+ private static bool cleanTestBuild = false;
+
+ private static string outputDir;
+ private static string testUrl;
+ private static string testListPath;
+
+ public static void Main(string[] args)
+ {
+ ExitCode exitCode = ExitCode.UnknownError;
+ ArgumentSyntax argSyntax = ParseCommandLine(args);
+
+ try
+ {
+ if (!Directory.Exists(outputDir))
+ Directory.CreateDirectory(outputDir);
+
+ if (cleanTestBuild)
+ {
+ CleanBuild(outputDir);
+ }
+
+ // Map test names to their definitions
+ Dictionary<string, XUnitTestAssembly> testAssemblyDefinitions = DeserializeTestJson(testListPath);
+
+ SetupTests(testUrl, outputDir, testAssemblyDefinitions).Wait();
+ exitCode = ExitCode.Success;
+ }
+
+ catch (AggregateException e)
+ {
+ e.Handle(innerExc =>
+ {
+
+ if (innerExc is HttpRequestException)
+ {
+ exitCode = ExitCode.HttpError;
+ Console.WriteLine("Error downloading tests from: " + testUrl);
+ Console.WriteLine(innerExc.Message);
+ return true;
+ }
+ else if (innerExc is IOException)
+ {
+ exitCode = ExitCode.IOError;
+ Console.WriteLine(innerExc.Message);
+ return true;
+ }
+ else if (innerExc is JSchemaValidationException || innerExc is JsonSerializationException)
+ {
+ exitCode = ExitCode.JsonSchemaValidationError;
+ Console.WriteLine("Error validating test list: ");
+ Console.WriteLine(innerExc.Message);
+ return true;
+ }
+ return false;
+ });
+ }
+
+ Environment.Exit((int)exitCode);
+ }
+
+ private static ArgumentSyntax ParseCommandLine(string[] args)
+ {
+ ArgumentSyntax argSyntax = ArgumentSyntax.Parse(args, syntax =>
+ {
+ syntax.DefineOption("out|outDir|outputDirectory", ref outputDir, "Directory where tests are downloaded");
+ syntax.DefineOption("testUrl", ref testUrl, "URL, pointing to the list of tests");
+ syntax.DefineOption("testListJsonPath", ref testListPath, "JSON-formatted list of test assembly names to download");
+ syntax.DefineOption("clean|cleanOutputDir", ref cleanTestBuild, "Clean test assembly output directory");
+ });
+
+ return argSyntax;
+ }
+
+ private static Dictionary<string, XUnitTestAssembly> DeserializeTestJson(string testDefinitionFilePath)
+ {
+ JSchemaGenerator jsonGenerator = new JSchemaGenerator();
+
+ JSchema testDefinitionSchema = jsonGenerator.Generate(typeof(IList<XUnitTestAssembly>));
+ IList<XUnitTestAssembly> testAssemblies = new List<XUnitTestAssembly>();
+
+ IList<string> validationMessages = new List<string>();
+
+ using (var sr = new StreamReader(testDefinitionFilePath))
+ using (var jsonReader = new JsonTextReader(sr))
+ using (var jsonValidationReader = new JSchemaValidatingReader(jsonReader))
+ {
+ // Create schema validator
+ jsonValidationReader.Schema = testDefinitionSchema;
+ jsonValidationReader.ValidationEventHandler += (o, a) => validationMessages.Add(a.Message);
+
+ // Deserialize json test assembly definitions
+ JsonSerializer serializer = new JsonSerializer();
+ try
+ {
+ testAssemblies = serializer.Deserialize<List<XUnitTestAssembly>>(jsonValidationReader);
+ }
+ catch (JsonSerializationException ex)
+ {
+ throw new AggregateException(ex);
+ }
+ }
+
+ // TODO - ABORT AND WARN
+ if (validationMessages.Count != 0)
+ {
+ StringBuilder aggregateExceptionMessage = new StringBuilder();
+ foreach (string validationMessage in validationMessages)
+ {
+ aggregateExceptionMessage.Append("JSON Validation Error: ");
+ aggregateExceptionMessage.Append(validationMessage);
+ aggregateExceptionMessage.AppendLine();
+ }
+
+ throw new AggregateException(new JSchemaValidationException(aggregateExceptionMessage.ToString()));
+
+ }
+
+ var nameToTestAssemblyDef = new Dictionary<string, XUnitTestAssembly>();
+
+ // Map test names to their definitions
+ foreach (XUnitTestAssembly assembly in testAssemblies)
+ {
+ nameToTestAssemblyDef.Add(assembly.Name, assembly);
+ }
+
+ return nameToTestAssemblyDef;
+ }
+
+ private static async Task SetupTests(string jsonUrl, string destinationDirectory, Dictionary<string, XUnitTestAssembly> testDefinitions = null, bool runAllTests = false)
+ {
+ Debug.Assert(Directory.Exists(destinationDirectory));
+ Debug.Assert(runAllTests || testDefinitions != null);
+
+ string tempDirPath = Path.Combine(destinationDirectory, "temp");
+ if (!Directory.Exists(tempDirPath))
+ {
+ Directory.CreateDirectory(tempDirPath);
+ }
+ Dictionary<string, XUnitTestAssembly> testPayloads = await GetTestUrls(jsonUrl, testDefinitions, runAllTests);
+
+ if (testPayloads == null)
+ {
+ return;
+ }
+
+ await GetTestArchives(testPayloads, tempDirPath);
+ ExpandArchivesInDirectory(tempDirPath, destinationDirectory);
+
+ RSPGenerator rspGenerator = new RSPGenerator();
+ foreach (XUnitTestAssembly assembly in testDefinitions.Values)
+ {
+ rspGenerator.GenerateRSPFile(assembly, Path.Combine(destinationDirectory, assembly.Name));
+ }
+
+ Directory.Delete(tempDirPath);
+ }
+
+ private static async Task<Dictionary<string, XUnitTestAssembly>> GetTestUrls(string jsonUrl, Dictionary<string, XUnitTestAssembly> testDefinitions = null, bool runAllTests = false)
+ {
+ if (httpClient is null)
+ {
+ httpClient = new HttpClient();
+ }
+
+ Debug.Assert(runAllTests || testDefinitions != null);
+ // Set up the json stream reader
+ using (var responseStream = await httpClient.GetStreamAsync(jsonUrl))
+ using (var streamReader = new StreamReader(responseStream))
+ using (var jsonReader = new JsonTextReader(streamReader))
+ {
+ // Manual parsing - we only need to key-value pairs from each object and this avoids deserializing all of the work items into objects
+ string markedTestName = string.Empty;
+ string currentPropertyName = string.Empty;
+
+ while (jsonReader.Read())
+ {
+ if (jsonReader.Value != null)
+ {
+ switch (jsonReader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ currentPropertyName = jsonReader.Value.ToString();
+ break;
+ case JsonToken.String:
+ if (currentPropertyName.Equals("WorkItemId"))
+ {
+ string currentTestName = jsonReader.Value.ToString();
+
+ if (runAllTests || testDefinitions.ContainsKey(currentTestName))
+ {
+ markedTestName = currentTestName;
+ }
+ }
+ else if (currentPropertyName.Equals("PayloadUri") && markedTestName != string.Empty)
+ {
+ if (!testDefinitions.ContainsKey(markedTestName))
+ {
+ testDefinitions[markedTestName] = new XUnitTestAssembly() { Name = markedTestName };
+ }
+ testDefinitions[markedTestName].Url = jsonReader.Value.ToString();
+ markedTestName = string.Empty;
+ }
+ break;
+ }
+ }
+ }
+
+ }
+ return testDefinitions;
+ }
+
+ private static async Task GetTestArchives(Dictionary<string, XUnitTestAssembly> testPayloads, string downloadDir)
+ {
+ if (httpClient is null)
+ {
+ httpClient = new HttpClient();
+ }
+
+ foreach (string testName in testPayloads.Keys)
+ {
+ string payloadUri = testPayloads[testName].Url;
+
+ if (!Uri.IsWellFormedUriString(payloadUri, UriKind.Absolute))
+ continue;
+
+ using (var response = await httpClient.GetStreamAsync(payloadUri))
+ {
+ if (response.CanRead)
+ {
+ // Create the test setup directory if it doesn't exist
+ if (!Directory.Exists(downloadDir))
+ {
+ Directory.CreateDirectory(downloadDir);
+ }
+
+ // CoreFX test archives are output as .zip regardless of platform
+ string archivePath = Path.Combine(downloadDir, testName + ".zip");
+
+ // Copy to a temp folder
+ using (FileStream file = new FileStream(archivePath, FileMode.Create))
+ {
+ await response.CopyToAsync(file);
+ }
+
+ }
+ }
+ }
+ }
+
+ private static void ExpandArchivesInDirectory(string archiveDirectory, string destinationDirectory, bool cleanup = true)
+ {
+ Debug.Assert(Directory.Exists(archiveDirectory));
+ Debug.Assert(Directory.Exists(destinationDirectory));
+
+ string[] archives = Directory.GetFiles(archiveDirectory, "*.zip", SearchOption.TopDirectoryOnly);
+
+ foreach (string archivePath in archives)
+ {
+ string destinationDirName = Path.Combine(destinationDirectory, Path.GetFileNameWithoutExtension(archivePath));
+
+ ZipFile.ExtractToDirectory(archivePath, destinationDirName);
+
+
+ // Delete archives
+ if (cleanup)
+ {
+ File.Delete(archivePath);
+ }
+ }
+ }
+
+ private static void CleanBuild(string directoryToClean)
+ {
+ Debug.Assert(Directory.Exists(directoryToClean));
+ DirectoryInfo dirInfo = new DirectoryInfo(directoryToClean);
+
+ foreach (FileInfo file in dirInfo.EnumerateFiles())
+ {
+ file.Delete();
+ }
+
+ foreach (DirectoryInfo dir in dirInfo.EnumerateDirectories())
+ {
+ dir.Delete(true);
+ }
+ }
+
+ }
+}