예제 #1
0
        public void DirectorySymlinksAreTraversed()
        {
            string rootDir           = Path.Combine(TemporaryDirectory, nameof(DirectorySymlinksAreTraversed));
            string fullTargetDirPath = Path.Combine(rootDir, "target-dir");

            Directory.CreateDirectory(fullTargetDirPath);

            var fileUnderTarget = Path.Combine(fullTargetDirPath, "file.txt");

            File.WriteAllText(fileUnderTarget, "content");

            string rootToScrub = Path.Combine(rootDir, "root-to-scrub");

            Directory.CreateDirectory(rootToScrub);

            string fullSymlinkPath = WriteSymlink(Path.Combine(rootToScrub, "directory symlink"), fullTargetDirPath, isTargetFile: false);

            XAssert.IsTrue(FileUtilities.FileExistsNoFollow(fullSymlinkPath));

            // Scrub starting on a root dir that contains a symlink directory. We should be able to find the file underneath and delete it
            // We consider all artifacts to be not part of the build, so symlink directories are followed and all files are deleted
            Scrubber.RemoveExtraneousFilesAndDirectories(
                isPathInBuild: path => false,
                pathsToScrub: new[] { rootDir },
                blockedPaths: CollectionUtilities.EmptyArray <string>(),
                nonDeletableRootDirectories: CollectionUtilities.EmptyArray <string>());

            XAssert.IsFalse(File.Exists(fileUnderTarget));
            XAssert.Equals(OperatingSystemHelper.IsMacOS, !Directory.Exists(fullSymlinkPath));
        }
예제 #2
0
        public void DeleteFilesCancellationDoesNotCrash()
        {
            const int FileDeletionsAllowed = 2;
            var       testHook             = new DirectoryScrubber.TestHooks
            {
                OnDeletion = new Action <string, int>((path, numDeletedSoFar) =>
                {
                    if (numDeletedSoFar > FileDeletionsAllowed)
                    {
                        m_cancellationTokenSource.Cancel();
                    }
                })
            };

            string rootDir = Path.Combine(TemporaryDirectory, nameof(DeleteFilesCanDeleteFile));

            List <string> files = new List <string>();

            for (var i = 0; i < FileDeletionsAllowed * 3; i++)
            {
                string fullFilePath = WriteFile(Path.Combine(rootDir, $"out{i}.txt"));
                XAssert.FileExists(fullFilePath);
                files.Add(fullFilePath);
            }

            XAssert.IsFalse(m_cancellationTokenSource.IsCancellationRequested);

            var numDeleted = Scrubber.DeleteFiles(files.ToArray(), testHook: testHook);

            XAssert.IsTrue(m_cancellationTokenSource.IsCancellationRequested);
            XAssert.Equals(FileDeletionsAllowed, numDeleted);
        }
예제 #3
0
        public void ABTestingOptionRelatedActivityIdSeed()
        {
            PathTable pt         = new PathTable();
            var       argsParser = new Args();

            string relatedActivityArg = "/relatedActivityId:cd0adef6-abef-4990-8cde-32441a54f747";
            string abTestingArg1      = "/abTesting:Id1=\"/maxProc:5\"";
            string abTestingArg2      = "/abTesting:Id2=\"/maxProc:10\"";

            string[] args = new[] { @"/c:" + m_specFilePath, relatedActivityArg, abTestingArg1, abTestingArg2 };
            XAssert.IsTrue(argsParser.TryParse(args, pt, out var config1));

            var chosen = config1.Startup.ChosenABTestingKey;

            XAssert.IsNotNull(chosen);

            XAssert.IsTrue(argsParser.TryParse(args, pt, out var config2));
            XAssert.Equals(chosen, config2.Startup.ChosenABTestingKey);

            XAssert.IsTrue(argsParser.TryParse(args, pt, out var config3));
            XAssert.Equals(chosen, config3.Startup.ChosenABTestingKey);

            XAssert.IsTrue(argsParser.TryParse(args, pt, out var config4));
            XAssert.Equals(chosen, config4.Startup.ChosenABTestingKey);
        }
예제 #4
0
        public void BlockExclusionFlagIsHonored(bool blockWritesUnderNodeModules)
        {
            var project = CreateRushProject();

            var exclusions = Start(new RushResolverSettings {
                BlockWritesUnderNodeModules = blockWritesUnderNodeModules
            })
                             .Add(project)
                             .ScheduleAll()
                             .RetrieveSuccessfulProcess(project)
                             .OutputDirectoryExclusions;

            XAssert.Equals(blockWritesUnderNodeModules? 1 : 0, exclusions.Length);
        }
예제 #5
0
        public void SymlinkDirectoriesDoNotIntroduceDuplicateWork()
        {
            // We are creating this layout
            //
            // root
            // -- real-dir
            //    -- symlink-dir -> real-dir
            //       --file.txt
            //
            // so there is in fact a cycle, where root/real-dir/symlink-dir/.../symlink-dir/... is a valid path
            // The fact that scrubbing finishes proves we are deduping work

            string rootDir       = Path.Combine(TemporaryDirectory, nameof(SymlinkDirectoriesDoNotIntroduceDuplicateWork));
            string realDirectory = Path.Combine(rootDir, "real-dir");

            Directory.CreateDirectory(realDirectory);

            string symlinkDirectory = WriteSymlink(Path.Combine(realDirectory, "symlink-dir"), rootDir, isTargetFile: false);

            XAssert.IsTrue(FileUtilities.FileExistsNoFollow(symlinkDirectory));

            var fileUnderSymlinkDir = Path.Combine(symlinkDirectory, "file.txt");

            File.WriteAllText(fileUnderSymlinkDir, "content");

            try
            {
                Scrubber.RemoveExtraneousFilesAndDirectories(
                    isPathInBuild: path => false,
                    pathsToScrub: new[] { rootDir },
                    blockedPaths: CollectionUtilities.EmptyArray <string>(),
                    nonDeletableRootDirectories: CollectionUtilities.EmptyArray <string>());

                XAssert.IsFalse(File.Exists(fileUnderSymlinkDir));
                XAssert.Equals(!OperatingSystemHelper.IsMacOS, Directory.Exists(realDirectory));
                XAssert.Equals(!OperatingSystemHelper.IsMacOS, Directory.Exists(symlinkDirectory));
            }
            finally
            {
                // On Windows, the temp directory cleaner has problems with cycles. So let's remove the symlink dir explicitly here
                if (!OperatingSystemHelper.IsMacOS)
                {
                    Directory.Delete(symlinkDirectory);
                }
            }
        }
예제 #6
0
        public void PredictedInputsUnderUntrackedDirectoriesAreSkipped()
        {
            var project = CreateProjectWithPredictions(inputs: CreatePath(@"untracked\input.txt", "input2.txt"));

            var processInputs = Start(new MsBuildResolverSettings
            {
                UntrackedDirectories = CreatePath("untracked").Select(path => DirectoryArtifact.CreateWithZeroPartialSealId(path)).ToList()
            })
                                .Add(project)
                                .ScheduleAll()
                                .RetrieveSuccessfulProcess(project)
                                .Dependencies;

            // The only source file (besides MSBuild.exe itself) should be input2
            var input = processInputs.Single(i => (i.IsSourceFile && i.Path.GetName(PathTable) != PathAtom.Create(StringTable, "MSBuild.exe")));

            XAssert.Equals("input2.txt", input.Path.GetName(PathTable).ToString(PathTable.StringTable));
        }
예제 #7
0
        public void PredictedInputsInKnownOutputDirectoriesAreSkipped()
        {
            var dependency = CreateProjectWithPredictions(outputs: CreatePath("OutDir"));

            // We create 4 predicted inputs. 3 of them under predicted output directories. So only the last one should be added as a true input, the rest are assumed to be intermediates
            var dependent = CreateProjectWithPredictions(
                outputs: CreatePath("AnotherOutput"),
                inputs: CreatePath(@"AnotherOutput\input.txt", @"OutDir\input1.txt", @"OutDir\nested\input2.txt", "input3.txt"),
                references: new[] { dependency });

            var processInputs = Start()
                                .Add(dependency)
                                .Add(dependent)
                                .ScheduleAll()
                                .RetrieveSuccessfulProcess(dependent)
                                .Dependencies;

            // The only source file (besides MSBuild.exe itself) should be input3
            var input = processInputs.Single(i => (i.IsSourceFile && i.Path.GetName(PathTable) != PathAtom.Create(StringTable, "MSBuild.exe")));

            XAssert.Equals("input3.txt", input.Path.GetName(PathTable).ToString(PathTable.StringTable));
        }
예제 #8
0
        public void AllowedDoubleWriteCachesTheRightContent()
        {
            string       sharedOpaqueDir     = Path.Combine(ObjectRoot, "sharedopaquedir");
            AbsolutePath sharedOpaqueDirPath = AbsolutePath.Create(Context.PathTable, sharedOpaqueDir);

            FileArtifact doubleWriteArtifact = CreateOutputFileArtifact(sharedOpaqueDir);

            var firstProducerBuilder  = CreateFileInSharedOpaqueBuilder(ContainerIsolationLevel.IsolateAllOutputs, RewritePolicy.UnsafeFirstDoubleWriteWins, doubleWriteArtifact, "first", sharedOpaqueDirPath);
            var secondProducerBuilder = CreateFileInSharedOpaqueBuilder(ContainerIsolationLevel.IsolateAllOutputs, RewritePolicy.UnsafeFirstDoubleWriteWins, doubleWriteArtifact, "second", sharedOpaqueDirPath);
            var firstProducer         = SchedulePipBuilder(firstProducerBuilder);
            var secondProducer        = SchedulePipBuilder(secondProducerBuilder);

            // Given the policy and isolation level, both producers should get cached
            RunScheduler().AssertSuccess();
            AssertWarningEventLogged(LogEventId.FileMonitoringWarning);

            string doubleWritePath = doubleWriteArtifact.Path.ToString(Context.PathTable);

            // Run the first producer alone. It should be a cache hit, and the content of the produced
            // file should correspond to the first producer

            RootFilter filter = new RootFilter(new PipIdFilter(firstProducer.Process.SemiStableHash));
            var        result = RunScheduler(filter: filter).AssertSuccess();

            result.AssertCacheHit(firstProducer.Process.PipId);
            XAssert.IsTrue(File.Exists(doubleWritePath));
            XAssert.Equals("first", File.ReadAllText(doubleWritePath));

            // Same procedure with the second producer
            filter = new RootFilter(new PipIdFilter(secondProducer.Process.SemiStableHash));
            result = RunScheduler(filter: filter).AssertSuccess();
            result.AssertCacheHit(secondProducer.Process.PipId);

            XAssert.IsTrue(File.Exists(doubleWritePath));
            XAssert.Equals("second", File.ReadAllText(doubleWritePath));
        }