public void GenerateNuSpec() { var pkg = m_packageGenerator.AnalyzePackage( @"<?xml version='1.0' encoding='utf-8'?> <package xmlns='http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd'> <metadata> <id>MyPkg</id> <version>1.999</version> <dependencies> <group targetFramework='.NETFramework4.5'> <dependency id='System.Collections' version='4.0.11' /> <dependency id='System.Collections.Concurrent' version='4.0.12' /> </group> <group targetFramework='.NETFramework4.5.1'> <dependency id='System.Collections' version='4.0.11' /> <dependency id='System.Collections.Concurrent' version='4.0.12' /> </group> <group targetFramework='.NETStandard2.0'> <dependency id='Newtonsoft.Json' version='10.0.0' exclude='Build,Analyzers' /> </group> </dependencies> </metadata> </package>", s_packagesOnConfig, new string[] { "lib/net45/my.dll", "lib/net451/my.dll", "lib/netstandard2.0/my.dll" }); var spec = new NugetSpecGenerator(m_context.PathTable, pkg).CreateScriptSourceFile(pkg); var text = spec.ToDisplayStringV2(); m_output.WriteLine(text); string expectedSpec = $@"import {{Transformer}} from ""Sdk.Transformers""; import * as Managed from ""Sdk.Managed""; export declare const qualifier: {{ targetFramework: ""net45"" | ""net451"" | ""net452"" | ""net46"" | ""net461"" | ""net462"" | ""net472"" | ""netstandard2.0"" | ""netcoreapp2.0"" | ""netcoreapp2.1"" | ""netcoreapp2.2"" | ""netcoreapp3.0"" | ""netcoreapp3.1"" | ""netstandard2.1"", targetRuntime: ""win-x64"" | ""osx-x64"" | ""linux-x64"", }}; const packageRoot = Contents.packageRoot; namespace Contents {{ export declare const qualifier: {{ }}; export const packageRoot = d`../../../pkgs/TestPkg.1.999`; @@public export const all: StaticDirectory = Transformer.sealDirectory( packageRoot, [ f`${{packageRoot}}/lib/net45/my.dll`, f`${{packageRoot}}/lib/net451/my.dll`, f`${{packageRoot}}/lib/netstandard2.0/my.dll`, f`${{packageRoot}}/TestPkg.nuspec`, ] ); }} @@public export const pkg: Managed.ManagedNugetPackage = (() => {{ switch (qualifier.targetFramework) {{ case ""net45"": return Managed.Factory.createNugetPackage( ""TestPkg"", ""1.999"", Contents.all, [Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/net45/my.dll`)], [Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/net45/my.dll`)], [importFrom(""System.Collections"").pkg, importFrom(""System.Collections.Concurrent"").pkg] ); case ""net451"": case ""net452"": case ""net46"": case ""net461"": case ""net462"": case ""net472"": return Managed.Factory.createNugetPackage( ""TestPkg"", ""1.999"", Contents.all, [Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/net451/my.dll`)], [Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/net451/my.dll`)], [importFrom(""System.Collections"").pkg, importFrom(""System.Collections.Concurrent"").pkg] ); case ""netstandard2.0"": case ""netcoreapp2.0"": case ""netcoreapp2.1"": case ""netcoreapp2.2"": case ""netcoreapp3.0"": case ""netcoreapp3.1"": case ""netstandard2.1"": return Managed.Factory.createNugetPackage( ""TestPkg"", ""1.999"", Contents.all, [Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/netstandard2.0/my.dll`)], [ Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/netstandard2.0/my.dll`), ], [...addIfLazy(qualifier.targetFramework === ""netstandard2.0"", () => [importFrom(""Newtonsoft.Json"").pkg])] ); default: Contract.fail(""Unsupported target framework""); }}; }} )();"; XAssert.AreEqual(expectedSpec, text); var hashingHelper = new global::BuildXL.Storage.Fingerprints.HashingHelper(m_context.PathTable, recordFingerprintString: false); hashingHelper.Add(expectedSpec); var hash = BitConverter.ToString(hashingHelper.GenerateHashBytes()).Replace("-", string.Empty); const string CurrentSpecHash = "54628A3B7DB3041473955EE2FC145009CFD298A2"; const int CurrentSpecGenVersion = 6; if (CurrentSpecHash != hash) { var hasFormatVersionIncreased = NugetSpecGenerator.SpecGenerationFormatVersion > CurrentSpecGenVersion; if (!hasFormatVersionIncreased) { XAssert.Fail( $@" ********************************************************************************** ** It looks like NuGet spec generation has changed but the version of ** '{nameof(NugetSpecGenerator.SpecGenerationFormatVersion)}.{nameof(NugetSpecGenerator)}' didn't increase. ** ** Please bump up the spec generation format version from {CurrentSpecGenVersion} to {CurrentSpecGenVersion+1} and then ** update the '{nameof(CurrentSpecHash)}' and '{nameof(CurrentSpecGenVersion)}' values in this ** test to '{hash}' and '{CurrentSpecGenVersion+1}' respectively. **********************************************************************************"); } else { var lines = new[] { $"Congratulations on remembering to increment '{nameof(NugetSpecGenerator.SpecGenerationFormatVersion)}.{nameof(NugetSpecGenerator)}'", $"after updating NuGet spec generator!", $"", $"To keep this reminder working, please update the '{nameof(CurrentSpecHash)}' and '{nameof(CurrentSpecGenVersion)}'", $"values in this unit test to '{hash}' and '{NugetSpecGenerator.SpecGenerationFormatVersion}' respectively.", }; const int width = 94; var fst = " " + String.Concat(Enumerable.Repeat("_", width + 2)) + " "; var snd = $"/ {' ',-width} \\"; var aligned = lines.Select(l => $"| {l,-width} |"); var last = "\\" + String.Concat(Enumerable.Repeat("_", width + 2)) + "/"; XAssert.Fail(string.Join(Environment.NewLine, new[] { fst, snd }.Concat(aligned).Concat(new[] { last }))); } } }
public async Task Stress() { const int N = 5; const int M = N * N; var context = BuildXLContext.CreateInstanceForTesting(); var loggingContext = CreateLoggingContextForTest(); var pathTable = context.PathTable; using (var tempFiles = new TempFileStorage(canGetFileNames: true)) { var config = ConfigHelpers.CreateDefault(pathTable, tempFiles.GetUniqueFileName(), tempFiles); using (var pipTable = new PipTable( context.PathTable, context.SymbolTable, initialBufferSize: 1024, maxDegreeOfParallelism: (Environment.ProcessorCount + 2) / 3, debug: false)) { var executionEnvironment = new PipQueueTestExecutionEnvironment( context, config, pipTable, Path.Combine(TestOutputDirectory, "temp"), TryGetSubstSourceAndTarget(out string substSource, out string substTarget) ? (substSource, substTarget) : default((string, string)?), GetSandboxConnection()); Func <RunnablePip, Task <PipResult> > taskFactory = async(runnablePip) => { PipResult result; var operationTracker = new OperationTracker(runnablePip.LoggingContext); var pip = runnablePip.Pip; using (var operationContext = operationTracker.StartOperation(PipExecutorCounter.PipRunningStateDuration, pip.PipId, pip.PipType, runnablePip.LoggingContext)) { result = await TestPipExecutor.ExecuteAsync(operationContext, executionEnvironment, pip); } executionEnvironment.MarkExecuted(pip); return(result); }; string executable = CmdHelper.OsShellExe; FileArtifact executableArtifact = FileArtifact.CreateSourceFile(AbsolutePath.Create(pathTable, executable)); // This is the only file artifact we reference without a producer. Rather than scheduling a hashing pip, let's just invent one (so fingerprinting can succeed). executionEnvironment.AddWellKnownFile(executableArtifact, WellKnownContentHashes.UntrackedFile); using (var phase1PipQueue = new PipQueue(executionEnvironment.Configuration.Schedule)) { // phase 1: create some files var baseFileArtifacts = new List <FileArtifact>(); for (int i = 0; i < N; i++) { string destination = tempFiles.GetUniqueFileName(); AbsolutePath destinationAbsolutePath = AbsolutePath.Create(pathTable, destination); FileArtifact destinationArtifact = FileArtifact.CreateSourceFile(destinationAbsolutePath).CreateNextWrittenVersion(); baseFileArtifacts.Add(destinationArtifact); PipData contents = PipDataBuilder.CreatePipData( context.StringTable, " ", PipDataFragmentEscaping.CRuntimeArgumentRules, i.ToString(CultureInfo.InvariantCulture)); var writeFile = new WriteFile(destinationArtifact, contents, WriteFileEncoding.Utf8, ReadOnlyArray <StringId> .Empty, PipProvenance.CreateDummy(context)); var pipId = pipTable.Add((uint)(i + 1), writeFile); var contentHash = ContentHashingUtilities.HashString(contents.ToString(pathTable)); executionEnvironment.AddExpectedWrite(writeFile, destinationArtifact, contentHash); var runnable = RunnablePip.Create(loggingContext, executionEnvironment, pipId, pipTable.GetPipType(pipId), 0, taskFactory, 0); runnable.Start(new OperationTracker(loggingContext), loggingContext); runnable.SetDispatcherKind(DispatcherKind.IO); phase1PipQueue.Enqueue(runnable); } phase1PipQueue.SetAsFinalized(); phase1PipQueue.DrainQueues(); await Task.WhenAll( Enumerable.Range(0, 2).Select( async range => { using (var phase2PipQueue = new PipQueue(executionEnvironment.Configuration.Schedule)) { // phase 2: do some more with those files var pips = new ConcurrentDictionary <PipId, Tuple <string, int> >(); var checkerTasks = new ConcurrentQueue <Task>(); Action <PipId, Task <PipResult> > callback = (id, task) => { XAssert.IsTrue(task.Status == TaskStatus.RanToCompletion); XAssert.IsFalse(task.Result.Status.IndicatesFailure()); Tuple <string, int> t; if (!pips.TryRemove(id, out t)) { XAssert.Fail(); } checkerTasks.Enqueue( Task.Run( () => { string actual = File.ReadAllText(t.Item1).Trim(); // TODO: Make this async XAssert.AreEqual(actual, t.Item2.ToString()); })); }; var r = new Random(0); for (int i = 0; i < M; i++) { int sourceIndex = r.Next(baseFileArtifacts.Count); FileArtifact sourceArtifact = baseFileArtifacts[sourceIndex]; string destination = tempFiles.GetUniqueFileName(); AbsolutePath destinationAbsolutePath = AbsolutePath.Create(pathTable, destination); FileArtifact destinationArtifact = FileArtifact.CreateSourceFile(destinationAbsolutePath).CreateNextWrittenVersion(); Pip pip; DispatcherKind queueKind; switch (r.Next(2)) { case 0: pip = new CopyFile(sourceArtifact, destinationArtifact, ReadOnlyArray <StringId> .Empty, PipProvenance.CreateDummy(context)); queueKind = DispatcherKind.IO; executionEnvironment.AddExpectedWrite(pip, destinationArtifact, executionEnvironment.GetExpectedContent(sourceArtifact)); break; case 1: string workingDirectory = OperatingSystemHelper.IsUnixOS ? "/tmp" : Environment.GetFolderPath(Environment.SpecialFolder.Windows); AbsolutePath workingDirectoryAbsolutePath = AbsolutePath.Create(pathTable, workingDirectory); var pipData = OperatingSystemHelper.IsUnixOS ? PipDataBuilder.CreatePipData(pathTable.StringTable, " ", PipDataFragmentEscaping.CRuntimeArgumentRules, "-c", "'", "cp", sourceArtifact, destinationArtifact, "'") : PipDataBuilder.CreatePipData(pathTable.StringTable, " ", PipDataFragmentEscaping.CRuntimeArgumentRules, "/d", "/c", "copy", "/B", sourceArtifact, destinationArtifact); queueKind = DispatcherKind.CPU; pip = new Process( executableArtifact, workingDirectoryAbsolutePath, pipData, FileArtifact.Invalid, PipData.Invalid, ReadOnlyArray <EnvironmentVariable> .Empty, FileArtifact.Invalid, FileArtifact.Invalid, FileArtifact.Invalid, tempFiles.GetUniqueDirectory(pathTable), null, null, ReadOnlyArray <FileArtifact> .FromWithoutCopy(executableArtifact, sourceArtifact), ReadOnlyArray <FileArtifactWithAttributes> .FromWithoutCopy(destinationArtifact.WithAttributes()), ReadOnlyArray <DirectoryArtifact> .Empty, ReadOnlyArray <DirectoryArtifact> .Empty, ReadOnlyArray <PipId> .Empty, ReadOnlyArray <AbsolutePath> .From(CmdHelper.GetCmdDependencies(pathTable)), ReadOnlyArray <AbsolutePath> .From(CmdHelper.GetCmdDependencyScopes(pathTable)), ReadOnlyArray <StringId> .Empty, ReadOnlyArray <int> .Empty, ReadOnlyArray <ProcessSemaphoreInfo> .Empty, provenance: PipProvenance.CreateDummy(context), toolDescription: StringId.Invalid, additionalTempDirectories: ReadOnlyArray <AbsolutePath> .Empty); executionEnvironment.AddExpectedWrite(pip, destinationArtifact, executionEnvironment.GetExpectedContent(sourceArtifact)); break; default: Contract.Assert(false); continue; } var pipId = pipTable.Add((uint)((range *M) + N + i + 1), pip); Func <RunnablePip, Task> taskFactoryWithCallback = async(runnablePip) => { var task = taskFactory(runnablePip); var pipResult = await task; callback(pipId, task); }; var runnable = RunnablePip.Create(loggingContext, executionEnvironment, pipId, pipTable.GetPipType(pipId), 0, taskFactoryWithCallback, 0); runnable.Start(new OperationTracker(loggingContext), loggingContext); runnable.SetDispatcherKind(queueKind); phase2PipQueue.Enqueue(runnable); if (!pips.TryAdd(pipId, Tuple.Create(destination, sourceIndex))) { Contract.Assert(false); } } phase2PipQueue.SetAsFinalized(); phase2PipQueue.DrainQueues(); XAssert.AreEqual(0, pips.Count); await Task.WhenAll(checkerTasks); } })); } } } }
private async Task VerifyReporting(AccessType access, Action <FileAccessManifest> populateManifest, params ExpectedReportEntry[] expectedExplicitReports) { // We need a process which will generate the expected accesses. var testProcess = CreateTestProcess(access, expectedExplicitReports); var pathTable = Context.PathTable; var info = ToProcessInfo(testProcess, "FileAccessExplicitReportingTest"); info.FileAccessManifest.ReportFileAccesses = false; info.FileAccessManifest.ReportUnexpectedFileAccesses = true; info.FileAccessManifest.FailUnexpectedFileAccesses = false; populateManifest(info.FileAccessManifest); using (ISandboxedProcess process = await StartProcessAsync(info)) { SandboxedProcessResult result = await process.GetResultAsync(); XAssert.AreEqual(0, result.ExitCode, "\r\ncmd: {0} \r\nStandard out: '{1}' \r\nStandard err: '{2}'.", info.Arguments, await result.StandardOutput.ReadValueAsync(), await result.StandardError.ReadValueAsync()); XAssert.IsNotNull(result.ExplicitlyReportedFileAccesses); Dictionary <AbsolutePath, ExpectedReportEntry> pathsToExpectations = expectedExplicitReports.ToDictionary( e => e.File.Path, e => e); var verifiedPaths = new HashSet <AbsolutePath>(); foreach (var actualReport in result.ExplicitlyReportedFileAccesses) { string actualReportedPathString = actualReport.GetPath(pathTable); XAssert.AreEqual( FileAccessStatus.Allowed, actualReport.Status, "Incorrect status for path " + actualReportedPathString); if (!TryVerifySingleReport(pathTable, actualReport, access, pathsToExpectations, out var actualReportPath)) { if ((actualReport.RequestedAccess & RequestedAccess.Enumerate) != 0) { // To account for 'explicitly reported' enumerations globally, we need to be lenient about unexpected enumerations. // Alternatively instead opt-in to enumeration reports under certain scopes. } else { AbsolutePath actualReportedPath = AbsolutePath.Create(pathTable, actualReportedPathString); XAssert.Fail("No expectations for an explicitly reported path {0}", actualReportedPath.ToString(pathTable)); } } else { verifiedPaths.Add(actualReportPath); } } foreach (var actualReport in result.AllUnexpectedFileAccesses) { XAssert.AreEqual(FileAccessStatus.Denied, actualReport.Status); if (TryVerifySingleReport(pathTable, actualReport, access, pathsToExpectations, out var actualReportPath)) { verifiedPaths.Add(actualReportPath); } // Note that we allow extra unexpected file accesses for the purposes of these tests. } var expectedPathsSet = new HashSet <AbsolutePath>(pathsToExpectations.Keys); var disagreeingPaths = new HashSet <AbsolutePath>(verifiedPaths); disagreeingPaths.SymmetricExceptWith(expectedPathsSet); if (disagreeingPaths.Any()) { var disagreeingReports = "Disagreeing reports:" + string.Join(string.Empty, disagreeingPaths .Select(p => (tag: expectedPathsSet.Contains(p) ? "Missing" : "Unexpected", path: p)) .Select(t => $"{Environment.NewLine} {t.tag} report for path {t.path.ToString(pathTable)}")); var expectedReports = "Expected reports:" + string.Join(string.Empty, pathsToExpectations.Keys .Select(p => $"{Environment.NewLine} {p.ToString(pathTable)}")); var verifiedReports = "Verified reports:" + string.Join(string.Empty, verifiedPaths .Select(p => $"{Environment.NewLine} {p.ToString(pathTable)}")); XAssert.Fail(string.Join(Environment.NewLine, disagreeingReports, expectedReports, verifiedReports)); } } }
private static object CreateInstance(BuildXLContext context, Type type, bool booleanDefault) { string path = A("x", "path"); type = GetNonNullableType(type); if (type == typeof(bool)) { return(booleanDefault); } if (type == typeof(double)) { return((double)0.23423); } if (type == typeof(byte)) { return((byte)123); } if (type == typeof(sbyte)) { return((sbyte)123); } if (type == typeof(short)) { return((short)123); } if (type == typeof(ushort)) { return((ushort)123); } if (type == typeof(int)) { return(123); } if (type == typeof(uint)) { return((uint)123); } if (type == typeof(long)) { return((long)123); } if (type == typeof(ulong)) { return((ulong)123); } if (type == typeof(string)) { return("nonDefaultString"); } if (type == typeof(ModuleId)) { return(new ModuleId(123)); } if (type == typeof(LocationData)) { return(new LocationData(AbsolutePath.Create(context.PathTable, path), 12, 23)); } if (type == typeof(AbsolutePath)) { return(AbsolutePath.Create(context.PathTable, path)); } if (type == typeof(RelativePath)) { string relativePath = R("rel1", "dir1", "path"); return(RelativePath.Create(context.StringTable, relativePath)); } if (type == typeof(FileArtifact)) { return(FileArtifact.CreateSourceFile(AbsolutePath.Create(context.PathTable, path))); } if (type == typeof(PathAtom)) { return(PathAtom.Create(context.StringTable, "atom")); } if (type == typeof(global::BuildXL.Utilities.LineInfo)) { return(new global::BuildXL.Utilities.LineInfo(1, 1)); } if (type.GetTypeInfo().IsEnum) { bool first = true; foreach (var value in Enum.GetValues(type)) { if (!first) { return(value); } first = false; } XAssert.Fail($"Enum {type.FullName} doesn't have more than one value, so can't pick the second one."); } if (type.GetTypeInfo().IsGenericType) { var generic = type.GetGenericTypeDefinition(); if (generic == typeof(IReadOnlyList <>)) { // Treat IReadOnlyList as if it was List type = typeof(List <>).MakeGenericType(type.GenericTypeArguments[0]); generic = type.GetGenericTypeDefinition(); } if (generic == typeof(List <>)) { var newList = (IList)Activator.CreateInstance(type); newList.Add(CreateInstance(context, type.GenericTypeArguments[0], booleanDefault)); return(newList); } if (generic == typeof(IReadOnlyDictionary <,>)) { // Treat IReadOnlyList as if it was List type = typeof(Dictionary <,>).MakeGenericType(type.GenericTypeArguments[0], type.GenericTypeArguments[1]); generic = type.GetGenericTypeDefinition(); } if (generic == typeof(Dictionary <,>)) { var newDictionary = (IDictionary)Activator.CreateInstance(type); newDictionary.Add( CreateInstance(context, type.GenericTypeArguments[0], booleanDefault), CreateInstance(context, type.GenericTypeArguments[1], booleanDefault)); return(newDictionary); } if (generic == typeof(ValueTuple <,>)) { var newTuple = Activator.CreateInstance(type); // In ValueTuple classes, the first 7 values are accessible via Item1-Item7 fields. // The tuple field names (named tuples) aren't part of runtime representation. type.GetField("Item1").SetValue(newTuple, CreateInstance(context, type.GenericTypeArguments[0], booleanDefault)); type.GetField("Item2").SetValue(newTuple, CreateInstance(context, type.GenericTypeArguments[1], booleanDefault)); return(newTuple); } } if (type.GetTypeInfo().IsInterface) { // Treat interfaces as if it was the mutable class type = ConfigurationConverter.FindImplementationType( type, ObjectLiteral.Create(new List <Binding>(), default(LineInfo), AbsolutePath.Invalid), // Return a SourceResolver to instantiate () => "SourceResolver"); } if (type.GetTypeInfo().IsClass) { var instance = Activator.CreateInstance(type); PopulateObject(context, type, instance, booleanDefault); return(instance); } XAssert.Fail($"Don't know how to create objects for this type: {type.FullName}."); return(null); }
public static void StaticAwaitCond(Func <bool> evaluator, TimeSpan max, TimeSpan?interval) { InternalAwaitCondition(evaluator, max, interval, (format, args) => XAssert.Fail(string.Format(format, args))); }
public SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> ListSealedDirectoryContents(DirectoryArtifact directoryArtifact) { XAssert.Fail("Shouldn't be called since no sealed directories are introduced"); return(default(SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer>)); }
public static void ValidateEqual(BuildXLContext context, Type type, object expected, object actual, string objPath, Remapper remapper) { type = GetNonNullableType(type); if (type == typeof(bool)) { XAssert.AreEqual((bool)expected, (bool)actual, $"{nameof(Boolean)} values don't match for objPath: {objPath}"); return; } if (type == typeof(int) || type == typeof(short) || type == typeof(sbyte) || type == typeof(long)) { XAssert.AreEqual( Convert.ToInt64(expected), Convert.ToInt64(actual), $"Numeric values don't match for objPath: {objPath}"); return; } if (type == typeof(uint) || type == typeof(ushort) || type == typeof(byte) || type == typeof(ulong)) { XAssert.AreEqual( Convert.ToUInt64(expected), Convert.ToUInt64(actual), $"Numeric values don't match for objPath: {objPath}"); return; } if (type == typeof(double)) { XAssert.AreEqual( Convert.ToDouble(expected), Convert.ToDouble(actual), $"Numeric values don't match for objPath: {objPath}"); return; } if (type == typeof(string)) { XAssert.AreEqual((string)expected, (string)actual, $"{nameof(String)} values don't match for objPath: {objPath}"); return; } if (type == typeof(ModuleId)) { XAssert.AreEqual( (ModuleId)expected, (ModuleId)actual, $"{nameof(ModuleId)} id values don't match for objPath: {objPath}"); return; } if (type == typeof(LocationData)) { AssertEqualLocationData(context, objPath, remapper, (LocationData)expected, (LocationData)actual); return; } if (type == typeof(RelativePath)) { AssertEqualRelativePaths(context, objPath, remapper, (RelativePath)expected, (RelativePath)actual); return; } if (type == typeof(AbsolutePath)) { AssertEqualAbsolutePaths(context, objPath, remapper, (AbsolutePath)expected, (AbsolutePath)actual); return; } if (type == typeof(FileArtifact)) { AssertEqualFileArtifacts(context, objPath, remapper, (FileArtifact)expected, (FileArtifact)actual); return; } if (type == typeof(PathAtom)) { AssertEqualPathAtoms(context, objPath, remapper, (PathAtom)expected, (PathAtom)actual); return; } if (type == typeof(SymbolAtom)) { XAssert.AreEqual((SymbolAtom)expected, (SymbolAtom)actual, $"{nameof(SymbolAtom)} values don't match for objPath: {objPath}"); return; } if (type == typeof(global::BuildXL.Utilities.LineInfo)) { XAssert.AreEqual( (global::BuildXL.Utilities.LineInfo)expected, (global::BuildXL.Utilities.LineInfo)actual, $"{nameof(global::BuildXL.Utilities.LineInfo)} values don't match for objPath: {objPath}"); return; } if (type == typeof(LineInfo)) { XAssert.AreEqual( (LineInfo)expected, (LineInfo)actual, $"{nameof(LineInfo)} values don't match for objPath: {objPath}"); return; } if (type.GetTypeInfo().IsEnum) { XAssert.AreEqual((Enum)expected, (Enum)actual, $"Enum values don't match for objPath: {objPath}"); return; } if (type.GetTypeInfo().IsGenericType) { var generic = type.GetGenericTypeDefinition(); if (generic == typeof(List <>) || generic == typeof(IReadOnlyList <>)) { XAssert.IsTrue((expected == null) == (actual == null)); var expectedList = expected as IList; var actualList = actual as IList; XAssert.IsTrue( (expectedList == null) == (actualList == null), "One of the lists is null, the other isn't for objPath: {0}", objPath); if (expectedList != null) { XAssert.AreEqual(expectedList.Count, actualList.Count, $"Counts of lists don't match for objPath: {objPath}"); for (int i = 0; i < expectedList.Count; i++) { ValidateEqual( context, type.GenericTypeArguments[0], expectedList[i], actualList[i], objPath + "[" + i.ToString(CultureInfo.InvariantCulture) + "]", remapper); } } return; } if (generic == typeof(Dictionary <,>) || generic == typeof(IReadOnlyDictionary <,>) || generic == typeof(ConcurrentDictionary <,>)) { XAssert.IsTrue((expected == null) == (actual == null)); var expectedDictionary = expected as IDictionary; var actualDictionary = actual as IDictionary; XAssert.IsTrue( (expectedDictionary == null) == (actualDictionary == null), $"One of the dictionaries is null, the other isn't for objPath: {objPath}"); if (expectedDictionary != null) { XAssert.AreEqual( expectedDictionary.Count, expectedDictionary.Count, $"Counts of dictionaries don't match for objPath: {objPath}"); foreach (var kv in expectedDictionary) { var key = kv.GetType().GetProperty("Key").GetValue(kv); var value = kv.GetType().GetTypeInfo().GetProperty("Value").GetValue(kv); var actualValue = actualDictionary[key]; ValidateEqual(context, type.GenericTypeArguments[1], value, actualValue, objPath + "[" + key + "]", remapper); } } return; } } if (type.GetTypeInfo().IsInterface) { var actualType = ConfigurationConverter.FindImplementationType( type, ObjectLiteral.Create(new List <Binding>(), default(LineInfo), AbsolutePath.Invalid), // Note we only create a sourceresolver, so no need to fiddle, just compare with SourceResolver. () => "SourceResolver"); ValidateEqualMembers(context, actualType, expected, actual, objPath, remapper); return; } if (type.GetTypeInfo().IsClass) { ValidateEqualMembers(context, type, expected, actual, objPath, remapper); return; } XAssert.Fail($"Don't know how to compare objects of this type '{type}' for objPath: {objPath}"); }
public void GetOrSetStress() { // Generate a bunch of operations that work on a set of fields that trigger resizes, updates and reads. var list = new ConcurrentArrayList <TestValue>(1, true); var rnd = new Random(); int maxIndex = 2000; int maxOperationsFactor = 1000; int val0 = 0xfff0000; int val1 = 0x000ff000; int val2 = 0x00000fff; var operations = Enumerable .Range(0, maxIndex * maxOperationsFactor) .Select( index => { int value; int valueToSet = rnd.Next(3); switch (valueToSet) { case 0: value = val0; break; case 1: value = val1; break; case 2: value = val2; break; default: value = 0; XAssert.Fail("sdfsd"); break; } return(new { Index = index / maxOperationsFactor, Value = value }); }) .ToArray() .OrderBy(x => rnd.Next(maxIndex)); Parallel.ForEach( operations, operation => { // Make sure it is one of the legal value. TestValue res = list.GetOrSet(operation.Index, () => new TestValue(operation.Value)); XAssert.IsTrue(res.Value == val0 || res.Value == val1 || res.Value == val2); // Also inspect random location. Make sure it is a legal value (or null when it is not set yet) TestValue other = list[rnd.Next(maxIndex)]; XAssert.IsTrue(other == null || other.Value == val0 || other.Value == val1 || other.Value == val2); }); }
void IObserver <ChangedPathInfo> .OnError(Exception error) { XAssert.Fail("Error processing: " + error); }
public void AllBasicEvents() { using (var l = new TestListener()) { MemberInfo[] allEventsMembers = typeof(Events).GetMembers(BindingFlags.Public | BindingFlags.Instance); foreach (MemberInfo eventsMember in allEventsMembers) { if (eventsMember is MethodInfo) { // Not all members are methods. continue; } var eventAttribute = eventsMember.GetCustomAttribute(typeof(EventAttribute)) as EventAttribute; if (eventAttribute == null) { // Not all members are tagged with [Event] data. continue; } var eventMethod = (MethodInfo)eventsMember; bool containsRelatedActivityId; object[] payload = CreateEventPayload(eventMethod, out containsRelatedActivityId); eventMethod.Invoke(Events.Log, payload); XAssert.AreEqual(eventAttribute.EventId, l.LastEvent.EventId, "Wrong event ID logged for event {0}", eventMethod.Name); XAssert.AreNotEqual(0, eventAttribute.Task, "Invalid task id == 0 for event {0} (this results in auto-assignment of task id)", eventMethod.Name); XAssert.AreEqual(eventAttribute.Task, l.LastEvent.Task, "Wrong task logged for event {0}", eventMethod.Name); XAssert.AreEqual(eventAttribute.Opcode, l.LastEvent.Opcode, "Wrong opcode logged for event {0}", eventMethod.Name); XAssert.AreEqual(eventAttribute.Level, l.LastEvent.Level, "Wrong level logged for event {0}", eventMethod.Name); XAssert.IsTrue(!containsRelatedActivityId || eventAttribute.Opcode == EventOpcode.Start, "Found related activity ID for non-start event {0}", eventMethod.Name); // EventSource does something weird with the top bits, but the bottom bits should be non-zero. unchecked { XAssert.AreEqual <uint>( (uint)eventAttribute.Keywords, (uint)l.LastEvent.Keywords, "Wrong keywords logged for event {0}", eventMethod.Name); XAssert.AreNotEqual <uint>(0, (uint)eventAttribute.Keywords, "Event {0} should have keywords defined", eventMethod.Name); } XAssert.IsTrue( (eventAttribute.Keywords & Keywords.Diagnostics) == 0 || (eventAttribute.Keywords & Keywords.UserMessage) == 0, "Event {0} specifies both the UserMessage and Diagnostics keywords; these are mutually exclusive.", eventMethod.Name); string formattedMessage; try { formattedMessage = string.Format(CultureInfo.InvariantCulture, l.LastEvent.Message, l.LastEvent.Payload.ToArray()); } catch (FormatException ex) { XAssert.Fail( "Formatting the message for event {0}. Maybe the format string does not match the WriteEvent arguments. Exception: {1}", eventMethod.Name, ex.ToString()); return; } if (containsRelatedActivityId) { object[] payloadCopy = new object[payload.Length - 1]; Array.Copy(payload, 1, payloadCopy, 0, payloadCopy.Length); payload = payloadCopy; } XAssert.AreEqual( payload.Length, l.LastEvent.Payload.Count, "Wrong payload size for event {0} (formatted message: `{1}`)", eventMethod.Name, formattedMessage); for (int i = 0; i < payload.Length; i++) { XAssert.AreEqual( payload[i], l.LastEvent.Payload[i], "Incorrect payload value for event {0}, position {1} (formatted message: `{2}`)", eventMethod.Name, i, formattedMessage); } // We now verify that all strings in the payload appear in the message. // We exclude pip-provenance and phase events for now because for some reason they define GUIDs that never actually // get logged (which is probably not a valid thing to do on an EventSource). if (!l.LastEvent.Message.StartsWith(EventConstants.ProvenancePrefix, StringComparison.Ordinal) && !l.LastEvent.Message.StartsWith(EventConstants.PhasePrefix, StringComparison.Ordinal)) { for (int i = 0; i < payload.Length; i++) { var currentPayload = payload[i] as string; if (currentPayload != null) { XAssert.IsTrue( formattedMessage.Contains(currentPayload), "The formatted message for event {0} did not include the payload string at index {1}", eventMethod.Name, i); } } } if (eventAttribute.EventId != (int)EventId.ErrorEvent) { XAssert.IsTrue( eventAttribute.Level != EventLevel.Error || (eventAttribute.Keywords & Keywords.UserMessage) == Keywords.UserMessage, "Event {0} marked as Error must be Keywords.UserMessage", eventMethod.Name); } } } }
public void RoundTripLog() { BuildXLContext context = BuildXLContext.CreateInstanceForTesting(); var pt = context.PathTable; string path1 = A("c", "a", "b", "c"); var ap1 = AbsolutePath.Create(pt, path1); string path2 = A("c", "d", "c", "a"); var ap2 = AbsolutePath.Create(pt, path2); string path3 = A("d", "a", "c", "a"); var ap3 = AbsolutePath.Create(pt, path3); string path3Caps = A("D", "A", "c", "a"); var ap3Caps = AbsolutePath.Create(pt, path3Caps); int lastTestCase0EventIteration = 0; int testCase0EventIteration = 0; int expectedReadCount = 0; Guid logId = Guid.NewGuid(); using (MemoryStream ms = new MemoryStream()) { using (BinaryLogger writer = new BinaryLogger(ms, context, logId, lastStaticAbsolutePathIndex: ap2.Value.Value, closeStreamOnDispose: false)) { using (var eventScope = writer.StartEvent((uint)EventId.TestCase0, workerId: 0)) { eventScope.Writer.Write(ap1); eventScope.Writer.Write("test string"); eventScope.Writer.Write(ap3); eventScope.Writer.Write(12345); expectedReadCount++; lastTestCase0EventIteration++; } using (var eventScope = writer.StartEvent((uint)EventId.TestCase0, workerId: 0)) { eventScope.Writer.Write("test string 2"); eventScope.Writer.Write(true); eventScope.Writer.Write(ap3); expectedReadCount++; lastTestCase0EventIteration++; } } ms.Position = 0; using (BinaryLogReader reader = new BinaryLogReader(ms, context)) { XAssert.IsTrue(reader.LogId.HasValue); XAssert.AreEqual(logId, reader.LogId.Value); reader.RegisterHandler((uint)EventId.TestCase0, (eventId, workerId, timestamp, eventReader) => { switch (testCase0EventIteration) { case 0: XAssert.AreEqual(ap1, eventReader.ReadAbsolutePath()); XAssert.AreEqual("test string", eventReader.ReadString()); XAssert.AreEqual(ap3, eventReader.ReadAbsolutePath()); XAssert.AreEqual(12345, eventReader.ReadInt32()); break; case 1: XAssert.AreEqual("test string 2", eventReader.ReadString()); XAssert.AreEqual(true, eventReader.ReadBoolean()); XAssert.AreEqual(ap3, eventReader.ReadAbsolutePath()); break; default: XAssert.Fail("Event raised unexpected number of times."); break; } testCase0EventIteration++; }); reader.RegisterHandler((uint)EventId.UnusedEvent, (eventId, workerId, timestamp, eventReader) => { XAssert.Fail("This event should never be called."); }); int readCount = 0; BinaryLogReader.EventReadResult?readResult; while ((readResult = reader.ReadEvent()) == BinaryLogReader.EventReadResult.Success) { XAssert.IsTrue(readCount < expectedReadCount); readCount++; } XAssert.AreEqual(expectedReadCount, readCount); XAssert.AreEqual(lastTestCase0EventIteration, testCase0EventIteration); XAssert.AreEqual(BinaryLogReader.EventReadResult.EndOfStream, readResult); } } }
public void ChildProcessCanBreakawayWhenConfigured(bool letInfiniteWaiterSurvive) { // Skip this test if running on .NET Framework with vstest // Reason: when this is the case and code coverage is turned on, launching breakaway // processes here causes the code coverage monitoring process to hang. if (!OperatingSystemHelper.IsDotNetCore && IsRunningInVsTestTestHost()) { return; } // We use InfiniteWaiter (a process that waits forever) as a long-living process that we can actually check it can // escape the job object var fam = new FileAccessManifest( Context.PathTable, childProcessesToBreakawayFromSandbox: letInfiniteWaiterSurvive ? new[] { InfiniteWaiterToolName } : null) { FailUnexpectedFileAccesses = false }; // We instruct the regular test process to spawn InfiniteWaiter as a child var info = ToProcessInfo( ToProcess( Operation.SpawnExe( Context.PathTable, CreateFileArtifactWithName(InfiniteWaiterToolName, TestDeploymentDir))), fileAccessManifest: fam); // Let's shorten the default time to wait for nested processes, since we are spawning // a process that never ends and we don't want this test to wait for that long info.NestedProcessTerminationTimeout = TimeSpan.FromMilliseconds(10); var result = RunProcess(info).GetAwaiter().GetResult(); XAssert.AreEqual(0, result.ExitCode); if (!letInfiniteWaiterSurvive) { // If we didn't let infinite waiter escape, we should have killed it when the job object was finalized XAssert.IsTrue(result.Killed); XAssert.Contains( result.SurvivingChildProcesses.Select(p => p?.Path).Where(p => p != null).Select(p => System.IO.Path.GetFileName(p).ToUpperInvariant()), InfiniteWaiterToolName.ToUpperInvariant()); } else { // If we did let it escape, then nothing should have been killed (nor tried to survive and later killed, from the job object point of view) XAssert.IsFalse(result.Killed); if (result.SurvivingChildProcesses != null && result.SurvivingChildProcesses.Any()) { var survivors = string.Join( ", ", result.SurvivingChildProcesses.Select(p => p?.Path != null ? System.IO.Path.GetFileName(p.Path) : "<unknown>")); XAssert.Fail($"Unexpected {result.SurvivingChildProcesses.Count()} surviving child processes: {survivors}"); } // Let's retrieve the child process and confirm it survived var infiniteWaiterInfo = RetrieveChildProcessesCreatedBySpawnExe(result).Single(); // The fact that this does not throw confirms survival var dummyWaiter = Process.GetProcessById(infiniteWaiterInfo.pid); // Just being protective, let's make sure we are talking about the same process XAssert.AreEqual(infiniteWaiterInfo.processName, dummyWaiter.ProcessName); // Now let's kill the surviving process, since we don't want it to linger around unnecessarily dummyWaiter.Kill(); } }