Example #1
0
        public async Task EgressCancelTest()
        {
            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                DiagnosticPortConnectionMode.Connect,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(appRunner, apiClient) =>
            {
                int processId = await appRunner.ProcessIdTask;

                OperationResponse response = await apiClient.EgressTraceAsync(processId, durationSeconds: -1, FileProviderName);
                Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);

                OperationStatusResponse operationResult = await apiClient.GetOperationStatus(response.OperationUri);
                Assert.Equal(HttpStatusCode.OK, operationResult.StatusCode);
                Assert.True(operationResult.OperationStatus.Status == OperationState.Running);

                HttpStatusCode deleteStatus = await apiClient.CancelEgressOperation(response.OperationUri);
                Assert.Equal(HttpStatusCode.OK, deleteStatus);

                operationResult = await apiClient.GetOperationStatus(response.OperationUri);
                Assert.Equal(HttpStatusCode.OK, operationResult.StatusCode);
                Assert.Equal(OperationState.Cancelled, operationResult.OperationStatus.Status);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                configureTool : (toolRunner) =>
            {
                toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempDirectory.FullName));
            });
        }
Example #2
0
        public async Task DisableHttpEgressTest()
        {
            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                DiagnosticPortConnectionMode.Connect,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(appRunner, appClient) =>
            {
                int processId = await appRunner.ProcessIdTask;

                ProcessInfo processInfo = await appClient.GetProcessAsync(processId);
                Assert.NotNull(processInfo);

                // Dump Error Check
                ValidationProblemDetailsException validationProblemDetailsExceptionDumps = await Assert.ThrowsAsync <ValidationProblemDetailsException>(
                    () => appClient.CaptureDumpAsync(processId, DumpType.Mini));
                Assert.Equal(HttpStatusCode.BadRequest, validationProblemDetailsExceptionDumps.StatusCode);
                Assert.Equal(StatusCodes.Status400BadRequest, validationProblemDetailsExceptionDumps.Details.Status);
                Assert.Equal(DisabledHTTPEgressErrorMessage, validationProblemDetailsExceptionDumps.Message);

                // Logs Error Check
                ValidationProblemDetailsException validationProblemDetailsExceptionLogs = await Assert.ThrowsAsync <ValidationProblemDetailsException>(
                    () => appClient.CaptureLogsAsync(processId, CommonTestTimeouts.LogsDuration, LogLevel.None, LogFormat.NewlineDelimitedJson));
                Assert.Equal(HttpStatusCode.BadRequest, validationProblemDetailsExceptionLogs.StatusCode);
                Assert.Equal(StatusCodes.Status400BadRequest, validationProblemDetailsExceptionLogs.Details.Status);
                Assert.Equal(DisabledHTTPEgressErrorMessage, validationProblemDetailsExceptionLogs.Message);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                disableHttpEgress : true);
        }
Example #3
0
        public async Task ConcurrencyLimitTest()
        {
            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                DiagnosticPortConnectionMode.Connect,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(appRunner, apiClient) =>
            {
                int processId = await appRunner.ProcessIdTask;

                OperationResponse response1 = await EgressTraceWithDelay(apiClient, processId);
                OperationResponse response2 = await EgressTraceWithDelay(apiClient, processId);
                OperationResponse response3 = await EgressTraceWithDelay(apiClient, processId);

                ValidationProblemDetailsException ex = await Assert.ThrowsAsync <ValidationProblemDetailsException>(() => EgressTraceWithDelay(apiClient, processId));
                Assert.Equal(HttpStatusCode.TooManyRequests, ex.StatusCode);
                Assert.Equal((int)HttpStatusCode.TooManyRequests, ex.Details.Status.GetValueOrDefault());

                await CancelEgressOperation(apiClient, response1);
                await CancelEgressOperation(apiClient, response2);

                OperationResponse response4 = await EgressTraceWithDelay(apiClient, processId, delay: false);

                await CancelEgressOperation(apiClient, response3);
                await CancelEgressOperation(apiClient, response4);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                configureTool : (toolRunner) =>
            {
                toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempDirectory.FullName));
            });
        }
        public async Task CollectionRule_StartupTriggerTest(DiagnosticPortConnectionMode mode)
        {
            using TemporaryDirectory tempDirectory = new(_outputHelper);
            string ExpectedFilePath    = Path.Combine(tempDirectory.FullName, "file.txt");
            string ExpectedFileContent = Guid.NewGuid().ToString("N");

            Task ruleCompletedTask = null;

            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                mode,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(runner, client) =>
            {
                await ruleCompletedTask;

                Assert.True(File.Exists(ExpectedFilePath));
                Assert.Equal(ExpectedFileContent, File.ReadAllText(ExpectedFilePath));

                await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                configureTool : runner =>
            {
                runner.ConfigurationFromEnvironment.CreateCollectionRule(DefaultRuleName)
                .SetStartupTrigger()
                .AddExecuteActionAppAction("TextFileOutput", ExpectedFilePath, ExpectedFileContent);

                ruleCompletedTask = runner.WaitForCollectionRuleCompleteAsync(DefaultRuleName);
            });
        }
Example #5
0
        public Task InfoEndpointValidationTest(DiagnosticPortConnectionMode mode)
        {
            return(ScenarioRunner.SingleTarget(
                       _outputHelper,
                       _httpClientFactory,
                       mode,
                       TestAppScenarios.AsyncWait.Name,
                       appValidate: async(runner, client) =>
            {
                // GET /info
                DotnetMonitorInfo info = await client.GetInfoAsync();

                Assert.NotNull(info.Version);     // Not sure of how to get Dotnet Monitor version from within tests...
                Assert.True(Version.TryParse(info.RuntimeVersion, out Version runtimeVersion), "Unable to parse version from RuntimeVersion property.");

                Version currentAspNetVersion = TargetFrameworkMoniker.Net60.GetAspNetCoreFrameworkVersion();
                Assert.Equal(currentAspNetVersion.Major, runtimeVersion.Major);
                Assert.Equal(currentAspNetVersion.Minor, runtimeVersion.Minor);
                Assert.Equal(currentAspNetVersion.Revision, runtimeVersion.Revision);

                Assert.Equal(mode, info.DiagnosticPortMode);

                if (mode == DiagnosticPortConnectionMode.Connect)
                {
                    Assert.Null(info.DiagnosticPortName);
                }
                else if (mode == DiagnosticPortConnectionMode.Listen)
                {
                    Assert.Equal(runner.DiagnosticPortPath, info.DiagnosticPortName);
                }

                await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            }));
        }
Example #6
0
        public async Task EgressListTest()
        {
            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                DiagnosticPortConnectionMode.Connect,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(appRunner, apiClient) =>
            {
                int processId = await appRunner.ProcessIdTask;

                OperationResponse response1 = await EgressTraceWithDelay(apiClient, processId);
                OperationResponse response2 = await EgressTraceWithDelay(apiClient, processId, delay: false);
                await CancelEgressOperation(apiClient, response2);

                List <OperationSummary> result = await apiClient.GetOperations();
                Assert.Equal(2, result.Count);

                OperationStatusResponse status1 = await apiClient.GetOperationStatus(response1.OperationUri);
                OperationSummary summary1       = result.First(os => os.OperationId == status1.OperationStatus.OperationId);
                ValidateOperation(status1.OperationStatus, summary1);

                OperationStatusResponse status2 = await apiClient.GetOperationStatus(response2.OperationUri);
                OperationSummary summary2       = result.First(os => os.OperationId == status2.OperationStatus.OperationId);
                ValidateOperation(status2.OperationStatus, summary2);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                configureTool : (toolRunner) =>
            {
                toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempDirectory.FullName));
            });
        }
Example #7
0
        public Task TestCustomMetrics()
        {
            return(ScenarioRunner.SingleTarget(_outputHelper,
                                               _httpClientFactory,
                                               DiagnosticPortConnectionMode.Connect,
                                               TestAppScenarios.AsyncWait.Name,
                                               async(appRunner, apiClient) =>
            {
                var counterNames = new[] { "cpu-usage", "working-set" };

                using ResponseStreamHolder holder = await apiClient.CaptureMetricsAsync(await appRunner.ProcessIdTask,
                                                                                        durationSeconds: 10,
                                                                                        metricsConfiguration: new EventMetricsConfiguration
                {
                    IncludeDefaultProviders = false,
                    Providers = new[]
                    {
                        new EventMetricsProvider
                        {
                            ProviderName = EventPipe.MonitoringSourceConfiguration.SystemRuntimeEventSourceName,
                            CounterNames = counterNames,
                        }
                    }
                });

                var metrics = GetAllMetrics(holder);
                await ValidateMetrics(new [] { EventPipe.MonitoringSourceConfiguration.SystemRuntimeEventSourceName },
                                      counterNames,
                                      metrics,
                                      strict: true);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            }));
        }
Example #8
0
        public Task TestDefaultMetrics()
        {
            return(ScenarioRunner.SingleTarget(_outputHelper,
                                               _httpClientFactory,
                                               DiagnosticPortConnectionMode.Connect,
                                               TestAppScenarios.AsyncWait.Name,
                                               async(appRunner, apiClient) =>
            {
                using ResponseStreamHolder holder = await apiClient.CaptureMetricsAsync(await appRunner.ProcessIdTask,
                                                                                        durationSeconds: 10);

                var metrics = GetAllMetrics(holder);
                await ValidateMetrics(new [] { EventPipe.MonitoringSourceConfiguration.SystemRuntimeEventSourceName },
                                      new []
                {
                    "cpu-usage",
                    "working-set",
                    "gc-heap-size",
                    "threadpool-thread-count",
                    "threadpool-queue-length"
                },
                                      metrics, strict: false);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            }));
        }
        public async Task CollectionRule_CommandLineFilterNoMatchTest(DiagnosticPortConnectionMode mode)
        {
            Task filteredTask = null;

            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                mode,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(runner, client) =>
            {
                await filteredTask;

                await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                configureTool : runner =>
            {
                // Note that the process name filter is specified as "SpinWait" whereas the
                // actual command line of the target process will contain "AsyncWait".
                runner.ConfigurationFromEnvironment.CreateCollectionRule(DefaultRuleName)
                .SetStartupTrigger()
                .AddProcessNameFilter(TestAppScenarios.SpinWait.Name);

                filteredTask = runner.WaitForCollectionRuleUnmatchedFiltersAsync(DefaultRuleName);
            });
        }
Example #10
0
        public Task LogsDefaultLevelNoneNotSupportedViaBodyTest(DiagnosticPortConnectionMode mode, LogFormat logFormat)
        {
            return(ScenarioRunner.SingleTarget(
                       _outputHelper,
                       _httpClientFactory,
                       mode,
                       TestAppScenarios.Logger.Name,
                       appValidate: async(runner, client) =>
            {
                ValidationProblemDetailsException exception = await Assert.ThrowsAsync <ValidationProblemDetailsException>(
                    async() =>
                {
                    using ResponseStreamHolder _ = await client.CaptureLogsAsync(
                              await runner.ProcessIdTask,
                              CommonTestTimeouts.LogsDuration,
                              new LogsConfiguration()
                    {
                        LogLevel = LogLevel.None
                    },
                              logFormat);
                });
                Assert.Equal(HttpStatusCode.BadRequest, exception.StatusCode);
                Assert.Equal(StatusCodes.Status400BadRequest, exception.Details.Status);

                // Allow test app to gracefully exit by continuing the scenario.
                await runner.SendCommandAsync(TestAppScenarios.Logger.Commands.StartLogging);
            }));
        }
Example #11
0
        public Task DumpTest(DiagnosticPortConnectionMode mode, DumpType type)
        {
#if !NET6_0_OR_GREATER
            // Capturing non-full dumps via diagnostic command works inconsistently
            // on Alpine for .NET 5 and lower (the dump command will return successfully, but)
            // the dump file will not exist). Only test other dump types on .NET 6+
            if (DistroInformation.IsAlpineLinux && type != DumpType.Full)
            {
                _outputHelper.WriteLine("Skipped on Alpine for .NET 5 and lower.");
                return(Task.CompletedTask);
            }
#endif

            return(ScenarioRunner.SingleTarget(
                       _outputHelper,
                       _httpClientFactory,
                       mode,
                       TestAppScenarios.AsyncWait.Name,
                       appValidate: async(runner, client) =>
            {
                int processId = await runner.ProcessIdTask;

                using ResponseStreamHolder holder = await client.CaptureDumpAsync(processId, type);
                Assert.NotNull(holder);

                // The dump operation may still be in progress but the process should still be discoverable.
                // If this check fails, then the dump operation is causing dotnet-monitor to not be able
                // to observe the process any more.
                ProcessInfo processInfo = await client.GetProcessAsync(processId);
                Assert.NotNull(processInfo);

                await DumpTestUtilities.ValidateDump(runner.Environment.ContainsKey(DumpTestUtilities.EnableElfDumpOnMacOS), holder.Stream);

                await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                       configureApp: runner =>
            {
                // MachO not supported on .NET 5, only ELF: https://github.com/dotnet/runtime/blob/main/docs/design/coreclr/botr/xplat-minidump-generation.md#os-x
                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && DotNetHost.RuntimeVersion.Major == 5)
                {
                    runner.Environment.Add(DumpTestUtilities.EnableElfDumpOnMacOS, "1");
                }
            },
                       configureTool: runner =>
            {
                string dumpTempFolder = Path.Combine(runner.TempPath, "Dumps");

                // The dump temp folder should not exist in order to test that capturing dumps into the folder
                // will work since dotnet-monitor should ensure the folder is created before issuing the dump command.
                Assert.False(Directory.Exists(dumpTempFolder), "The dump temp folder should not exist.");

                runner.ConfigurationFromEnvironment.SetDumpTempFolder(dumpTempFolder);
            }));
        }
Example #12
0
        public async Task EgressNotExistTest()
        {
            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                DiagnosticPortConnectionMode.Connect,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(appRunner, apiClient) =>
            {
                int processId = await appRunner.ProcessIdTask;

                ValidationProblemDetailsException validationException = await Assert.ThrowsAsync <ValidationProblemDetailsException>(
                    () => apiClient.EgressTraceAsync(processId, durationSeconds: 5, FileProviderName));
                Assert.Equal(HttpStatusCode.BadRequest, validationException.StatusCode);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            });
        }
Example #13
0
        public async Task SharedConcurrencyLimitTest()
        {
            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                DiagnosticPortConnectionMode.Connect,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(appRunner, apiClient) =>
            {
                int processId = await appRunner.ProcessIdTask;

                OperationResponse response1            = await EgressTraceWithDelay(apiClient, processId);
                OperationResponse response3            = await EgressTraceWithDelay(apiClient, processId);
                using HttpResponseMessage traceDirect1 = await TraceWithDelay(apiClient, processId);
                Assert.Equal(HttpStatusCode.OK, traceDirect1.StatusCode);

                ValidationProblemDetailsException ex = await Assert.ThrowsAsync <ValidationProblemDetailsException>(
                    () => EgressTraceWithDelay(apiClient, processId, delay: false));
                Assert.Equal(HttpStatusCode.TooManyRequests, ex.StatusCode);

                using HttpResponseMessage traceDirect = await TraceWithDelay(apiClient, processId, delay: false);
                Assert.Equal(HttpStatusCode.TooManyRequests, traceDirect.StatusCode);

                //Validate that the failure from a direct call (handled by middleware)
                //matches the failure produces by egress operations (handled by the Mvc ActionResult stack)
                using HttpResponseMessage egressDirect = await EgressDirect(apiClient, processId);
                Assert.Equal(HttpStatusCode.TooManyRequests, egressDirect.StatusCode);
                Assert.Equal(await egressDirect.Content.ReadAsStringAsync(), await traceDirect.Content.ReadAsStringAsync());

                await CancelEgressOperation(apiClient, response1);
                OperationResponse response4 = await EgressTraceWithDelay(apiClient, processId, delay: false);

                await CancelEgressOperation(apiClient, response3);
                await CancelEgressOperation(apiClient, response4);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                configureTool : (toolRunner) =>
            {
                toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempDirectory.FullName));
            });
        }
        public async Task CollectionRule_ActionLimitTest(DiagnosticPortConnectionMode mode)
        {
            using TemporaryDirectory tempDirectory = new(_outputHelper);
            string ExpectedFilePath    = Path.Combine(tempDirectory.FullName, "file.txt");
            string ExpectedFileContent = Guid.NewGuid().ToString("N");

            Task ruleCompletedTask = null;

            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                mode,
                TestAppScenarios.SpinWait.Name,
                appValidate : async(runner, client) =>
            {
                await runner.SendCommandAsync(TestAppScenarios.SpinWait.Commands.StartSpin);

                await ruleCompletedTask;

                await runner.SendCommandAsync(TestAppScenarios.SpinWait.Commands.StopSpin);

                Assert.True(File.Exists(ExpectedFilePath));
                Assert.Equal(ExpectedFileContent, File.ReadAllText(ExpectedFilePath));
            },
                configureTool : runner =>
            {
                runner.ConfigurationFromEnvironment.CreateCollectionRule(DefaultRuleName)
                .SetEventCounterTrigger(options =>
                {
                    // cpu usage greater that 5% for 2 seconds
                    options.ProviderName          = "System.Runtime";
                    options.CounterName           = "cpu-usage";
                    options.GreaterThan           = 5;
                    options.SlidingWindowDuration = TimeSpan.FromSeconds(2);
                })
                .AddExecuteActionAppAction("TextFileOutput", ExpectedFilePath, ExpectedFileContent)
                .SetActionLimits(count: 1);

                ruleCompletedTask = runner.WaitForCollectionRuleCompleteAsync(DefaultRuleName);
            });
        }
Example #15
0
        public Task SingleProcessIdentificationTest(DiagnosticPortConnectionMode mode)
        {
            string expectedEnvVarValue = Guid.NewGuid().ToString("D");

            return(ScenarioRunner.SingleTarget(
                       _outputHelper,
                       _httpClientFactory,
                       mode,
                       TestAppScenarios.AsyncWait.Name,
                       appValidate: async(runner, client) =>
            {
                int processId = await runner.ProcessIdTask;

                // GET /processes and filter to just the single process
                IEnumerable <ProcessIdentifier> identifiers = await client.GetProcessesWithRetryAsync(
                    _outputHelper,
                    new[] { processId });
                Assert.NotNull(identifiers);
                Assert.Single(identifiers);

                await VerifyProcessAsync(client, identifiers, processId, expectedEnvVarValue);

                await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                       postAppValidate: async(client, processId) =>
            {
                // GET /processes and filter to just the single process
                IEnumerable <ProcessIdentifier> identifiers = await client.GetProcessesWithRetryAsync(
                    _outputHelper,
                    new[] { processId });

                // Verify app is no longer reported
                Assert.NotNull(identifiers);
                Assert.Empty(identifiers);
            },
                       configureApp: runner =>
            {
                runner.Environment[ExpectedEnvVarName] = expectedEnvVarValue;
            }));
        }
Example #16
0
 private Task ValidateLogsAsync(
     DiagnosticPortConnectionMode mode,
     LogsConfiguration configuration,
     Func <ChannelReader <LogEntry>, Task> callback,
     LogFormat logFormat)
 {
     return(ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                mode,
                TestAppScenarios.Logger.Name,
                appValidate: async(runner, client) =>
                await ValidateResponseStream(
                    runner,
                    client.CaptureLogsAsync(
                        await runner.ProcessIdTask,
                        CommonTestTimeouts.LogsDuration,
                        configuration,
                        logFormat),
                    callback,
                    logFormat)));
 }
        public async Task CollectionRule_ProcessNameFilterNoMatchTest(DiagnosticPortConnectionMode mode)
        {
            Task filteredTask = null;

            await ScenarioRunner.SingleTarget(
                _outputHelper,
                _httpClientFactory,
                mode,
                TestAppScenarios.AsyncWait.Name,
                appValidate : async(runner, client) =>
            {
                await filteredTask;

                await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                configureTool : runner =>
            {
                runner.ConfigurationFromEnvironment.CreateCollectionRule(DefaultRuleName)
                .SetStartupTrigger()
                .AddProcessNameFilter("UmatchedName");

                filteredTask = runner.WaitForCollectionRuleUnmatchedFiltersAsync(DefaultRuleName);
            });
        }