SteveGilham / altcover

Cross-platform coverage gathering and processing tool set for dotnet/.Net Framework and Mono
MIT License
498 stars 18 forks source link

AltCover.ContingentCopy failing due to dotnetcore.testadapter.dll being used by another process #161

Closed MattA48 closed 2 years ago

MattA48 commented 2 years ago

We've just done a routine update of 3rd party libraries for our .NET Core 6 project and have started seeing the above error when testing coverage of our project.

We're running via a Cake script inside Docker. As part of this update we updated AltCover from 8.2.837 to 8.3.838. Rolling this back did not fix the issue, however.

The error and callstack:

#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018: The "AltCover.ContingentCopy" task failed unexpectedly. [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018: System.IO.IOException: The process cannot access the file '/root/.nuget/packages/xunit.runner.visualstudio/2.4.5/build/netcoreapp3.1/xunit.runner.visualstudio.dotnetcore.testadapter.dll' because it is being used by another process. [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018:    at Microsoft.Win32.SafeHandles.SafeFileHandle.Init(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize) [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018:    at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize) [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018:    at System.IO.FileSystem.CopyFile(String sourceFullPath, String destFullPath, Boolean overwrite) [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018:    at System.IO.File.Copy(String sourceFileName, String destFileName, Boolean overwrite) [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018:    at AltCover.ContingentCopy.Execute() in /_//AltCover.Engine/Tasks.fs:line 506 [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute() [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(155,5): error MSB4018:    at Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask(ITaskExecutionHost taskExecutionHost, TaskLoggingContext taskLoggingContext, TaskHost taskHost, ItemBucket bucket, TaskExecutionMode howToExecuteTask) [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]
#13 149.6 /root/.nuget/packages/altcover/8.3.838/build/netstandard2.0/AltCover.targets(203,5): warning : A total of 0 visits recorded [/build/src/test/unit/Bff.Tests/Bff.Tests.csproj]

The process is running in docker base container: mcr.microsoft.com/dotnet/sdk:6.0-focal and running on Cake 2.2.0

Our full "Coverage" section of our Cake file (including AltCover settings) is:


Task("Coverage")
    .IsDependentOn("BuildTest")
    .DoesForEach(GetFiles(TEST_FILES), (file) => {
        var project = file.GetFilenameWithoutExtension().ToString();
        var testDirectory = TEST_DIR + Directory(project);
        var coverageDirectory =  BUILD_DIR + Directory("coverage");
        Information($"Project: {project}, File: {file.FullPath}, TestDirectory: {testDirectory}, CoverageDirectory: {coverageDirectory}");
        var excludedDlls = String.Join(
            "|",
            GetFiles($"{testDirectory}/*.dll")
                .Where(f => !f.GetFilename().ToString().StartsWith("Icis") || f.GetFilename().ToString().EndsWith("Tests.dll"))
                .Select(f => f.GetFilenameWithoutExtension().ToString()));

        var testSettings = new DotNetCoreTestSettings()
        {
            OutputDirectory = testDirectory,
            NoBuild = true,
            Loggers = new[] { "console;verbosity=normal" },
            ArgumentCustomization = args => args
                .Append($"/p:AltCover=true")
                .Append($"/p:AltCoverOpenCover=true")
                .Append($"/p:AltCoverXmlReport={coverageDirectory.Path.MakeAbsolute(Context.Environment)}/{project}.xml")
                .Append($"/p:AltCoverAttributeFilter=ExcludeFromCodeCoverage")
                .Append($"/p:AltCoverAssemblyExcludeFilter={excludedDlls}")
                .Append($"/p:AltCoverForce=true")
                .Append("/p:RestoreLockedMode=true")
        };

        DotNetTest(file.FullPath, testSettings);
        ReportGenerator(
            File($"{coverageDirectory}/{file.GetFilenameWithoutExtension()}.xml"),
            $"{coverageDirectory}/report",
            new ReportGeneratorSettings(){
                                ArgumentCustomization = args => args
                                    .Append("-reporttypes:HTMLInline;TeamCitySummary")
                            });
    });
SteveGilham commented 2 years ago

What's happening here is that by default AltCover creates a copy of the build target directory context, including copying all files marked as "Copy to Output Directory" (resolving issue #112); however something else now happens to be using the file (or have recently been using it, as file system locks tend to linger slightly). I had hoped to avoid adding a back-off and retry to this task, but that looks like it might have to be the way to go.

As a work-around, if that does not interfere with other steps in your build process, setting /p:AltCoverInPlace=true avoids that precautionary copying stage (some copying does happen later, but that gives more chance for things to have been relinquished).

As an aside, while I have Cake user on the line -- have you tried the Cake API (linkable from the altcover.api package, which is there for use instead of the main package for users whose primary use case is scripting dotnet test access rather than running the tool directly? I'd be interested in any comments you might have about that if you do/have tried it.

MattA48 commented 2 years ago

Thanks for the reply, as to the API, no we've not looked at this - the config for our build script has been pretty much 'fire and forget' and if it's working we don't touch it until something goes wrong.

The suggestion seems to be working though, so thanks

SteveGilham commented 2 years ago

I've also added back-off and retry logic to the task, re-using an existing wrapper used by another of the custom tasks. That will be present in the next release.