<commit_before>﻿// Copyright (c) Microsoft Open Technologies, Inc.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CompilerServer;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.Win32;
using Moq;
using Roslyn.Test.Utilities;
using Xunit;
using System.IO.Pipes;

namespace Microsoft.CodeAnalysis.BuildTasks.UnitTests
{
    public class CompilerServerApiTest : TestBase
    {
        private sealed class TestableClientConnection : IClientConnection
        {
            internal string LoggingIdentifier = string.Empty;
            internal Task<BuildRequest> ReadBuildRequestTask = TaskFromException<BuildRequest>(new Exception());
            internal Task WriteBuildResponseTask = TaskFromException(new Exception());
            internal Task MonitorTask = TaskFromException(new Exception());
            internal Action CloseAction = delegate { };

            string IClientConnection.LoggingIdentifier
            {
                get { return LoggingIdentifier; }
            }

            Task<BuildRequest> IClientConnection.ReadBuildRequest(CancellationToken cancellationToken)
            {
                return ReadBuildRequestTask;
            }

            Task IClientConnection.WriteBuildResponse(BuildResponse response, CancellationToken cancellationToken)
            {
                return WriteBuildResponseTask;
            }

            Task IClientConnection.CreateMonitorDisconnectTask(CancellationToken cancellationToken)
            {
                return MonitorTask;
            }

            void IClientConnection.Close()
            {
                CloseAction();
            }
        }

        private sealed class TestableDiagnosticListener : IDiagnosticListener
        {
            public int ProcessedCount = 0;
            public DateTime? LastProcessedTime;
            public TimeSpan? KeepAlive;

            public void ConnectionProcessed(int count)
            {
                ProcessedCount += count;
                LastProcessedTime = DateTime.Now;
            }

            public void UpdateKeepAlive(TimeSpan timeSpan)
            {
                KeepAlive = timeSpan;
            }
        }

        private static readonly BuildRequest EmptyCSharpBuildRequest = new BuildRequest(
            1,
            BuildProtocolConstants.RequestLanguage.CSharpCompile,
            ImmutableArray<BuildRequest.Argument>.Empty);

        private static readonly BuildResponse EmptyBuildResponse = new CompletedBuildResponse(
            returnCode: 0,
            utf8output: false,
            output: string.Empty,
            errorOutput: string.Empty);

        private const string HelloWorldSourceText = @"
using System;
class Hello
{
    static void Main()
    {
        Console.WriteLine(""Hello, world.""); 
    }
}";

        private static Task TaskFromException(Exception e)
        {
            return TaskFromException<bool>(e);
        }

        private static Task<T> TaskFromException<T>(Exception e)
        {
            var source = new TaskCompletionSource<T>();
            source.SetException(e);
            return source.Task;
        }

        private async Task<BuildRequest> CreateBuildRequest(string sourceText, TimeSpan? keepAlive = null)
        {
            var directory = Temp.CreateDirectory();
            var file = directory.CreateFile("temp.cs");
            await file.WriteAllTextAsync(sourceText).ConfigureAwait(false);

            var builder = ImmutableArray.CreateBuilder<BuildRequest.Argument>();
            if (keepAlive.HasValue)
            {
                builder.Add(new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.KeepAlive, argumentIndex: 0, value: keepAlive.Value.TotalSeconds.ToString()));
            }

            builder.Add(new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CurrentDirectory, argumentIndex: 0, value: directory.Path));
            builder.Add(new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CommandLineArgument, argumentIndex: 0, value: file.Path));

            return new BuildRequest(
                BuildProtocolConstants.ProtocolVersion,
                BuildProtocolConstants.RequestLanguage.CSharpCompile,
                builder.ToImmutable());
        }

        /// <summary>
        /// Run a C# compilation against the given source text using the provided named pipe name.
        /// </summary>
        private async Task<BuildResponse> RunCSharpCompile(string pipeName, string sourceText, TimeSpan? keepAlive = null)
        {
            using (var namedPipe = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut))
            {
                var buildRequest = await CreateBuildRequest(sourceText, keepAlive).ConfigureAwait(false);
                namedPipe.Connect((int)TimeSpan.FromSeconds(5).TotalMilliseconds);
                await buildRequest.WriteAsync(namedPipe, default(CancellationToken)).ConfigureAwait(false);
                return await BuildResponse.ReadAsync(namedPipe, default(CancellationToken)).ConfigureAwait(false);
            }
        }

        /// <summary>
        /// This returns an <see cref="IRequestHandler"/> that always returns <see cref="CompletedBuildResponse"/> without
        /// doing any work.
        /// </summary>
        private static Mock<IRequestHandler> CreateNopRequestHandler()
        {
            var requestHandler = new Mock<IRequestHandler>();
            requestHandler
                .Setup(x => x.HandleRequest(It.IsAny<BuildRequest>(), It.IsAny<CancellationToken>()))
                .Returns(new CompletedBuildResponse(0, utf8output: false, output: string.Empty, errorOutput: string.Empty));
            return requestHandler;
        }
<commit_msg>Remove arbitrary timeout in unit test support. This was causing flakiness during builds if the machine is loaded. (changeset 1397093)<commit_after>﻿// Copyright (c) Microsoft Open Technologies, Inc.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CompilerServer;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.Win32;
using Moq;
using Roslyn.Test.Utilities;
using Xunit;
using System.IO.Pipes;

namespace Microsoft.CodeAnalysis.BuildTasks.UnitTests
{
    public class CompilerServerApiTest : TestBase
    {
        private sealed class TestableClientConnection : IClientConnection
        {
            internal string LoggingIdentifier = string.Empty;
            internal Task<BuildRequest> ReadBuildRequestTask = TaskFromException<BuildRequest>(new Exception());
            internal Task WriteBuildResponseTask = TaskFromException(new Exception());
            internal Task MonitorTask = TaskFromException(new Exception());
            internal Action CloseAction = delegate { };

            string IClientConnection.LoggingIdentifier
            {
                get { return LoggingIdentifier; }
            }

            Task<BuildRequest> IClientConnection.ReadBuildRequest(CancellationToken cancellationToken)
            {
                return ReadBuildRequestTask;
            }

            Task IClientConnection.WriteBuildResponse(BuildResponse response, CancellationToken cancellationToken)
            {
                return WriteBuildResponseTask;
            }

            Task IClientConnection.CreateMonitorDisconnectTask(CancellationToken cancellationToken)
            {
                return MonitorTask;
            }

            void IClientConnection.Close()
            {
                CloseAction();
            }
        }

        private sealed class TestableDiagnosticListener : IDiagnosticListener
        {
            public int ProcessedCount = 0;
            public DateTime? LastProcessedTime;
            public TimeSpan? KeepAlive;

            public void ConnectionProcessed(int count)
            {
                ProcessedCount += count;
                LastProcessedTime = DateTime.Now;
            }

            public void UpdateKeepAlive(TimeSpan timeSpan)
            {
                KeepAlive = timeSpan;
            }
        }

        private static readonly BuildRequest EmptyCSharpBuildRequest = new BuildRequest(
            1,
            BuildProtocolConstants.RequestLanguage.CSharpCompile,
            ImmutableArray<BuildRequest.Argument>.Empty);

        private static readonly BuildResponse EmptyBuildResponse = new CompletedBuildResponse(
            returnCode: 0,
            utf8output: false,
            output: string.Empty,
            errorOutput: string.Empty);

        private const string HelloWorldSourceText = @"
using System;
class Hello
{
    static void Main()
    {
        Console.WriteLine(""Hello, world.""); 
    }
}";

        private static Task TaskFromException(Exception e)
        {
            return TaskFromException<bool>(e);
        }

        private static Task<T> TaskFromException<T>(Exception e)
        {
            var source = new TaskCompletionSource<T>();
            source.SetException(e);
            return source.Task;
        }

        private async Task<BuildRequest> CreateBuildRequest(string sourceText, TimeSpan? keepAlive = null)
        {
            var directory = Temp.CreateDirectory();
            var file = directory.CreateFile("temp.cs");
            await file.WriteAllTextAsync(sourceText).ConfigureAwait(false);

            var builder = ImmutableArray.CreateBuilder<BuildRequest.Argument>();
            if (keepAlive.HasValue)
            {
                builder.Add(new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.KeepAlive, argumentIndex: 0, value: keepAlive.Value.TotalSeconds.ToString()));
            }

            builder.Add(new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CurrentDirectory, argumentIndex: 0, value: directory.Path));
            builder.Add(new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CommandLineArgument, argumentIndex: 0, value: file.Path));

            return new BuildRequest(
                BuildProtocolConstants.ProtocolVersion,
                BuildProtocolConstants.RequestLanguage.CSharpCompile,
                builder.ToImmutable());
        }

        /// <summary>
        /// Run a C# compilation against the given source text using the provided named pipe name.
        /// </summary>
        private async Task<BuildResponse> RunCSharpCompile(string pipeName, string sourceText, TimeSpan? keepAlive = null)
        {
            using (var namedPipe = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut))
            {
                var buildRequest = await CreateBuildRequest(sourceText, keepAlive).ConfigureAwait(false);
                namedPipe.Connect(Timeout.Infinite);
                await buildRequest.WriteAsync(namedPipe, default(CancellationToken)).ConfigureAwait(false);
                return await BuildResponse.ReadAsync(namedPipe, default(CancellationToken)).ConfigureAwait(false);
            }
        }

        /// <summary>
        /// This returns an <see cref="IRequestHandler"/> that always returns <see cref="CompletedBuildResponse"/> without
        /// doing any work.
        /// </summary>
        private static Mock<IRequestHandler> CreateNopRequestHandler()
        {
            var requestHandler = new Mock<IRequestHandler>();
            requestHandler
                .Setup(x => x.HandleRequest(It.IsAny<BuildRequest>(), It.IsAny<CancellationToken>()))
                .Returns(new CompletedBuildResponse(0, utf8output: false, output: string.Empty, errorOutput: string.Empty));
            return requestHandler;
        }

{'fraction_non_alphanumeric': 0.07826157332470055, 'fraction_numerical': 0.002751699579151829, 'mean_word_length': 2.4163671551009123, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5105864', 'n_tokens_mistral': 2933, 'n_tokens_neox': 2858, 'n_words': 693}