File: Assert\ArtifactUploadUtil.cs
Web Access
Project: src\src\Compilers\Test\Core\Microsoft.CodeAnalysis.Test.Utilities.csproj (Microsoft.CodeAnalysis.Test.Utilities)
// 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.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit.Abstractions;
 
namespace Roslyn.Test.Utilities
{
    /// <summary>
    /// There are test failures that are virtually impossible to debug without artifacts generated during
    /// the test execution. This utility is helpful at getting those artifacts attached to AzDO / Helix 
    /// when executed in our CI process. 
    /// 
    /// The utilility works by collecting a set of file paths to artifacts. If the test succeeds it should 
    /// call the <see cref="SetSucceeded"/> method. Otherwise if the test fails an exception is generated,
    /// the call is skipped and in <see cref="Dispose"/> we prepare the artifacts for upload.
    /// </summary>
    public sealed class ArtifactUploadUtil : IDisposable
    {
        private readonly ITestOutputHelper _testOutputHelper;
        private readonly string _baseDirectoryName;
        private readonly List<string> _filePaths = new List<string>();
        private readonly List<string> _directoryPaths = new List<string>();
        private bool _success = false;
 
        public ArtifactUploadUtil(ITestOutputHelper testOutputHelper, string? baseDirectoryName = null)
        {
            _testOutputHelper = testOutputHelper;
            _baseDirectoryName = baseDirectoryName ?? Guid.NewGuid().ToString();
        }
 
        public void AddFile(string filePath)
        {
            _filePaths.Add(filePath);
        }
 
        public void AddDirectory(string directory)
        {
            _directoryPaths.Add(directory);
        }
 
        public void SetSucceeded()
        {
            _success = true;
        }
 
        public void Dispose()
        {
            if (_success)
            {
                return;
            }
 
            var uploadDir = Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT");
            if (string.IsNullOrEmpty(uploadDir))
            {
                _testOutputHelper.WriteLine("Skipping artifact upload as not running in helix");
                _testOutputHelper.WriteLine("Files:");
                foreach (var filePath in _filePaths)
                {
                    _testOutputHelper.WriteLine(filePath);
                }
 
                _testOutputHelper.WriteLine("Directories:");
                foreach (var directory in _directoryPaths)
                {
                    _testOutputHelper.WriteLine(directory);
                }
            }
            else
            {
                uploadDir = Path.Combine(uploadDir, _baseDirectoryName);
                Directory.CreateDirectory(uploadDir);
                _testOutputHelper.WriteLine($"Uploading artifacts by copying to {uploadDir}");
                foreach (var filePath in _filePaths)
                {
                    _testOutputHelper.WriteLine($"Copying file {filePath}");
                    var fileName = Path.GetFileName(filePath);
                    File.Copy(filePath, Path.Combine(uploadDir, fileName));
                }
 
                foreach (var directory in _directoryPaths)
                {
                    _testOutputHelper.WriteLine($"Copying directory {directory}");
                    var destDirectory = Path.Combine(uploadDir, Path.GetFileName(directory));
                    Directory.CreateDirectory(destDirectory);
                    foreach (var filePath in Directory.EnumerateFiles(directory, searchPattern: "*.*", SearchOption.AllDirectories))
                    {
                        _testOutputHelper.WriteLine($"\tCopying file {filePath}");
 
                        var destFilePath = filePath.Substring(directory.Length);
                        if (destFilePath.Length > 0 && destFilePath[0] == Path.DirectorySeparatorChar)
                        {
                            destFilePath = destFilePath.Substring(1);
                        }
 
                        destFilePath = Path.Combine(destDirectory, destFilePath);
                        Directory.CreateDirectory(Path.GetDirectoryName(destFilePath)!);
                        File.Copy(filePath, destFilePath);
                    }
                }
            }
        }
    }
}