예제 #1
0
        public async Task WhenWorkIsAddedAgainWhenPreviousIsAnalysing_ThenDontWaitAnotherOneToGetReady()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground);

            now = PassOverThrotlingPeriod(now);

            var work        = queue.TakeWork(AnalyzerWorkType.Foreground);
            var waitingCall = Task.Run(async() => await queue.WaitForegroundWorkComplete());
            await Task.Delay(50);

            // User updates code -> document is queued again during period when theres already api call waiting
            // to continue.
            queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground);

            // First iteration of work is done.
            queue.WorkComplete(AnalyzerWorkType.Foreground);

            // Waiting call continues because its iteration of work is done, even when theres next
            // already waiting.
            await waitingCall;

            Assert.True(waitingCall.IsCompleted);
        }
        public async Task WhenWorkIsAddedAgainWhenPreviousIsAnalysing_ThenDontWaitAnotherOneToGetReady()
        {
            var now           = DateTime.UtcNow;
            var loggerFactory = new LoggerFactory();
            var queue         = new AnalyzerWorkQueue(loggerFactory, utcNow: () => now);
            var document      = CreateTestDocumentId();

            queue.PutWork(document);

            now = PassOverThrotlingPeriod(now);

            var work        = queue.TakeWork();
            var waitingCall = Task.Run(async() => await queue.WaitForResultsAsync(work));
            await Task.Delay(50);

            // User updates code -> document is queued again during period when theres already api call waiting
            // to continue.
            queue.PutWork(document);

            // First iteration of work is done.
            queue.MarkWorkAsCompleteForDocumentId(document);

            // Waiting call continues because it's iteration of work is done, even when theres next
            // already waiting.
            await waitingCall;

            Assert.True(waitingCall.IsCompleted);
            Assert.Empty(loggerFactory.Logger.RecordedMessages);
        }
예제 #3
0
        public async Task WhenMultipleThreadsAreConsumingAnalyzerWorkerQueueItWorksAsExpected()
        {
            var now = DateTime.UtcNow;

            var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 1000);

            var parallelQueues =
                Enumerable.Range(0, 10)
                .Select(_ =>
                        Task.Run(() =>
            {
                var document = CreateTestDocumentId();

                queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground);

                now = PassOverThrotlingPeriod(now);

                var work = queue.TakeWork(AnalyzerWorkType.Foreground);

                var pendingTask = queue.WaitForegroundWorkComplete();

                queue.WaitForegroundWorkComplete();

                pendingTask.Wait(TimeSpan.FromMilliseconds(300));
            }))
                .ToArray();

            await Task.WhenAll(parallelQueues);

            Assert.Empty(queue.TakeWork(AnalyzerWorkType.Foreground));
        }
        public CSharpDiagnosticWorkerWithAnalyzers(
            OmniSharpWorkspace workspace,
            [ImportMany] IEnumerable <ICodeActionProvider> providers,
            ILoggerFactory loggerFactory,
            DiagnosticEventForwarder forwarder,
            OmniSharpOptions options)
        {
            _logger    = loggerFactory.CreateLogger <CSharpDiagnosticWorkerWithAnalyzers>();
            _providers = providers.ToImmutableArray();
            _workQueue = new AnalyzerWorkQueue(loggerFactory, timeoutForPendingWorkMs: options.RoslynExtensionsOptions.DocumentAnalysisTimeoutMs * 3);

            _forwarder = forwarder;
            _options   = options;
            _workspace = workspace;

            _workspaceAnalyzerOptionsConstructor = Assembly
                                                   .Load("Microsoft.CodeAnalysis.Features")
                                                   .GetType("Microsoft.CodeAnalysis.Diagnostics.WorkspaceAnalyzerOptions")
                                                   .GetConstructor(new Type[] { typeof(AnalyzerOptions), typeof(Solution) })
                                                   ?? throw new InvalidOperationException("Could not resolve 'Microsoft.CodeAnalysis.Diagnostics.WorkspaceAnalyzerOptions' for IDE analyzers.");

            _workspace.WorkspaceChanged += OnWorkspaceChanged;
            _workspace.OnInitialized    += OnWorkspaceInitialized;

            Task.Factory.StartNew(() => Worker(AnalyzerWorkType.Foreground), TaskCreationOptions.LongRunning);
            Task.Factory.StartNew(() => Worker(AnalyzerWorkType.Background), TaskCreationOptions.LongRunning);

            OnWorkspaceInitialized(_workspace.Initialized);
        }
예제 #5
0
        public void WhenItemsAreAddedButThrotlingIsntOverNoWorkShouldBeReturned(AnalyzerWorkType workType)
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.PutWork(new[] { document }, workType);
            Assert.Empty(queue.TakeWork(workType));
        }
예제 #6
0
        public void WhenBackgroundWorkIsAdded_DontWaitIt()
        {
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.PutWork(new[] { document }, AnalyzerWorkType.Background);

            Assert.True(queue.WaitForegroundWorkComplete().IsCompleted);
        }
        public void WhenItemsAreAddedButThrotlingIsntOverNoWorkShouldBeReturned()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now);
            var document = CreateTestDocumentId();

            queue.PutWork(document);
            Assert.Empty(queue.TakeWork());
        }
예제 #8
0
        public void WhenFileIsntAtBackgroundQueueAndTriedToBePromoted_ThenDontDoNothing()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.TryPromote(document);

            now = PassOverThrotlingPeriod(now);

            Assert.Empty(queue.TakeWork(AnalyzerWorkType.Foreground));
        }
        public void WhenFileIsntAtBackgroundQueueAndTriedToBeQueued_ThenQueue()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new TestLoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.QueueDocumentForeground(document);

            now = PassOverThrotlingPeriod(now);

            Assert.Equal(document, queue.TakeWork(AnalyzerWorkType.Foreground).Single());
        }
예제 #10
0
        public void WhenSingleFileIsPromoted_ThenPromoteItFromBackgroundQueueToForeground()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.PutWork(new[] { document }, AnalyzerWorkType.Background);

            queue.TryPromote(document);

            now = PassOverThrotlingPeriod(now);

            Assert.NotEmpty(queue.TakeWork(AnalyzerWorkType.Foreground));
        }
        public void WhenWorksIsAddedToQueueThenTheyWillBeReturned()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now);
            var document = CreateTestDocumentId();

            queue.PutWork(document);

            now = PassOverThrotlingPeriod(now);
            var work = queue.TakeWork();

            Assert.Contains(document, work);
            Assert.Empty(queue.TakeWork());
        }
예제 #12
0
        public void WhenWorksIsAddedToQueueThenTheyWillBeReturned(AnalyzerWorkType workType)
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.PutWork(new[] { document }, workType);

            now = PassOverThrotlingPeriod(now);
            var work = queue.TakeWork(workType);

            Assert.Contains(document, work);
            Assert.Empty(queue.TakeWork(workType));
        }
        public void WhenSameItemIsAddedMultipleTimesInRowThenThrottleItemAsOne()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now);
            var document = CreateTestDocumentId();

            queue.PutWork(document);
            queue.PutWork(document);
            queue.PutWork(document);

            Assert.Empty(queue.TakeWork());

            now = PassOverThrotlingPeriod(now);

            Assert.Contains(document, queue.TakeWork());
            Assert.Empty(queue.TakeWork());
        }
예제 #14
0
        public void WhenSameItemIsAddedMultipleTimesInRowThenThrottleItemAsOne(AnalyzerWorkType workType)
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.PutWork(new[] { document }, workType);
            queue.PutWork(new[] { document }, workType);
            queue.PutWork(new[] { document }, workType);

            Assert.Empty(queue.TakeWork(workType));

            now = PassOverThrotlingPeriod(now);

            Assert.Contains(document, queue.TakeWork(workType));
            Assert.Empty(queue.TakeWork(workType));
        }
예제 #15
0
        public void WhenForegroundWorkIsUnderAnalysisOutFromQueueThenWaitUntilNextIterationOfItIsReady()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 500);
            var document = CreateTestDocumentId();

            queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground);

            now = PassOverThrotlingPeriod(now);

            var work = queue.TakeWork(AnalyzerWorkType.Foreground);

            var pendingTask = queue.WaitForegroundWorkComplete();

            pendingTask.Wait(TimeSpan.FromMilliseconds(50));

            Assert.False(pendingTask.IsCompleted);
            queue.WorkComplete(AnalyzerWorkType.Foreground);
            pendingTask.Wait(TimeSpan.FromMilliseconds(50));
            Assert.True(pendingTask.IsCompleted);
        }
        public void WhenFileIsProcessingInBackgroundQueue_ThenPromoteItAsForeground()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new TestLoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000);
            var document = CreateTestDocumentId();

            queue.PutWork(new[] { document }, AnalyzerWorkType.Background);

            now = PassOverThrotlingPeriod(now);

            var activeWork = queue.TakeWork(AnalyzerWorkType.Background);

            queue.QueueDocumentForeground(document);

            now = PassOverThrotlingPeriod(now);

            var foregroundWork = queue.TakeWork(AnalyzerWorkType.Foreground);

            Assert.NotEmpty(foregroundWork);
            Assert.NotEmpty(activeWork);
        }
예제 #17
0
        public void WhenWorkIsWaitedButTimeoutForWaitIsExceededAllowContinue()
        {
            var now           = DateTime.UtcNow;
            var loggerFactory = new LoggerFactory();
            var queue         = new AnalyzerWorkQueue(loggerFactory, utcNow: () => now, timeoutForPendingWorkMs: 20);
            var document      = CreateTestDocumentId();

            queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground);

            now = PassOverThrotlingPeriod(now);
            var work = queue.TakeWork(AnalyzerWorkType.Foreground);

            var pendingTask = queue.WaitForegroundWorkComplete();
            var cts         = new CancellationTokenSource();

            cts.CancelAfter(TimeSpan.FromSeconds(5));
            pendingTask.Wait(cts.Token);

            Assert.True(pendingTask.IsCompleted);
            Assert.Contains("Timeout before work got ready", loggerFactory.Logger.RecordedMessages.Single());
        }
        public void WhenWorkIsAddedThenWaitNextIterationOfItReady()
        {
            var now      = DateTime.UtcNow;
            var queue    = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 500);
            var document = CreateTestDocumentId();

            queue.PutWork(document);

            var pendingTask = queue.WaitForResultsAsync(new [] { document }.ToImmutableArray());

            pendingTask.Wait(TimeSpan.FromMilliseconds(50));

            Assert.False(pendingTask.IsCompleted);

            now = PassOverThrotlingPeriod(now);

            var work = queue.TakeWork();

            queue.MarkWorkAsCompleteForDocumentId(document);
            pendingTask.Wait(TimeSpan.FromMilliseconds(50));
            Assert.True(pendingTask.IsCompleted);
        }