Example #1
0
        public static async Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests. " +
                                                "MSBuild.exe is located using state created as part of running build[cmd|sh] at the root of the repository. Run build /t:Prepare to set this up if this hasn't been done.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = "dotnet";
                processStartInfo.Arguments = $"msbuild {arguments}";
            }

            var processResult = await RunProcessCoreAsync(processStartInfo, timeout);

            return(new MSBuildResult(project, processResult.FileName, processResult.Arguments, processResult.ExitCode, processResult.Output));
        }
Example #2
0
        internal Task <MSBuildResult> DotnetMSBuild(
            string target,
            string args              = null,
            bool suppressRestore     = false,
            bool suppressTimeout     = false,
            bool suppressBuildServer = false,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            var timeout           = suppressTimeout ? (TimeSpan?)Timeout.InfiniteTimeSpan : null;
            var buildArgumentList = new List <string>();

            if (!suppressRestore)
            {
                buildArgumentList.Add("/restore");
            }

            if (!suppressBuildServer)
            {
                buildArgumentList.Add($"/p:_RazorBuildServerPipeName={BuildServer.PipeName}");
            }

            buildArgumentList.Add($"/t:{target} /p:Configuration={Configuration} {args}");
            var buildArguments = string.Join(" ", buildArgumentList);

            return(MSBuildProcessManager.RunProcessAsync(
                       Project,
                       buildArguments,
                       timeout,
                       msBuildProcessKind));
        }
        private async Task Build_SimpleMvc_CanBuildSuccessfully(MSBuildProcessKind msBuildProcessKind)
        {
            var result = await DotnetMSBuild(
                "Build",
                $"/p:RazorCompileOnBuild=true /p:UseRazorBuildServer=true /p:_RazorBuildServerPipeName={_pipeName} /p:_RazorForceBuildServer=true",
                msBuildProcessKind : msBuildProcessKind);

            Assert.BuildPassed(result);
            Assert.FileExists(result, OutputPath, "SimpleMvc.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.pdb");
            Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.pdb");
        }
        private async Task Build_ComponentsWorks(MSBuildProcessKind msBuildProcessKind)
        {
            var result = await DotnetMSBuild("Build", msBuildProcessKind : msBuildProcessKind);

            Assert.BuildPassed(result);
            Assert.FileExists(result, OutputPath, "MvcWithComponents.dll");
            Assert.FileExists(result, OutputPath, "MvcWithComponents.pdb");
            Assert.FileExists(result, OutputPath, "MvcWithComponents.Views.dll");
            Assert.FileExists(result, OutputPath, "MvcWithComponents.Views.pdb");

            Assert.AssemblyContainsType(result, Path.Combine(OutputPath, "MvcWithComponents.dll"), "MvcWithComponents.TestComponent");
            Assert.AssemblyContainsType(result, Path.Combine(OutputPath, "MvcWithComponents.dll"), "MvcWithComponents.Views.Shared.NavMenu");
        }
        internal Task <MSBuildResult> DotnetMSBuild(
            string target,
            string args                           = null,
            bool suppressTimeout                  = false,
            bool suppressBuildServer              = false,
            string buildServerPipeName            = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            var timeout = suppressTimeout ? (TimeSpan?)Timeout.InfiniteTimeSpan : null;

            var buildArgumentList = new List <string>
            {
                // Disable node-reuse. We don't want msbuild processes to stick around
                // once the test is completed.
                "/nr:false",

                // Always generate a bin log for debugging purposes
                "/bl",

                // Let the test app know it is running as part of a test.
                "/p:RunningAsTest=true",

                $"/p:MicrosoftNETCoreAppRuntimeVersion={BuildVariables.MicrosoftNETCoreAppRuntimeVersion}",
                $"/p:MicrosoftNetCompilersToolsetPackageVersion={BuildVariables.MicrosoftNetCompilersToolsetPackageVersion}",
                $"/p:RazorSdkDirectoryRoot={BuildVariables.RazorSdkDirectoryRoot}",
                $"/p:RepoRoot={BuildVariables.RepoRoot}",
            };

            if (!suppressBuildServer)
            {
                buildArgumentList.Add($@"/p:_RazorBuildServerPipeName=""{buildServerPipeName ?? BuildServer.PipeName}""");
            }

            if (!string.IsNullOrEmpty(target))
            {
                buildArgumentList.Add($"/t:{target}");
            }
            else
            {
                buildArgumentList.Add($"/t:Build");
            }

            buildArgumentList.Add($"/p:Configuration={Configuration} {args}");
            var buildArguments = string.Join(" ", buildArgumentList);

            return(MSBuildProcessManager.RunProcessAsync(
                       Project,
                       buildArguments,
                       timeout,
                       msBuildProcessKind));
        }
Example #6
0
        internal Task <MSBuildResult> DotnetMSBuild(
            string target,
            string args          = null,
            bool suppressRestore = false,
            bool suppressTimeout = false,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            var timeout         = suppressTimeout ? (TimeSpan?)Timeout.InfiniteTimeSpan : null;
            var restoreArgument = suppressRestore ? "" : "/restore";

            return(MSBuildProcessManager.RunProcessAsync(
                       Project,
                       $"{restoreArgument} /t:{target} /p:Configuration={Configuration} {args}",
                       timeout,
                       msBuildProcessKind));
        }
Example #7
0
        private async Task Build_SimpleMvc_CanBuildSuccessfully(MSBuildProcessKind msBuildProcessKind)
        {
            var result = await DotnetMSBuild("Build", "/p:RazorCompileOnBuild=true", msBuildProcessKind : msBuildProcessKind);

            Assert.BuildPassed(result);
            Assert.FileExists(result, OutputPath, "SimpleMvc.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.pdb");
            Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.pdb");

            if (RuntimeEnvironment.OperatingSystemPlatform != Platform.Darwin)
            {
                // GetFullPath on OSX doesn't work well in travis. We end up computing a different path than will
                // end up in the MSBuild logs.
                Assert.BuildOutputContainsLine(result, $"SimpleMvc -> {Path.Combine(Path.GetFullPath(Project.DirectoryPath), OutputPath, "SimpleMvc.PrecompiledViews.dll")}");
            }
        }
Example #8
0
        public static async Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet,
            string localPackageCache = null)
        {
            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (localPackageCache != null)
            {
                processStartInfo.Environment.Add("NUGET_PACKAGES", localPackageCache);
            }

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests. " +
                                                "MSBuild.exe is located using state created as part of running build[cmd|sh] at the root of the repository. Run build /t:Prepare to set this up if this hasn't been done.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = DotNetMuxer.MuxerPathOrDefault();
                processStartInfo.Arguments = $"msbuild {arguments}";

                // Suppresses the 'Welcome to .NET Core!' output that times out tests and causes locked file issues.
                // When using dotnet we're not guarunteed to run in an environment where the dotnet.exe has had its first run experience already invoked.
                processStartInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true";
            }

            var processResult = await RunProcessCoreAsync(processStartInfo, timeout);

            return(new MSBuildResult(project, processResult.FileName, processResult.Arguments, processResult.ExitCode, processResult.Output));
        }
        // This test is identical to the ones in BuildServerIntegrationTest except this one explicitly disables the Razor build server.
        private async Task Build_SimpleMvc_WithoutBuildServer_CanBuildSuccessfully(MSBuildProcessKind msBuildProcessKind)
        {
            var result = await DotnetMSBuild("Build",
                                             "/p:UseRazorBuildServer=false",
                                             suppressBuildServer : true,
                                             msBuildProcessKind : msBuildProcessKind);

            Assert.BuildPassed(result);
            Assert.FileExists(result, OutputPath, "SimpleMvc.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.pdb");
            Assert.FileExists(result, OutputPath, "SimpleMvc.Views.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.Views.pdb");

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // GetFullPath on OSX doesn't work well in travis. We end up computing a different path than will
                // end up in the MSBuild logs.
                Assert.BuildOutputContainsLine(result, $"SimpleMvc -> {Path.Combine(Path.GetFullPath(Project.DirectoryPath), OutputPath, "SimpleMvc.Views.dll")}");
            }
        }
        private async Task Build_SimpleMvc_CanBuildSuccessfully(MSBuildProcessKind msBuildProcessKind)
        {
            var result = await DotnetMSBuild("Build", "/p:RazorCompileOnBuild=true", msBuildProcessKind : msBuildProcessKind);

            Assert.BuildPassed(result);
            Assert.FileExists(result, OutputPath, "SimpleMvc.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.pdb");
            Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.pdb");

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // GetFullPath on OSX doesn't work well in travis. We end up computing a different path than will
                // end up in the MSBuild logs.
                Assert.BuildOutputContainsLine(result, $"SimpleMvc -> {Path.Combine(Path.GetFullPath(Project.DirectoryPath), OutputPath, "SimpleMvc.PrecompiledViews.dll")}");
            }

            result = await DotnetMSBuild("_IntrospectPreserveCompilationContext");

            Assert.BuildPassed(result);
            Assert.BuildOutputContainsLine(result, "PreserveCompilationContext: true");
        }
Example #11
0
        private async Task Build_ComponentsWorks(MSBuildProcessKind msBuildProcessKind)
        {
            var result = await DotnetMSBuild("Build", msBuildProcessKind : msBuildProcessKind);

            Assert.BuildPassed(result);
            Assert.FileExists(result, OutputPath, "MvcWithComponents.dll");
            Assert.FileExists(result, OutputPath, "MvcWithComponents.pdb");
            Assert.FileExists(result, OutputPath, "MvcWithComponents.Views.dll");
            Assert.FileExists(result, OutputPath, "MvcWithComponents.Views.pdb");

            Assert.AssemblyContainsType(result, Path.Combine(OutputPath, "MvcWithComponents.dll"), "MvcWithComponents.TestComponent");
            Assert.AssemblyContainsType(result, Path.Combine(OutputPath, "MvcWithComponents.dll"), "MvcWithComponents.Views.Shared.NavMenu");

            // This is a component file with a .cshtml extension. It should appear in the main assembly, but not in the views dll.
            Assert.AssemblyContainsType(result, Path.Combine(OutputPath, "MvcWithComponents.dll"), "MvcWithComponents.Components.Counter");
            Assert.AssemblyDoesNotContainType(result, Path.Combine(OutputPath, "MvcWithComponents.Views.dll"), "MvcWithComponents.Components.Counter");
            Assert.AssemblyDoesNotContainType(result, Path.Combine(OutputPath, "MvcWithComponents.Views.dll"), "AspNetCore.Components_Counter");

            // Verify a regular View appears in the views dll, but not in the main assembly.
            Assert.AssemblyDoesNotContainType(result, Path.Combine(OutputPath, "MvcWithComponents.dll"), "AspNetCore.Views.Home.Index");
            Assert.AssemblyDoesNotContainType(result, Path.Combine(OutputPath, "MvcWithComponents.dll"), "AspNetCore.Views_Home_Index");
            Assert.AssemblyContainsType(result, Path.Combine(OutputPath, "MvcWithComponents.Views.dll"), "AspNetCore.Views_Home_Index");
        }
Example #12
0
        private async Task Build_SimpleMvc_CanBuildSuccessfully(MSBuildProcessKind msBuildProcessKind)
        {
            var result = await DotnetMSBuild(
                "Build",
                "/p:_RazorForceBuildServer=true",
                msBuildProcessKind : msBuildProcessKind);

            Assert.BuildPassed(result);
            Assert.FileExists(result, OutputPath, "SimpleMvc.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.pdb");
            Assert.FileExists(result, OutputPath, "SimpleMvc.Views.dll");
            Assert.FileExists(result, OutputPath, "SimpleMvc.Views.pdb");

            // Verify RazorTagHelper works
            Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.TagHelpers.input.cache");
            Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.TagHelpers.output.cache");
            Assert.FileContains(
                result,
                Path.Combine(IntermediateOutputPath, "SimpleMvc.TagHelpers.output.cache"),
                @"""Name"":""SimpleMvc.SimpleTagHelper""");

            // Verify RazorGenerate works
            Assert.FileCountEquals(result, 8, RazorIntermediateOutputPath, "*.cs");
        }
Example #13
0
        public static Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            timeout = timeout ?? TimeSpan.FromSeconds(60);

            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = "dotnet";
                processStartInfo.Arguments = $"msbuild {arguments}";
            }

            var process = new Process()
            {
                StartInfo           = processStartInfo,
                EnableRaisingEvents = true,
            };

            var completionSource = new TaskCompletionSource <MSBuildResult>();
            var output           = new StringBuilder();

            process.Exited             += Process_Exited;
            process.ErrorDataReceived  += Process_ErrorDataReceived;
            process.OutputDataReceived += Process_OutputDataReceived;

            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

            var timeoutTask = Task.Delay(timeout.Value).ContinueWith((t) =>
            {
                // Don't timeout during debug sessions
                while (Debugger.IsAttached)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                }

                if (process.HasExited)
                {
                    // This will happen on success, the 'real' task has already completed so this value will
                    // never be visible.
                    return((MSBuildResult)null);
                }

                // This is a timeout.
                process.Kill();
                throw new TimeoutException($"command '${process.StartInfo.FileName} {process.StartInfo.Arguments}' timed out after {timeout}.");
            });

            return(Task.WhenAny <MSBuildResult>(completionSource.Task, timeoutTask).Unwrap());

            void Process_Exited(object sender, EventArgs e)
            {
                var result = new MSBuildResult(project, process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, output.ToString());

                completionSource.SetResult(result);
            }

            void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
            {
                output.AppendLine(e.Data);
            }

            void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
            {
                output.AppendLine(e.Data);
            }
        }
        public static async Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests. " +
                                                "MSBuild.exe is located using state created as part of running build[cmd|sh] at the root of the repository. Run build /t:Prepare to set this up if this hasn't been done.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = DotNetMuxer.MuxerPathOrDefault();
                processStartInfo.Arguments = $"msbuild {arguments}";

                // Suppresses the 'Welcome to .NET Core!' output that times out tests and causes locked file issues.
                // When using dotnet we're not guarunteed to run in an environment where the dotnet.exe has had its first run experience already invoked.
                processStartInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true";
            }

            ProcessResult processResult;

            try
            {
                processResult = await RunProcessCoreAsync(processStartInfo, timeout);
            }
            catch (TimeoutException ex)
            {
                // Copy the binlog to the artifacts directory if executing MSBuild throws.
                // This would help diagnosing failures on the CI.
                var binaryLogFile = Path.Combine(project.ProjectFilePath, "msbuild.binlog");

                var artifactsLogDir = Assembly.GetExecutingAssembly()
                                      .GetCustomAttributes <AssemblyMetadataAttribute>()
                                      .FirstOrDefault(ama => ama.Key == "ArtifactsLogDir")?.Value;

                if (!string.IsNullOrEmpty(artifactsLogDir) && File.Exists(binaryLogFile))
                {
                    var targetPath = Path.Combine(artifactsLogDir, Path.GetFileNameWithoutExtension(project.ProjectFilePath) + "." + Path.GetRandomFileName() + ".binlog");
                    File.Copy(binaryLogFile, targetPath);

                    throw new TimeoutException(ex.Message + $"{Environment.NewLine}Captured binlog at {targetPath}");
                }

                throw;
            }

            return(new MSBuildResult(project, processResult.FileName, processResult.Arguments, processResult.ExitCode, processResult.Output));
        }
        public static Task <MSBuildResult> RunProcessAsync(
            ProjectDirectory project,
            string arguments,
            TimeSpan?timeout = null,
            MSBuildProcessKind msBuildProcessKind = MSBuildProcessKind.Dotnet)
        {
            timeout = timeout ?? TimeSpan.FromSeconds(60);

            var processStartInfo = new ProcessStartInfo()
            {
                WorkingDirectory       = project.DirectoryPath,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
            };

            if (msBuildProcessKind == MSBuildProcessKind.Desktop)
            {
                if (string.IsNullOrEmpty(BuildVariables.MSBuildPath))
                {
                    throw new ArgumentException("Unable to locate MSBuild.exe to run desktop tests. " +
                                                "MSBuild.exe is located using state created as part of running build[cmd|sh] at the root of the repository. Run build /t:Prepare to set this up if this hasn't been done.");
                }

                processStartInfo.FileName  = BuildVariables.MSBuildPath;
                processStartInfo.Arguments = arguments;
            }
            else
            {
                processStartInfo.FileName  = "dotnet";
                processStartInfo.Arguments = $"msbuild {arguments}";
            }

            var process = new Process()
            {
                StartInfo           = processStartInfo,
                EnableRaisingEvents = true,
            };

            var output     = new StringBuilder();
            var outputLock = new object();

            process.ErrorDataReceived  += Process_ErrorDataReceived;
            process.OutputDataReceived += Process_OutputDataReceived;

            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

            var timeoutTask = Task.Delay(timeout.Value).ContinueWith((t) =>
            {
                // Don't timeout during debug sessions
                while (Debugger.IsAttached)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                }

                if (process.HasExited)
                {
                    // This will happen on success, the 'real' task has already completed so this value will
                    // never be visible.
                    return((MSBuildResult)null);
                }

                // This is a timeout.
                process.Kill();
                throw new TimeoutException($"command '${process.StartInfo.FileName} {process.StartInfo.Arguments}' timed out after {timeout}.");
            });

            var waitTask = Task.Run(() =>
            {
                // We need to use two WaitForExit calls to ensure that all of the output/events are processed. Previously
                // this code used Process.Exited, which could result in us missing some output due to the ordering of
                // events.
                //
                // See the remarks here: https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx
                if (!process.WaitForExit(Int32.MaxValue))
                {
                    // unreachable - the timeoutTask will kill the process before this happens.
                    throw new TimeoutException();
                }

                process.WaitForExit();

                string outputString;
                lock (outputLock)
                {
                    outputString = output.ToString();
                }

                var result = new MSBuildResult(project, process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, outputString);
                return(result);
            });

            return(Task.WhenAny <MSBuildResult>(waitTask, timeoutTask).Unwrap());

            void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
            {
                lock (outputLock)
                {
                    output.AppendLine(e.Data);
                }
            }

            void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
            {
                lock (outputLock)
                {
                    output.AppendLine(e.Data);
                }
            }
        }
        private async Task Build_ProjectWithDependencyThatReferencesMvc_AddsAttribute(MSBuildProcessKind msBuildProcessKind)
        {
            var result = await DotnetMSBuild("Build", msBuildProcessKind : msBuildProcessKind);

            Assert.BuildPassed(result);

            Assert.FileExists(result, IntermediateOutputPath, "AppWithP2PReference.MvcApplicationPartsAssemblyInfo.cs");
            Assert.FileContains(result, Path.Combine(IntermediateOutputPath, "AppWithP2PReference.MvcApplicationPartsAssemblyInfo.cs"), "[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute(\"ClassLibrary\")]");
            Assert.AssemblyHasAttribute(result, Path.Combine(OutputPath, "AppWithP2PReference.dll"), "Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute");
        }