diff --git a/Tms.Adapter.Core/Tms.Adapter.Core.csproj b/Tms.Adapter.Core/Tms.Adapter.Core.csproj
index 83d713d..7d036c8 100644
--- a/Tms.Adapter.Core/Tms.Adapter.Core.csproj
+++ b/Tms.Adapter.Core/Tms.Adapter.Core.csproj
@@ -29,10 +29,10 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
+
diff --git a/Tms.Adapter.CoreTests/Tms.Adapter.CoreTests.csproj b/Tms.Adapter.CoreTests/Tms.Adapter.CoreTests.csproj
index 6aea926..346ce48 100644
--- a/Tms.Adapter.CoreTests/Tms.Adapter.CoreTests.csproj
+++ b/Tms.Adapter.CoreTests/Tms.Adapter.CoreTests.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/Tms.Adapter/Tms.Adapter.csproj b/Tms.Adapter/Tms.Adapter.csproj
index c6c7f9a..532b3d3 100644
--- a/Tms.Adapter/Tms.Adapter.csproj
+++ b/Tms.Adapter/Tms.Adapter.csproj
@@ -32,7 +32,7 @@
-
+
diff --git a/TmsRunner/App.cs b/TmsRunner/App.cs
new file mode 100644
index 0000000..a3c355c
--- /dev/null
+++ b/TmsRunner/App.cs
@@ -0,0 +1,63 @@
+using Microsoft.Extensions.Logging;
+using TmsRunner.Client;
+using TmsRunner.Configuration;
+using TmsRunner.Models;
+using TmsRunner.Services;
+
+namespace TmsRunner;
+
+public class App(ILogger logger, AdapterConfig adapterConfig, TmsSettings tmsSettings, ITmsClient tmsClient, FilterService filterService, Runner runner)
+{
+ public async Task RunAsync()
+ {
+ logger.LogInformation("Adapter works in {Mode} mode", tmsSettings.AdapterMode);
+ logger.LogDebug("Parameters:");
+ logger.LogDebug("Runner Path: {Path}", adapterConfig.RunnerPath);
+ logger.LogDebug("Test Assembly Path: {Path}", adapterConfig.TestAssemblyPath);
+ logger.LogDebug("Test Adapter Path: {Path}", adapterConfig.TestAdapterPath);
+ logger.LogDebug("Test Logger Path: {Path}", adapterConfig.LoggerPath);
+
+ runner.InitialiseRunner();
+ var testCases = runner.DiscoverTests();
+ logger.LogInformation("Discovered Tests Count: {Count}", testCases.Count);
+
+ if (testCases.Count == 0)
+ {
+ logger.LogInformation("Can not found tests for run");
+
+ return 1;
+ }
+
+ switch (tmsSettings.AdapterMode)
+ {
+ case 0:
+ {
+ var testCaseForRun = await tmsClient.GetAutoTestsForRunAsync(tmsSettings.TestRunId).ConfigureAwait(false);
+ testCases = filterService.FilterTestCases(adapterConfig.TestAssemblyPath, testCaseForRun, testCases);
+
+ break;
+ }
+ case 2:
+ {
+ tmsSettings.TestRunId = await tmsClient.CreateTestRunAsync().ConfigureAwait(false);
+
+ if (!string.IsNullOrEmpty(adapterConfig.TmsLabelsOfTestsToRun))
+ {
+ testCases = filterService.FilterTestCasesByLabels(adapterConfig, testCases);
+ }
+
+ break;
+ }
+ }
+
+ logger.LogInformation("Running tests: {Count}", testCases.Count);
+ await runner.RunSelectedTestsAsync(testCases).ConfigureAwait(false);
+
+ if (tmsSettings.AdapterMode == 2)
+ {
+ logger.LogInformation("Test run {TestRunId} finished.", tmsSettings.TestRunId);
+ }
+
+ return 0;
+ }
+}
diff --git a/TmsRunner/Client/Converter.cs b/TmsRunner/Client/Converter.cs
deleted file mode 100644
index e3d84b9..0000000
--- a/TmsRunner/Client/Converter.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-using TestIT.ApiClient.Model;
-using TmsRunner.Models;
-
-namespace TmsRunner.Client;
-
-public class Converter
-{
- public static CreateAutoTestRequest ConvertAutoTestDtoToPostModel(AutoTest dto, string projectId)
- {
- var links = dto.Links?.Select(l =>
- new LinkPostModel(
- l.Title,
- l.Url,
- l.Description,
- Enum.Parse(l.Type.ToString()!))
- ).ToList();
-
- return new CreateAutoTestRequest(externalId: dto.ExternalId, name: dto.Name)
- {
- ExternalId = dto.ExternalId,
- Links = links!,
- ProjectId = new Guid(projectId),
- Namespace = dto.Namespace,
- Classname = dto.Classname,
- Steps = ConvertStepsToModel(dto.Steps),
- Setup = ConvertStepsToModel(dto.Setup),
- Teardown = ConvertStepsToModel(dto.Teardown),
- Title = dto.Title,
- Description = dto.Description,
- Labels = ConvertLabelsToModel(dto.Labels)
- };
- }
-
- public static UpdateAutoTestRequest ConvertAutoTestDtoToPutModel(AutoTest dto, string projectId)
- {
- var links = dto.Links.Select(l =>
- new LinkPutModel(
- title: l.Title,
- url: l.Url,
- description: l.Description,
- type: Enum.Parse(l.Type.ToString()!))
- ).ToList();
-
-
- return new UpdateAutoTestRequest(externalId: dto.ExternalId, name: dto.Name)
- {
- Links = links,
- ProjectId = new Guid(projectId), Name = dto.Name,
- Namespace = dto.Namespace,
- Classname = dto.Classname,
- Steps = ConvertStepsToModel(dto.Steps),
- Setup = ConvertStepsToModel(dto.Setup),
- Teardown = ConvertStepsToModel(dto.Teardown),
- Title = dto.Title,
- Description = dto.Description,
- Labels = ConvertLabelsToModel(dto.Labels),
- IsFlaky = dto.IsFlaky
- };
- }
-
- public static AutoTestResultsForTestRunModel ConvertResultToModel(AutoTestResult dto, string configurationId)
- {
- var links = dto.Links?.Select(l =>
- new LinkPostModel(
- l.Title,
- l.Url,
- l.Description,
- Enum.Parse(l.Type.ToString()!))
- ).ToList();
-
- return new AutoTestResultsForTestRunModel(
- autoTestExternalId: dto.ExternalId,
- outcome: Enum.Parse(dto.Outcome.ToString()))
- {
- ConfigurationId = new Guid(configurationId),
- Links = links,
- Message = dto.Message,
- Traces = dto.Traces,
- StartedOn = dto.StartedOn,
- CompletedOn = dto.CompletedOn,
- Duration = dto.Duration,
- Attachments = dto.Attachments.Select(a => new AttachmentPutModel(a)).ToList(),
- Parameters = dto.Parameters,
- StepResults = ConvertResultStepToModel(dto.StepResults),
- SetupResults = ConvertResultStepToModel(dto.SetupResults),
- TeardownResults = ConvertResultStepToModel(dto.TeardownResults)
- };
- }
-
- private static List? ConvertLabelsToModel(IEnumerable? labels)
- {
- return labels?.Select(l =>
- new LabelPostModel(l))
- .ToList();
- }
-
- private static List ConvertResultStepToModel(
- IEnumerable dtos)
- {
- return dtos
- .Select(s => new AttachmentPutModelAutoTestStepResultsModel
- {
- Title = s.Title,
- Description = s.Description,
- StartedOn = s.StartedOn,
- CompletedOn = s.CompletedOn,
- Duration = s.Duration,
- Attachments = s.Attachments.Select(a => new AttachmentPutModel(a)).ToList(),
- Parameters = s.Parameters,
- StepResults = ConvertResultStepToModel(s.Steps),
- Outcome = Enum.Parse(s.Outcome)
- }).ToList();
- }
-
- private static List ConvertStepsToModel(IEnumerable stepDtos)
- {
- return stepDtos
- .Select(s => new AutoTestStepModel(
- s.Title,
- s.Description,
- ConvertStepsToModel(s.Steps))).ToList();
- }
-}
\ No newline at end of file
diff --git a/TmsRunner/Client/ITmsClient.cs b/TmsRunner/Client/ITmsClient.cs
index cb055b2..725c072 100644
--- a/TmsRunner/Client/ITmsClient.cs
+++ b/TmsRunner/Client/ITmsClient.cs
@@ -5,12 +5,12 @@ namespace TmsRunner.Client;
public interface ITmsClient
{
- Task CreateTestRun();
- Task> GetAutoTestsForRun(string testRunId);
- Task SubmitResultToTestRun(string guid, AutoTestResult result);
- Task UploadAttachment(string fileName, Stream content);
- Task GetAutotestByExternalId(string externalId);
- Task CreateAutotest(AutoTest model);
- Task UpdateAutotest(AutoTest model);
- Task TryLinkAutoTestToWorkItem(string autotestId, IEnumerable workItemIds);
+ Task CreateTestRunAsync();
+ Task> GetAutoTestsForRunAsync(string? testRunId);
+ Task SubmitResultToTestRunAsync(string? guid, AutoTestResult result);
+ Task UploadAttachmentAsync(string fileName, Stream content);
+ Task GetAutotestByExternalIdAsync(string? externalId);
+ Task CreateAutotestAsync(AutoTest model);
+ Task UpdateAutotestAsync(AutoTest model);
+ Task TryLinkAutoTestToWorkItemAsync(string autotestId, IEnumerable workItemIds);
}
\ No newline at end of file
diff --git a/TmsRunner/Client/TmsClient.cs b/TmsRunner/Client/TmsClient.cs
index 4c4a347..1ea017e 100644
--- a/TmsRunner/Client/TmsClient.cs
+++ b/TmsRunner/Client/TmsClient.cs
@@ -1,180 +1,149 @@
-using Serilog;
+using Microsoft.Extensions.Logging;
using TestIT.ApiClient.Api;
using TestIT.ApiClient.Client;
using TestIT.ApiClient.Model;
-using TmsRunner.Logger;
using TmsRunner.Models;
+using TmsRunner.Utils;
-namespace TmsRunner.Client
+namespace TmsRunner.Client;
+
+public sealed class TmsClient(ILogger logger, TmsSettings settings, ITestRunsApiAsync testRunsApi, IAttachmentsApiAsync attachmentsApi, IAutoTestsApiAsync autoTestsApi) : ITmsClient
{
- public class TmsClient : ITmsClient
+ public async Task CreateTestRunAsync()
{
- private readonly TmsSettings _settings;
- private readonly ILogger _logger;
- private readonly TestRunsApi _testRuns;
- private readonly AttachmentsApi _attachments;
- private readonly AutoTestsApi _autoTests;
-
- public TmsClient(TmsSettings settings)
+ var createTestRunRequestBody = new CreateEmptyRequest
{
- _logger = LoggerFactory.GetLogger().ForContext();
- _settings = settings;
-
- var cfg = new TestIT.ApiClient.Client.Configuration { BasePath = settings.Url };
- cfg.AddApiKeyPrefix("Authorization", "PrivateToken");
- cfg.AddApiKey("Authorization", settings.PrivateToken);
+ ProjectId = new Guid(settings.ProjectId ?? string.Empty),
+ Name = (string.IsNullOrEmpty(settings.TestRunName) ? null : settings.TestRunName)!
+ };
- var httpClientHandler = new HttpClientHandler();
- httpClientHandler.ServerCertificateCustomValidationCallback = (_, _, _, _) => _settings.CertValidation;
+ logger.LogDebug("Creating test run {@TestRun}", createTestRunRequestBody);
- _testRuns = new TestRunsApi(new HttpClient(), cfg, httpClientHandler);
- _attachments = new AttachmentsApi(new HttpClient(), cfg, httpClientHandler);
- _autoTests = new AutoTestsApi(new HttpClient(), cfg, httpClientHandler);
- }
+ var testRun = await testRunsApi.CreateEmptyAsync(createTestRunRequestBody).ConfigureAwait(false) ?? throw new Exception($"Could not find project with id: {settings.ProjectId}");
+ logger.LogDebug("Created test run {@TestRun}", testRun);
- public async Task CreateTestRun()
- {
- var createTestRunRequestBody = new CreateEmptyRequest
- {
- ProjectId = new Guid(_settings.ProjectId),
- Name = (string.IsNullOrEmpty(_settings.TestRunName) ? null : _settings.TestRunName)!
- };
-
- _logger.Debug("Creating test run {@TestRun}", createTestRunRequestBody);
+ return testRun.Id.ToString();
+ }
- var testRun = await _testRuns.CreateEmptyAsync(createTestRunRequestBody);
+ public async Task> GetAutoTestsForRunAsync(string? testRunId)
+ {
+ logger.LogDebug("Getting autotests for run from test run {Id}", testRunId);
- if (testRun is null)
- {
- throw new Exception($"Could not find project with id: {_settings.ProjectId}");
- }
+ var testRun = await testRunsApi.GetTestRunByIdAsync(new Guid(testRunId ?? string.Empty)).ConfigureAwait(false);
- _logger.Debug("Created test run {@TestRun}", testRun);
+ var autotests = testRun.TestResults.Where(x => !x.AutoTest.IsDeleted).Select(x => x.AutoTest.ExternalId).ToList();
- return testRun.Id.ToString();
- }
+ logger.LogDebug(
+ "Autotests for run from test run {Id}: {@Autotests}",
+ testRunId,
+ autotests);
- public async Task> GetAutoTestsForRun(string testRunId)
- {
- _logger.Debug("Getting autotests for run from test run {Id}", testRunId);
+ return autotests as List;
+ }
- var testRun = await _testRuns.GetTestRunByIdAsync(new Guid(testRunId));
+ public async Task SubmitResultToTestRunAsync(string? id, AutoTestResult result)
+ {
+ logger.LogDebug("Submitting test result {@Result} to test run {@Id}", result, id);
- var autotests = testRun.TestResults.Where(x => !x.AutoTest.IsDeleted).Select(x => x.AutoTest.ExternalId).ToList();
+ var model = Converter.ConvertResultToModel(result, settings.ConfigurationId);
+ _ = await testRunsApi.SetAutoTestResultsForTestRunAsync(new Guid(id ?? string.Empty), [model]).ConfigureAwait(false);
- _logger.Debug(
- "Autotests for run from test run {Id}: {@Autotests}",
- testRunId,
- autotests);
+ logger.LogDebug("Submit test result to test run {Id} is successfully", id);
+ }
- return autotests;
- }
+ public async Task UploadAttachmentAsync(string fileName, Stream content)
+ {
+ logger.LogDebug("Uploading attachment {Name}", fileName);
- public async Task SubmitResultToTestRun(string id, AutoTestResult result)
- {
- _logger.Debug("Submitting test result {@Result} to test run {@Id}", result, id);
+ var response = await attachmentsApi.ApiV2AttachmentsPostAsync(
+ new FileParameter(
+ filename: Path.GetFileName(fileName),
+ content: content,
+ contentType: MimeTypes.GetMimeType(fileName))
+ ).ConfigureAwait(false);
- var model = Converter.ConvertResultToModel(result, _settings.ConfigurationId);
- await _testRuns.SetAutoTestResultsForTestRunAsync(new Guid(id),
- new List { model });
+ logger.LogDebug("Upload attachment {@Attachment} is successfully", response);
- _logger.Debug("Submit test result to test run {Id} is successfully", id);
- }
+ return response;
+ }
- public async Task UploadAttachment(string fileName, Stream content)
- {
- _logger.Debug("Uploading attachment {Name}", fileName);
+ public async Task GetAutotestByExternalIdAsync(string? externalId)
+ {
+ logger.LogDebug("Getting autotest by external id {Id}", externalId);
- var response = await _attachments.ApiV2AttachmentsPostAsync(
- new FileParameter(
- filename: Path.GetFileName(fileName),
- content: content,
- contentType: MimeTypes.GetMimeType(fileName))
- );
+ var filter = new ApiV2AutoTestsSearchPostRequest(
+ filter: new AutotestsSelectModelFilter
+ {
+ ExternalIds = [externalId ?? string.Empty],
+ ProjectIds = settings.ProjectId == null ? [] : [new Guid(settings.ProjectId)],
+ IsDeleted = false
+ },
+ includes: new AutotestsSelectModelIncludes()
+ );
+
+ var autotests = await autoTestsApi.ApiV2AutoTestsSearchPostAsync(apiV2AutoTestsSearchPostRequest: filter).ConfigureAwait(false);
+ var autotest = autotests.FirstOrDefault();
+
+ logger.LogDebug(
+ "Get autotest {@Autotest} by external id {Id}",
+ autotest,
+ externalId);
+
+ return autotest;
+ }
- _logger.Debug("Upload attachment {@Attachment} is successfully", response);
+ public async Task CreateAutotestAsync(AutoTest dto)
+ {
+ logger.LogDebug("Creating autotest {@Autotest}", dto);
- return response;
- }
+ var model = Converter.ConvertAutoTestDtoToPostModel(dto, settings.ProjectId);
+ model.ShouldCreateWorkItem = settings.AutomaticCreationTestCases;
+ var response = await autoTestsApi.CreateAutoTestAsync(model).ConfigureAwait(false);
- public async Task GetAutotestByExternalId(string externalId)
- {
- _logger.Debug("Getting autotest by external id {Id}", externalId);
-
- var filter = new ApiV2AutoTestsSearchPostRequest(
- filter: new AutotestsSelectModelFilter
- {
- ExternalIds = new List { externalId },
- ProjectIds = new List { new Guid(_settings.ProjectId) },
- IsDeleted = false
- },
- includes: new AutotestsSelectModelIncludes()
- );
-
- var autotests = await _autoTests.ApiV2AutoTestsSearchPostAsync(apiV2AutoTestsSearchPostRequest: filter);
- var autotest = autotests.FirstOrDefault();
-
- _logger.Debug(
- "Get autotest {@Autotest} by external id {Id}",
- autotest,
- externalId);
-
- return autotest;
- }
+ logger.LogDebug("Create autotest {@Autotest} is successfully", response);
- public async Task CreateAutotest(AutoTest dto)
- {
- _logger.Debug("Creating autotest {@Autotest}", dto);
+ return response;
+ }
- var model = Converter.ConvertAutoTestDtoToPostModel(dto, _settings.ProjectId);
- model.ShouldCreateWorkItem = _settings.AutomaticCreationTestCases;
- var response = await _autoTests.CreateAutoTestAsync(model);
+ public async Task UpdateAutotestAsync(AutoTest dto)
+ {
+ logger.LogDebug("Updating autotest {@Autotest}", dto);
- _logger.Debug("Create autotest {@Autotest} is successfully", response);
+ var model = Converter.ConvertAutoTestDtoToPutModel(dto, settings.ProjectId);
+ await autoTestsApi.UpdateAutoTestAsync(model).ConfigureAwait(false);
- return response;
- }
+ logger.LogDebug("Update autotest {@Autotest} is successfully", model);
+ }
- public async Task UpdateAutotest(AutoTest dto)
+ public async Task TryLinkAutoTestToWorkItemAsync(string autotestId, IEnumerable workItemIds)
+ {
+ foreach (var workItemId in workItemIds)
{
- _logger.Debug("Updating autotest {@Autotest}", dto);
-
- var model = Converter.ConvertAutoTestDtoToPutModel(dto, _settings.ProjectId);
- await _autoTests.UpdateAutoTestAsync(model);
-
- _logger.Debug("Update autotest {@Autotest} is successfully", model);
- }
+ logger.LogDebug(
+ "Linking autotest {AutotestId} to workitem {WorkitemId}",
+ autotestId,
+ workItemId);
- public async Task TryLinkAutoTestToWorkItem(string autotestId, IEnumerable workItemIds)
- {
- foreach (var workItemId in workItemIds)
+ try
{
- _logger.Debug(
- "Linking autotest {AutotestId} to workitem {WorkitemId}",
- autotestId,
- workItemId);
-
- try
- {
- await _autoTests.LinkAutoTestToWorkItemAsync(autotestId, new LinkAutoTestToWorkItemRequest(workItemId));
- }
- catch (ApiException e) when (e.Message.Contains("does not exist"))
- {
- _logger.Error(
- "Cannot link autotest {AutotestId} to work item {WorkItemId}: work item does not exist",
- autotestId,
- workItemId);
-
- return false;
- }
-
- _logger.Debug(
- "Link autotest {AutotestId} to workitem {WorkitemId} is successfully",
- autotestId,
- workItemId);
+ await autoTestsApi.LinkAutoTestToWorkItemAsync(autotestId, new LinkAutoTestToWorkItemRequest(workItemId ?? string.Empty)).ConfigureAwait(false);
}
+ catch (ApiException e) when (e.Message.Contains("does not exist"))
+ {
+ logger.LogError(
+ "Cannot link autotest {AutotestId} to work item {WorkItemId}: work item does not exist",
+ autotestId,
+ workItemId);
- return true;
+ return false;
+ }
+
+ logger.LogDebug(
+ "Link autotest {AutotestId} to workitem {WorkitemId} is successfully",
+ autotestId,
+ workItemId);
}
+
+ return true;
}
}
\ No newline at end of file
diff --git a/TmsRunner/Options/AdapterConfig.cs b/TmsRunner/Configuration/AdapterConfig.cs
similarity index 75%
rename from TmsRunner/Options/AdapterConfig.cs
rename to TmsRunner/Configuration/AdapterConfig.cs
index 7a82a54..75af0f6 100644
--- a/TmsRunner/Options/AdapterConfig.cs
+++ b/TmsRunner/Configuration/AdapterConfig.cs
@@ -1,66 +1,66 @@
using CommandLine;
using TmsRunner.Models;
-namespace TmsRunner.Options;
+namespace TmsRunner.Configuration;
-public class AdapterConfig
+public sealed class AdapterConfig
{
[Option('r', "runner", Required = true,
HelpText =
"Set path to test runner. Example: --runner '/opt/homebrew/Cellar/dotnet/6.0.110/libexec/sdk/6.0.110/vstest.console.dll'")]
- public string RunnerPath { get; set; }
+ public string? RunnerPath { get; set; }
[Option('t', "testassembly", Required = true,
HelpText = "Set path to test assembly. Example: --testassembly '/Tests/tests.dll'")]
- public string TestAssemblyPath { get; set; }
+ public string? TestAssemblyPath { get; set; }
[Option('a', "testadapter", Required = false,
HelpText = "Set path to test adapter. Example: --testadapter '/Tests/testsAdapter.dll'")]
- public string TestAdapterPath { get; set; }
+ public string? TestAdapterPath { get; set; }
[Option('l', "logger", Required = false,
HelpText = "Set path to logger. Example: --logger '/Tests/logger.dll'")]
- public string LoggerPath { get; set; }
+ public string? LoggerPath { get; set; }
[Option("tmsLabelsOfTestsToRun", Required = false, HelpText = "Set labels of autotests to run. Example: --tmsLabelsOfTestsToRun smoke OR --tmsLabelsOfTestsToRun smoke,prod,cloud")]
- public string TmsLabelsOfTestsToRun { get; set; }
+ public string? TmsLabelsOfTestsToRun { get; set; }
[Option('d', "debug", Required = false,
HelpText = "Set debug level for logging. Example: --debug")]
public bool IsDebug { get; set; }
[Option("tmsUrl", Required = false, HelpText = "Set TMS host address.")]
- public string TmsUrl { get; set; }
+ public string? TmsUrl { get; set; }
[Option("tmsPrivateToken", Required = false, HelpText = "Set private token.")]
- public string TmsPrivateToken { get; set; }
+ public string? TmsPrivateToken { get; set; }
[Option("tmsProjectId", Required = false, HelpText = "Set project id.")]
- public string TmsProjectId { get; set; }
+ public string? TmsProjectId { get; set; }
[Option("tmsConfigurationId", Required = false, HelpText = "Set configuration id.")]
- public string TmsConfigurationId { get; set; }
+ public string? TmsConfigurationId { get; set; }
[Option("tmsTestRunId", Required = false, HelpText = "Set test run id.")]
- public string TmsTestRunId { get; set; }
+ public string? TmsTestRunId { get; set; }
[Option("tmsTestRunName", Required = false, HelpText = "Set test run name.")]
- public string TmsTestRunName { get; set; }
+ public string? TmsTestRunName { get; set; }
[Option("tmsAdapterMode", Required = false, HelpText = "Set adapter mode.")]
- public string TmsAdapterMode { get; set; }
+ public string? TmsAdapterMode { get; set; }
[Option("tmsConfigFile", Required = false, HelpText = "Set configuration file name.")]
- public string TmsConfigFile { get; set; }
+ public string? TmsConfigFile { get; set; }
[Option("tmsRunSettings", Required = false, HelpText = "Set run settings.")]
- public string TmsRunSettings { get; set; }
+ public string? TmsRunSettings { get; set; }
[Option("tmsAutomaticCreationTestCases", Required = false, HelpText = "Set automatic creation test cases.")]
- public string TmsAutomaticCreationTestCases { get; set; }
+ public string? TmsAutomaticCreationTestCases { get; set; }
[Option("tmsCertValidation", Default = "true", Required = false, HelpText = "Set certificate validation.")]
- public string TmsCertValidation { get; set; }
+ public string? TmsCertValidation { get; set; }
public Config ToInternalConfig()
{
diff --git a/TmsRunner/Configuration/ClassConfigurationProvider.cs b/TmsRunner/Configuration/ClassConfigurationProvider.cs
index bf29927..3740564 100644
--- a/TmsRunner/Configuration/ClassConfigurationProvider.cs
+++ b/TmsRunner/Configuration/ClassConfigurationProvider.cs
@@ -3,30 +3,23 @@
namespace TmsRunner.Configuration;
-public class ClassConfigurationProvider : ConfigurationProvider
+public sealed class ClassConfigurationProvider(Config config) : ConfigurationProvider
{
- private readonly Config _config;
-
- public ClassConfigurationProvider(Config config)
- {
- _config = config;
- }
-
public override void Load()
{
- var data = new Dictionary
+ var data = new Dictionary
{
- { "Url", _config.TmsUrl },
- { "PrivateToken", _config.TmsPrivateToken },
- { "ProjectId", _config.TmsProjectId },
- { "ConfigurationId", _config.TmsConfigurationId },
- { "TestRunId", _config.TmsTestRunId },
- { "TestRunName", _config.TmsTestRunName },
- { "AdapterMode", _config.TmsAdapterMode },
- { "ConfigFile", _config.TmsConfigFile },
- { "RunSettings", _config.TmsRunSettings },
- { "AutomaticCreationTestCases", _config.TmsAutomaticCreationTestCases },
- { "CertValidation", _config.TmsCertValidation }
+ { "Url", config.TmsUrl },
+ { "PrivateToken", config.TmsPrivateToken },
+ { "ProjectId", config.TmsProjectId },
+ { "ConfigurationId", config.TmsConfigurationId },
+ { "TestRunId", config.TmsTestRunId },
+ { "TestRunName", config.TmsTestRunName },
+ { "AdapterMode", config.TmsAdapterMode },
+ { "ConfigFile", config.TmsConfigFile },
+ { "RunSettings", config.TmsRunSettings },
+ { "AutomaticCreationTestCases", config.TmsAutomaticCreationTestCases },
+ { "CertValidation", config.TmsCertValidation }
};
Data = data
diff --git a/TmsRunner/Configuration/ClassConfigurationSource.cs b/TmsRunner/Configuration/ClassConfigurationSource.cs
index f6e7e61..e8c903c 100644
--- a/TmsRunner/Configuration/ClassConfigurationSource.cs
+++ b/TmsRunner/Configuration/ClassConfigurationSource.cs
@@ -3,15 +3,12 @@
namespace TmsRunner.Configuration;
-public class ClassConfigurationSource : IConfigurationSource
+public sealed class ClassConfigurationSource(Config config) : IConfigurationSource
{
- private readonly Config _config;
+ private readonly Config _config = config;
- public ClassConfigurationSource(Config config)
+ public IConfigurationProvider Build(IConfigurationBuilder builder)
{
- _config = config;
+ return new ClassConfigurationProvider(_config);
}
-
- public IConfigurationProvider Build(IConfigurationBuilder builder)
- => new ClassConfigurationProvider(_config);
}
\ No newline at end of file
diff --git a/TmsRunner/Configuration/ConfigurationExtension.cs b/TmsRunner/Configuration/ConfigurationExtension.cs
index 8c05784..144767b 100644
--- a/TmsRunner/Configuration/ConfigurationExtension.cs
+++ b/TmsRunner/Configuration/ConfigurationExtension.cs
@@ -5,10 +5,9 @@ namespace TmsRunner.Configuration;
public static class ConfigurationExtension
{
- public static void AddCustomConfiguration(this IConfigurationBuilder builder,
- Config config)
+ public static void AddCustomConfiguration(this IConfigurationBuilder builder, Config config)
{
- builder.Add(new EnvConfigurationSource());
- builder.Add(new ClassConfigurationSource(config));
+ _ = builder.Add(new EnvConfigurationSource());
+ _ = builder.Add(new ClassConfigurationSource(config));
}
}
\ No newline at end of file
diff --git a/TmsRunner/Configuration/ConfigurationManager.cs b/TmsRunner/Configuration/ConfigurationManager.cs
index 71e341b..d1e60d6 100644
--- a/TmsRunner/Configuration/ConfigurationManager.cs
+++ b/TmsRunner/Configuration/ConfigurationManager.cs
@@ -1,80 +1,81 @@
-using System.Configuration;
-using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Configuration;
+using System.Configuration;
using TmsRunner.Extensions;
using TmsRunner.Models;
-namespace TmsRunner.Configuration
+namespace TmsRunner.Configuration;
+
+public static class ConfigurationManager
{
- public static class ConfigurationManager
+ private const string EnvConfigFile = "TMS_CONFIG_FILE";
+ private const string DefaultConfigFileName = "Tms.config.json";
+
+ public static TmsSettings Configure(Config adapterConfig, string pathToConfFile)
{
- private const string EnvConfigFile = "TMS_CONFIG_FILE";
- private const string DefaultConfigFileName = "Tms.config.json";
+ if (string.IsNullOrWhiteSpace(pathToConfFile))
+ {
+ throw new ArgumentException("The path of config directory is empty", nameof(pathToConfFile));
+ }
- public static TmsSettings Configure(Config adapterConfig, string pathToConfFile)
+ var configFileName = GetConfigFileName(adapterConfig.TmsConfigFile);
+ var configurationFileLocation = Path.Combine(pathToConfFile, configFileName);
+
+ var configBuilder = new ConfigurationBuilder();
+
+ if (File.Exists(configurationFileLocation))
{
- if (string.IsNullOrWhiteSpace(pathToConfFile))
- {
- throw new ArgumentException("The path of config directory is empty", nameof(pathToConfFile));
- }
+ _ = configBuilder.AddJsonFile(configurationFileLocation);
+ }
+ else
+ {
+ Console.WriteLine($"Configuration file was not found at {configurationFileLocation}");
+ }
- var configFileName = GetConfigFileName(adapterConfig.TmsConfigFile);
- var configurationFileLocation = Path.Combine(pathToConfFile, configFileName);
+ configBuilder.AddCustomConfiguration(adapterConfig);
+ var config = configBuilder.Build();
+ var tmsSettings = new TmsSettings();
+ config.Bind(tmsSettings);
- var configBuilder = new ConfigurationBuilder();
+ Validate(tmsSettings);
- if (File.Exists(configurationFileLocation))
- {
- configBuilder.AddJsonFile(configurationFileLocation);
- }
- else
- {
- Console.WriteLine($"Configuration file was not found at {configurationFileLocation}");
- }
+ return tmsSettings;
+ }
- configBuilder.AddCustomConfiguration(adapterConfig);
- var config = configBuilder.Build();
- var tmsSettings = new TmsSettings();
- config.Bind(tmsSettings);
+ private static string GetConfigFileName(string? path)
+ {
+ var defaultConfFileName = DefaultConfigFileName;
+ var envConfFileName = Environment.GetEnvironmentVariable(EnvConfigFile);
+ defaultConfFileName = defaultConfFileName.AssignIfNullOrEmpty(envConfFileName);
- Validate(tmsSettings);
+ return defaultConfFileName.AssignIfNullOrEmpty(path);
+ }
- return tmsSettings;
+ private static void Validate(TmsSettings settings)
+ {
+ if (string.IsNullOrWhiteSpace(settings.Url))
+ {
+ throw new ConfigurationErrorsException("Url is empty");
}
- private static string GetConfigFileName(string path)
+ if (string.IsNullOrWhiteSpace(settings.PrivateToken))
{
- var defaultConfFileName = DefaultConfigFileName;
- var envConfFileName = Environment.GetEnvironmentVariable(EnvConfigFile);
- defaultConfFileName = defaultConfFileName.AssignIfNullOrEmpty(envConfFileName);
- return defaultConfFileName.AssignIfNullOrEmpty(path);
+ throw new ConfigurationErrorsException("Private token is empty");
}
- private static void Validate(TmsSettings settings)
+ if (string.IsNullOrWhiteSpace(settings.ConfigurationId))
{
- if (string.IsNullOrWhiteSpace(settings.Url))
- {
- throw new ConfigurationErrorsException("Url is empty");
- }
-
- if (string.IsNullOrWhiteSpace(settings.PrivateToken))
- {
- throw new ConfigurationErrorsException("Private token is empty");
- }
-
- if (string.IsNullOrWhiteSpace(settings.ConfigurationId))
- {
- throw new ConfigurationErrorsException("Configuration id is empty");
- }
+ throw new ConfigurationErrorsException("Configuration id is empty");
+ }
- if (!string.IsNullOrWhiteSpace(settings.RunSettings) && !IsValidXml(settings.RunSettings))
- {
- throw new ConfigurationErrorsException("Run settings is invalid");
- }
+ if (!string.IsNullOrWhiteSpace(settings.RunSettings) && !IsValidXml(settings.RunSettings))
+ {
+ throw new ConfigurationErrorsException("Run settings is invalid");
+ }
- switch (settings.AdapterMode)
- {
- case 0:
- case 1:
+ switch (settings.AdapterMode)
+ {
+ case 0:
+ case 1:
{
if (string.IsNullOrWhiteSpace(settings.TestRunId))
{
@@ -84,33 +85,35 @@ private static void Validate(TmsSettings settings)
break;
}
- case 2:
- if (string.IsNullOrWhiteSpace(settings.ProjectId) || !string.IsNullOrWhiteSpace(settings.TestRunId))
- {
- throw new ConfigurationErrorsException(
- "Adapter works in mode 2. Config should contains project id and configuration id. Also doesn't contains test run id.");
- }
+ case 2:
+ if (string.IsNullOrWhiteSpace(settings.ProjectId) || !string.IsNullOrWhiteSpace(settings.TestRunId))
+ {
+ throw new ConfigurationErrorsException(
+ "Adapter works in mode 2. Config should contains project id and configuration id. Also doesn't contains test run id.");
+ }
- break;
- default:
- throw new Exception($"Incorrect adapter mode: {settings.AdapterMode}");
- }
+ break;
+ default:
+ throw new Exception($"Incorrect adapter mode: {settings.AdapterMode}");
}
+ }
- private static bool IsValidXml(string xmlStr)
+ private static bool IsValidXml(string xmlStr)
+ {
+ try
{
- try
- {
- if (string.IsNullOrEmpty(xmlStr)) return false;
-
- var xmlDoc = new System.Xml.XmlDocument();
- xmlDoc.LoadXml(xmlStr);
- return true;
- }
- catch (System.Xml.XmlException)
+ if (string.IsNullOrEmpty(xmlStr))
{
return false;
}
+
+ var xmlDoc = new System.Xml.XmlDocument();
+ xmlDoc.LoadXml(xmlStr);
+ return true;
+ }
+ catch (System.Xml.XmlException)
+ {
+ return false;
}
}
}
\ No newline at end of file
diff --git a/TmsRunner/Configuration/EnvConfigurationProvider.cs b/TmsRunner/Configuration/EnvConfigurationProvider.cs
index 2b00d9b..cec8b9d 100644
--- a/TmsRunner/Configuration/EnvConfigurationProvider.cs
+++ b/TmsRunner/Configuration/EnvConfigurationProvider.cs
@@ -2,7 +2,7 @@
namespace TmsRunner.Configuration;
-public class EnvConfigurationProvider : ConfigurationProvider
+public sealed class EnvConfigurationProvider : ConfigurationProvider
{
private const string EnvTmsUrl = "TMS_URL";
private const string EnvTmsPrivateToken = "TMS_PRIVATE_TOKEN";
@@ -17,7 +17,7 @@ public class EnvConfigurationProvider : ConfigurationProvider
public override void Load()
{
- var data = new Dictionary
+ var data = new Dictionary
{
{ "Url", Environment.GetEnvironmentVariable(EnvTmsUrl) },
{ "PrivateToken", Environment.GetEnvironmentVariable(EnvTmsPrivateToken) },
diff --git a/TmsRunner/Configuration/EnvConfigurationSource.cs b/TmsRunner/Configuration/EnvConfigurationSource.cs
index eaf98b9..d9b0fa6 100644
--- a/TmsRunner/Configuration/EnvConfigurationSource.cs
+++ b/TmsRunner/Configuration/EnvConfigurationSource.cs
@@ -2,8 +2,10 @@
namespace TmsRunner.Configuration;
-public class EnvConfigurationSource : IConfigurationSource
+public sealed class EnvConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
- => new EnvConfigurationProvider();
+ {
+ return new EnvConfigurationProvider();
+ }
}
\ No newline at end of file
diff --git a/TmsRunner/Enums/HttpClientNames.cs b/TmsRunner/Enums/HttpClientNames.cs
new file mode 100644
index 0000000..ce210d5
--- /dev/null
+++ b/TmsRunner/Enums/HttpClientNames.cs
@@ -0,0 +1,6 @@
+namespace TmsRunner.Enums;
+
+public enum HttpClientNames
+{
+ Default,
+}
diff --git a/TmsRunner/Extensions/StringExtension.cs b/TmsRunner/Extensions/StringExtension.cs
index 6bae3fc..9500089 100644
--- a/TmsRunner/Extensions/StringExtension.cs
+++ b/TmsRunner/Extensions/StringExtension.cs
@@ -1,26 +1,24 @@
using System.Security.Cryptography;
using System.Text;
-namespace TmsRunner.Extensions
+namespace TmsRunner.Extensions;
+
+public static class StringExtension
{
- public static class StringExtension
+ public static string AssignIfNullOrEmpty(this string str, string? value)
+ {
+ return string.IsNullOrWhiteSpace(value) ? str : value;
+ }
+
+ public static string ComputeHash(this string str)
{
- public static string AssignIfNullOrEmpty(this string str, string? value)
- {
- return string.IsNullOrWhiteSpace(value) ? str : value;
- }
+ var hash = SHA256.HashData(Encoding.UTF8.GetBytes(str));
- public static string ComputeHash(this string str)
- {
- var sha = SHA256.Create();
- var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(str));
-
- return BitConverter.ToUInt32(hash).ToString();
- }
+ return BitConverter.ToUInt32(hash).ToString();
+ }
- public static string RemoveQuotes(this string str)
- {
- return str.Replace("'", "").Replace("\"", "");
- }
+ public static string RemoveQuotes(this string str)
+ {
+ return str.Replace("'", "").Replace("\"", "");
}
}
\ No newline at end of file
diff --git a/TmsRunner/Handlers/DiscoveryEventHandler.cs b/TmsRunner/Handlers/DiscoveryEventHandler.cs
index b7336d0..2865511 100644
--- a/TmsRunner/Handlers/DiscoveryEventHandler.cs
+++ b/TmsRunner/Handlers/DiscoveryEventHandler.cs
@@ -1,35 +1,26 @@
+using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
-using Serilog;
-using TmsRunner.Logger;
namespace TmsRunner.Handlers;
-public class DiscoveryEventHandler : ITestDiscoveryEventsHandler
+public sealed class DiscoveryEventHandler(ILogger logger, AutoResetEvent waitHandle) : ITestDiscoveryEventsHandler
{
- private AutoResetEvent waitHandle;
- private readonly ILogger _logger;
- public List DiscoveredTestCases { get; }
+ public List DiscoveredTestCases { get; } = [];
- public DiscoveryEventHandler(AutoResetEvent waitHandle)
+ public void HandleDiscoveredTests(IEnumerable? discoveredTestCases)
{
- this.waitHandle = waitHandle;
- DiscoveredTestCases = new List();
- _logger = LoggerFactory.GetLogger().ForContext();
- }
-
- public void HandleDiscoveredTests(IEnumerable discoveredTestCases)
- {
- _logger.Debug("Discovery tests");
+ logger.LogDebug("Discovery tests");
- if (discoveredTestCases == null) return;
+ if (discoveredTestCases == null)
+ {
+ return;
+ }
DiscoveredTestCases.AddRange(discoveredTestCases);
- _logger.Debug(
- "Added test cases: {@TestCases}",
- discoveredTestCases.Select(t => t.FullyQualifiedName));
+ logger.LogDebug("Added test cases: {@TestCases}", discoveredTestCases.Select(t => t.FullyQualifiedName));
}
public void HandleDiscoveryComplete(long totalTests, IEnumerable? lastChunk, bool isAborted)
@@ -39,14 +30,19 @@ public void HandleDiscoveryComplete(long totalTests, IEnumerable? last
DiscoveredTestCases.AddRange(lastChunk);
}
- _logger.Debug("Discovery completed");
+ logger.LogDebug("Discovery completed");
+
+ _ = waitHandle.Set();
+ }
- waitHandle.Set();
+ public void WaitForEnd()
+ {
+ _ = waitHandle.WaitOne();
}
- public void HandleLogMessage(TestMessageLevel level, string message)
+ public void HandleLogMessage(TestMessageLevel level, string? message)
{
- _logger.Debug("Discovery Message: {Message}", message);
+ logger.LogDebug("Discovery Message: {Message}", message);
}
public void HandleRawMessage(string rawMessage)
diff --git a/TmsRunner/Handlers/RunEventHandler.cs b/TmsRunner/Handlers/RunEventHandler.cs
index a1f8ead..e1a1dbb 100644
--- a/TmsRunner/Handlers/RunEventHandler.cs
+++ b/TmsRunner/Handlers/RunEventHandler.cs
@@ -1,52 +1,40 @@
+using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
-using Serilog;
-using TmsRunner.Logger;
+using TmsRunner.Services;
namespace TmsRunner.Handlers;
-public class RunEventHandler : ITestRunEventsHandler2
+public sealed class RunEventHandler(ILogger logger, AutoResetEvent waitHandle, ProcessorService processorService) : ITestRunEventsHandler
{
- private AutoResetEvent waitHandle;
- private readonly ILogger _logger;
+ public List ProcessTestResultsTasks { get; } = [];
- public List TestResults { get;}
-
- public RunEventHandler(AutoResetEvent waitHandle)
- {
- this.waitHandle = waitHandle;
- TestResults = new List();
-
- _logger = LoggerFactory.GetLogger().ForContext();
- }
-
- public void HandleLogMessage(TestMessageLevel level, string message)
+ public void HandleLogMessage(TestMessageLevel level, string? message)
{
- _logger.Debug("Run Message: {Message}", message);
+ logger.LogDebug("Run Message: {Message}", message);
}
public void HandleTestRunComplete(
TestRunCompleteEventArgs testRunCompleteArgs,
- TestRunChangedEventArgs lastChunkArgs,
- ICollection runContextAttachments,
- ICollection executorUris)
+ TestRunChangedEventArgs? lastChunkArgs,
+ ICollection? runContextAttachments,
+ ICollection? executorUris)
{
if (lastChunkArgs != null && lastChunkArgs.NewTestResults != null)
{
- TestResults.AddRange(lastChunkArgs.NewTestResults);
+ ProcessTestResultsTasks.Add(ProcessTestResultsAsync(lastChunkArgs.NewTestResults));
}
- _logger.Debug("Test Run completed");
-
- waitHandle.Set();
+ logger.LogDebug("Test Run completed");
+ _ = waitHandle.Set();
}
- public void HandleTestRunStatsChange(TestRunChangedEventArgs testRunChangedArgs)
+ public void HandleTestRunStatsChange(TestRunChangedEventArgs? testRunChangedArgs)
{
if (testRunChangedArgs != null && testRunChangedArgs.NewTestResults != null)
{
- TestResults.AddRange(testRunChangedArgs.NewTestResults);
+ ProcessTestResultsTasks.Add(ProcessTestResultsAsync(testRunChangedArgs.NewTestResults));
}
}
@@ -66,4 +54,38 @@ public bool AttachDebuggerToProcess(int pid)
// No op
return false;
}
+
+ public void WaitForEnd()
+ {
+ _ = waitHandle.WaitOne();
+ }
+
+ private async Task ProcessTestResultsAsync(IEnumerable? testResults)
+ {
+ if (testResults == null || !testResults.Any())
+ {
+ return;
+ }
+
+ foreach (var testResult in testResults)
+ {
+ if (testResult == null)
+ {
+ continue;
+ }
+
+ logger.LogInformation("Uploading test {Name}", testResult.DisplayName);
+
+ try
+ {
+ await processorService.ProcessAutoTestAsync(testResult).ConfigureAwait(false);
+
+ logger.LogInformation("Uploaded test {Name}", testResult.DisplayName);
+ }
+ catch (Exception e)
+ {
+ logger.LogError(e, "Uploaded test {Name} is failed", testResult.DisplayName);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/TmsRunner/Logger/LoggerFactory.cs b/TmsRunner/Logger/LoggerFactory.cs
deleted file mode 100644
index 65c55ff..0000000
--- a/TmsRunner/Logger/LoggerFactory.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using Serilog;
-
-namespace TmsRunner.Logger;
-
-public static class LoggerFactory
-{
- private static ILogger _logger;
- private static readonly object Lock = new object();
-
- public static ILogger GetLogger(bool isDebug = false)
- {
- if (_logger != null) return _logger;
-
- lock (Lock)
- {
- if (_logger != null) return _logger;
-
- var logConfig = isDebug
- ? new LoggerConfiguration()
- .MinimumLevel.Debug()
- : new LoggerConfiguration();
-
- _logger = logConfig
- .Enrich.FromLogContext()
- .Enrich.WithThreadId()
- .WriteTo.Console(
- outputTemplate:
- "{Timestamp:HH:mm} [{Level}] ({ThreadId}) {SourceContext}: {Message}{NewLine}{Exception}")
- .CreateLogger();
-
- return _logger;
- }
- }
-}
\ No newline at end of file
diff --git a/TmsRunner/Models/AutoTest.cs b/TmsRunner/Models/AutoTest.cs
index e5196c2..308fd3b 100644
--- a/TmsRunner/Models/AutoTest.cs
+++ b/TmsRunner/Models/AutoTest.cs
@@ -1,23 +1,22 @@
using Tms.Adapter.Models;
-namespace TmsRunner.Models
+namespace TmsRunner.Models;
+
+public sealed record AutoTest
{
- public class AutoTest
- {
- public string Namespace { get; set; }
- public string Classname { get; set; }
- public List Steps { get; set; } = new();
- public List Setup { get; set; }
- public List Teardown { get; set; }
- public string ExternalId { get; set; }
- public string Name { get; set; }
- public string Title { get; set; }
- public string Description { get; set; }
- public List WorkItemIds { get; set; } = new();
- public List? Links { get; set; } = new();
- public List? Labels { get; set; }
- public string MethodName { get; set; }
- public string? Message { get; set; }
- public bool? IsFlaky { get; set; }
- }
+ public string? Namespace { get; set; }
+ public string? Classname { get; set; }
+ public List Steps { get; set; } = [];
+ public List? Setup { get; set; }
+ public List? Teardown { get; set; }
+ public string? ExternalId { get; set; }
+ public string? Name { get; set; }
+ public string? Title { get; set; }
+ public string? Description { get; set; }
+ public List WorkItemIds { get; set; } = [];
+ public List? Links { get; set; } = [];
+ public List? Labels { get; set; }
+ public string? MethodName { get; set; }
+ public string? Message { get; set; }
+ public bool? IsFlaky { get; set; }
}
\ No newline at end of file
diff --git a/TmsRunner/Models/AutoTestResult.cs b/TmsRunner/Models/AutoTestResult.cs
index c3ec7b1..b2105f6 100644
--- a/TmsRunner/Models/AutoTestResult.cs
+++ b/TmsRunner/Models/AutoTestResult.cs
@@ -3,19 +3,19 @@
namespace TmsRunner.Models;
-public class AutoTestResult
+public sealed record AutoTestResult
{
public List? Links { get; set; }
- public string Message { get; set; }
- public string ExternalId { get; set; }
- public TestOutcome Outcome { get; set; }
- public string Traces { get; set; }
+ public string? Message { get; set; }
+ public string? ExternalId { get; set; }
+ public TestOutcome? Outcome { get; set; }
+ public string? Traces { get; set; }
public DateTime? StartedOn { get; set; }
public DateTime? CompletedOn { get; set; }
public long? Duration { get; set; }
- public List Attachments { get; set; }
- public Dictionary Parameters { get; set; }
- public List StepResults { get; set; }
- public List SetupResults { get; set; }
- public List TeardownResults { get; set; }
+ public List? Attachments { get; set; }
+ public Dictionary? Parameters { get; set; }
+ public List? StepResults { get; set; }
+ public List? SetupResults { get; set; }
+ public List? TeardownResults { get; set; }
}
\ No newline at end of file
diff --git a/TmsRunner/Models/AutoTestStep.cs b/TmsRunner/Models/AutoTestStep.cs
index 48e681a..1995ed4 100644
--- a/TmsRunner/Models/AutoTestStep.cs
+++ b/TmsRunner/Models/AutoTestStep.cs
@@ -1,17 +1,17 @@
namespace TmsRunner.Models;
-public class AutoTestStep
+public sealed record AutoTestStep
{
- public string Title { get; set; }
- public string Description { get; set; }
- public List Steps { get; set; }
+ public string? Title { get; set; }
+ public string? Description { get; set; }
+ public List? Steps { get; set; }
public static AutoTestStep ConvertFromStep(Step step)
{
return new AutoTestStep
{
- Title = step.Title,
- Description = step.Description,
+ Title = step.Title ?? string.Empty,
+ Description = step.Description ?? string.Empty,
Steps = step.Steps.Select(ConvertFromStep).ToList()
};
}
diff --git a/TmsRunner/Models/AutoTestStepResult.cs b/TmsRunner/Models/AutoTestStepResult.cs
index c98e2f5..ee457b2 100644
--- a/TmsRunner/Models/AutoTestStepResult.cs
+++ b/TmsRunner/Models/AutoTestStepResult.cs
@@ -1,16 +1,16 @@
namespace TmsRunner.Models;
-public class AutoTestStepResult
+public sealed record AutoTestStepResult
{
public string? Title { get; set; }
public string? Description { get; set; }
public DateTime? StartedOn { get; set; }
public DateTime? CompletedOn { get; set; }
public long? Duration { get; set; }
- public List Attachments { get; set; }
+ public List? Attachments { get; set; }
public Dictionary? Parameters { get; set; }
- public List Steps { get; set; }
- public string Outcome { get; set; }
+ public List? Steps { get; set; }
+ public string? Outcome { get; set; }
public static AutoTestStepResult ConvertFromStep(Step step)
{
diff --git a/TmsRunner/Models/Config.cs b/TmsRunner/Models/Config.cs
index 6ea55a3..69abe78 100644
--- a/TmsRunner/Models/Config.cs
+++ b/TmsRunner/Models/Config.cs
@@ -1,28 +1,28 @@
namespace TmsRunner.Models;
-public class Config
+public sealed record Config
{
- public string TmsUrl { get; set; }
+ public string? TmsUrl { get; set; }
- public string TmsPrivateToken { get; set; }
+ public string? TmsPrivateToken { get; set; }
- public string TmsProjectId { get; set; }
+ public string? TmsProjectId { get; set; }
- public string TmsConfigurationId { get; set; }
+ public string? TmsConfigurationId { get; set; }
- public string TmsTestRunId { get; set; }
+ public string? TmsTestRunId { get; set; }
- public string TmsTestRunName { get; set; }
+ public string? TmsTestRunName { get; set; }
- public string TmsAdapterMode { get; set; }
+ public string? TmsAdapterMode { get; set; }
- public string TmsConfigFile { get; set; }
+ public string? TmsConfigFile { get; set; }
- public string TmsRunSettings { get; set; }
-
- public string TmsAutomaticCreationTestCases { get; set; }
+ public string? TmsRunSettings { get; set; }
- public string TmsCertValidation { get; set; }
+ public string? TmsAutomaticCreationTestCases { get; set; }
- public string TmsLabelsOfTestsToRun { get; set; }
+ public string? TmsCertValidation { get; set; }
+
+ public string? TmsLabelsOfTestsToRun { get; set; }
}
\ No newline at end of file
diff --git a/TmsRunner/Models/MessageMetadata.cs b/TmsRunner/Models/MessageMetadata.cs
index ba80098..ea0ed79 100644
--- a/TmsRunner/Models/MessageMetadata.cs
+++ b/TmsRunner/Models/MessageMetadata.cs
@@ -2,8 +2,8 @@
namespace TmsRunner.Models;
-public class MessageMetadata
+public sealed record MessageMetadata
{
public MessageType Type { get; set; }
- public string Value { get; set; }
+ public string? Value { get; set; }
}
\ No newline at end of file
diff --git a/TmsRunner/Models/MethodMetadata.cs b/TmsRunner/Models/MethodMetadata.cs
index 9e2b48f..4e6fdf1 100644
--- a/TmsRunner/Models/MethodMetadata.cs
+++ b/TmsRunner/Models/MethodMetadata.cs
@@ -1,9 +1,9 @@
namespace TmsRunner.Models;
-public class MethodMetadata
+public sealed record MethodMetadata
{
- public string Name { get; set; }
- public string Namespace { get; set; }
- public string Classname { get; set; }
- public List Attributes { get; set; }
-}
\ No newline at end of file
+ public string? Name { get; set; }
+ public string? Namespace { get; set; }
+ public string? Classname { get; set; }
+ public List? Attributes { get; set; }
+}
\ No newline at end of file
diff --git a/TmsRunner/Models/Step.cs b/TmsRunner/Models/Step.cs
index e51332a..1fa381a 100644
--- a/TmsRunner/Models/Step.cs
+++ b/TmsRunner/Models/Step.cs
@@ -1,39 +1,41 @@
using System.Text;
using Tms.Adapter.Models;
-namespace TmsRunner.Models
+namespace TmsRunner.Models;
+
+public sealed class Step : StepDto
{
- public class Step : StepDto
+ public string? Result { get; set; }
+ public DateTime? CompletedOn { get; set; }
+ public long Duration { get; set; }
+ public List Steps { get; set; } = [];
+ public Step? ParentStep { get; set; }
+ public int NestingLevel { get; set; }
+ public List Links { get; set; } = [];
+ public List Attachments { get; set; } = [];
+ public string? Outcome { get; set; }
+
+ private string? _stackTrace;
+
+ public string StackTrace()
{
- public string? Result { get; set; }
- public DateTime? CompletedOn { get; set; }
- public long Duration { get; set; }
- public List Steps { get; set; } = new();
- public Step? ParentStep { get; set; }
- public int NestingLevel { get; set; }
- public List Links { get; set; } = new();
- public List Attachments { get; set; } = new();
- public string Outcome { get; set; }
-
- string _stackTrace;
-
- public string StackTrace()
+ if (_stackTrace != null)
{
- if (_stackTrace != null) return _stackTrace;
+ return _stackTrace;
+ }
- var sb = new StringBuilder();
- var parent = ParentStep;
- sb.Append(CurrentMethod);
+ var sb = new StringBuilder();
+ var parent = ParentStep;
+ _ = sb.Append(CurrentMethod);
- while (parent != null)
- {
- sb.Insert(0, parent.CurrentMethod + Environment.NewLine);
- parent = parent.ParentStep;
- }
+ while (parent != null)
+ {
+ _ = sb.Insert(0, parent.CurrentMethod + Environment.NewLine);
+ parent = parent.ParentStep;
+ }
- _stackTrace = sb.ToString();
+ _stackTrace = sb.ToString();
- return _stackTrace;
- }
+ return _stackTrace;
}
}
\ No newline at end of file
diff --git a/TmsRunner/Models/TmsSettings.cs b/TmsRunner/Models/TmsSettings.cs
index 5e60c84..5ed9f63 100644
--- a/TmsRunner/Models/TmsSettings.cs
+++ b/TmsRunner/Models/TmsSettings.cs
@@ -1,6 +1,6 @@
namespace TmsRunner.Models;
-public class TmsSettings
+public sealed class TmsSettings
{
private string? _url;
@@ -10,13 +10,13 @@ public string? Url
set => _url = value;
}
- public string PrivateToken { get; set; }
- public string ProjectId { get; set; }
- public string ConfigurationId { get; set; }
- public string TestRunId { get; set; }
- public string TestRunName { get; set; }
+ public string? PrivateToken { get; set; }
+ public string? ProjectId { get; set; }
+ public string? ConfigurationId { get; set; }
+ public string? TestRunId { get; set; }
+ public string? TestRunName { get; set; }
public int AdapterMode { get; set; }
- public string RunSettings { get; set; }
+ public string? RunSettings { get; set; }
public bool AutomaticCreationTestCases { get; set; }
public bool CertValidation { get; set; }
}
\ No newline at end of file
diff --git a/TmsRunner/Program.cs b/TmsRunner/Program.cs
index f0d6367..40c3173 100644
--- a/TmsRunner/Program.cs
+++ b/TmsRunner/Program.cs
@@ -1,116 +1,49 @@
using CommandLine;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.TestPlatform.VsTestConsole.TranslationLayer;
+using Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces;
+using Polly;
+using Polly.Extensions.Http;
+using Polly.Retry;
+using Serilog;
+using Serilog.Events;
+using Serilog.Expressions;
+using Serilog.Settings.Configuration;
+using System.Net;
+using TestIT.ApiClient.Api;
using Tms.Adapter.Utils;
using TmsRunner.Client;
using TmsRunner.Configuration;
+using TmsRunner.Enums;
using TmsRunner.Extensions;
-using TmsRunner.Logger;
-using TmsRunner.Options;
+using TmsRunner.Handlers;
+using TmsRunner.Models;
using TmsRunner.Services;
using TmsRunner.Utils;
+using ConfigurationManager = TmsRunner.Configuration.ConfigurationManager;
namespace TmsRunner;
-internal class Program
+public class Program
{
public static async Task Main(string[] args)
{
- var config = GetAdapterConfiguration(args);
- var settings = ConfigurationManager.Configure(config.ToInternalConfig(),
- Path.GetDirectoryName(config.TestAssemblyPath)!);
-
- var log = LoggerFactory.GetLogger(config.IsDebug).ForContext();
-
- log.Information("Adapter works in {Mode} mode", settings.AdapterMode);
- log.Debug("Parameters:");
- log.Debug("Runner Path: {Path}", config.RunnerPath);
- log.Debug("Test Assembly Path: {Path}", config.TestAssemblyPath);
- log.Debug("Test Adapter Path: {Path}", config.TestAdapterPath);
- log.Debug("Test Logger Path: {Path}", config.LoggerPath);
-
- var runner = new Runner(config);
- runner.InitialiseRunner();
-
- var testCases = runner.DiscoverTests();
-
- log.Information("Discovered Tests Count: {Count}", testCases.Count);
-
- if (testCases.Count == 0)
- {
- log.Information("Can not found tests for run");
- return 1;
- }
-
- ITmsClient apiClient = new TmsClient(settings);
-
- var replacer = new Replacer();
- var filterService = new FilterService(replacer);
-
- switch (settings.AdapterMode)
- {
- case 0:
- {
- var testCaseForRun = await apiClient.GetAutoTestsForRun(settings.TestRunId);
- testCases = filterService.FilterTestCases(config.TestAssemblyPath, testCaseForRun, testCases);
- break;
- }
- case 2:
- {
- settings.TestRunId = await apiClient.CreateTestRun();
-
- if (!string.IsNullOrEmpty(config.TmsLabelsOfTestsToRun))
- {
- testCases = filterService.FilterTestCasesByLabels(config, testCases);
- }
-
- break;
- }
- }
-
- log.Information("Running tests: {Count}", testCases.Count);
-
- var testResults = runner.RunSelectedTests(testCases);
-
- log.Debug("Run Selected Test Result: {@Results}",
- testResults.Select(t => t.DisplayName));
-
- var reflector = new Reflector();
- var parser = new LogParser(replacer, reflector);
- var processorService =
- new ProcessorService(apiClient, settings, parser);
-
- foreach (var testResult in testResults)
- {
- log.Information("Uploading test {Name}", testResult.DisplayName);
-
- try
- {
- await processorService.ProcessAutoTest(testResult);
-
- log.Information("Uploaded test {Name}", testResult.DisplayName);
- }
- catch (Exception e)
- {
- log.Error(e, "Uploaded test {Name} is failed", testResult.DisplayName);
- }
- }
-
- if (settings.AdapterMode == 2)
- log.Information("Test run {TestRunId} finished.", settings.TestRunId);
-
- return 0;
+ using var host = CreateHostBuilder(args).Build();
+ return await host.Services.GetRequiredService().RunAsync().ConfigureAwait(false);
}
private static AdapterConfig GetAdapterConfiguration(IEnumerable args)
{
AdapterConfig config = null!;
- Parser.Default.ParseArguments(args)
+ _ = Parser.Default.ParseArguments(args)
.WithParsed(ac =>
{
config = new AdapterConfig
{
- RunnerPath = ac.RunnerPath.RemoveQuotes(),
- TestAssemblyPath = ac.TestAssemblyPath.RemoveQuotes(),
+ RunnerPath = ac.RunnerPath?.RemoveQuotes(),
+ TestAssemblyPath = ac.TestAssemblyPath?.RemoveQuotes(),
TestAdapterPath = ac.TestAdapterPath?.RemoveQuotes() ?? string.Empty,
LoggerPath = ac.LoggerPath?.RemoveQuotes() ?? string.Empty,
IsDebug = ac.IsDebug,
@@ -125,7 +58,108 @@ private static AdapterConfig GetAdapterConfiguration(IEnumerable args)
TmsLabelsOfTestsToRun = ac.TmsLabelsOfTestsToRun
};
});
-
+
+ if (string.IsNullOrWhiteSpace(config.TmsRunSettings))
+ {
+ config.TmsRunSettings =
+ @"
+
+
+
+
+";
+ }
+
return config;
}
+
+ private static IHostBuilder CreateHostBuilder(string[] args)
+ {
+ var options = new ConfigurationReaderOptions(
+ typeof(ConsoleLoggerConfigurationExtensions).Assembly,
+ typeof(SerilogExpression).Assembly
+ );
+
+ return Host.CreateDefaultBuilder()
+ .UseSerilog((context, services, configuration) => configuration
+ .ReadFrom.Configuration(context.Configuration, options)
+ .ReadFrom.Services(services)
+ .Enrich.FromLogContext()
+ .MinimumLevel.Debug()
+ .WriteTo.Console(LogEventLevel.Information))
+ .ConfigureServices((hostContext, services) =>
+ {
+ _ = services.AddHttpClient(nameof(HttpClientNames.Default), client =>
+ {
+ client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher;
+ client.DefaultRequestVersion = HttpVersion.Version11;
+ })
+ .SetHandlerLifetime(TimeSpan.FromDays(1))
+ .AddPolicyHandler(GetRetryPolicy());
+
+ _ = services
+ .AddSingleton(GetAdapterConfiguration(args))
+ .AddSingleton(provider =>
+ {
+ var adapterConfig = provider.GetRequiredService();
+
+ return ConfigurationManager.Configure(
+ adapterConfig.ToInternalConfig(),
+ Path.GetDirectoryName(adapterConfig.TestAssemblyPath) ?? string.Empty
+ );
+ })
+ .AddSingleton(provider =>
+ {
+ var tmsSettings = provider.GetRequiredService();
+
+ return new TestIT.ApiClient.Client.Configuration
+ {
+ BasePath = tmsSettings.Url ?? string.Empty,
+ ApiKeyPrefix = new Dictionary { { "Authorization", "PrivateToken" } },
+ ApiKey = new Dictionary { { "Authorization", tmsSettings?.PrivateToken ?? string.Empty } }
+ };
+ })
+ .AddTransient(provider => new HttpClientHandler
+ {
+ ServerCertificateCustomValidationCallback = (_, _, _, _) => provider.GetRequiredService().CertValidation
+ })
+ .AddTransient(provider => new AttachmentsApi(
+ provider.GetRequiredService().CreateClient(nameof(HttpClientNames.Default)),
+ provider.GetRequiredService(),
+ provider.GetRequiredService()
+ ))
+ .AddTransient(provider => new TestRunsApi(
+ provider.GetRequiredService().CreateClient(nameof(HttpClientNames.Default)),
+ provider.GetRequiredService(),
+ provider.GetRequiredService()
+ ))
+ .AddTransient(provider => new AutoTestsApi(
+ provider.GetRequiredService().CreateClient(nameof(HttpClientNames.Default)),
+ provider.GetRequiredService(),
+ provider.GetRequiredService()
+ ))
+ .AddTransient()
+ .AddTransient()
+ .AddTransient()
+ .AddTransient()
+ .AddTransient()
+ .AddTransient()
+ .AddTransient()
+ .AddTransient(provider => new AutoResetEvent(false))
+ .AddTransient()
+ .AddTransient()
+ .AddTransient(provider => new VsTestConsoleWrapper(
+ provider.GetRequiredService().RunnerPath ?? string.Empty,
+ new ConsoleParameters { LogFilePath = Path.Combine(Directory.GetCurrentDirectory(), @"log.txt") }
+ ))
+ .AddSingleton();
+ });
+ }
+
+ private static AsyncRetryPolicy GetRetryPolicy()
+ {
+ return HttpPolicyExtensions
+ .HandleTransientHttpError()
+ .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
+ }
}
\ No newline at end of file
diff --git a/TmsRunner/Runner.cs b/TmsRunner/Runner.cs
deleted file mode 100644
index 6e65d32..0000000
--- a/TmsRunner/Runner.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using Microsoft.TestPlatform.VsTestConsole.TranslationLayer;
-using Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
-using Serilog;
-using TmsRunner.Handlers;
-using TmsRunner.Logger;
-using TmsRunner.Options;
-
-namespace TmsRunner;
-
-public class Runner
-{
- private const string DefaultRunSettings =
- @"
-
-
-
-
-";
-
- private readonly AdapterConfig _config;
- private readonly ILogger _logger;
- private readonly IVsTestConsoleWrapper _consoleWrapper;
- private readonly string _runSettings;
-
- public Runner(AdapterConfig config)
- {
- _config = config;
- _logger = LoggerFactory.GetLogger().ForContext();
- _consoleWrapper = new VsTestConsoleWrapper(config.RunnerPath,
- new ConsoleParameters { LogFilePath = Path.Combine(Directory.GetCurrentDirectory(), @"log.txt") });
- _runSettings = string.IsNullOrWhiteSpace(_config.TmsRunSettings) ? DefaultRunSettings : _config.TmsRunSettings;
- }
-
- public void InitialiseRunner()
- {
- _consoleWrapper.StartSession();
-
- _logger.Information("Start session");
-
- var extensions = new List();
-
- if (File.Exists(_config.TestAdapterPath))
- {
- extensions.Add(_config.TestAdapterPath);
-
- _logger.Debug("Added test adapter extension");
- }
-
- if (File.Exists(_config.LoggerPath))
- {
- extensions.Add(_config.LoggerPath);
-
- _logger.Debug("Added logger extension");
- }
-
- if (extensions.Count > 0)
- {
- _consoleWrapper.InitializeExtensions(extensions);
- }
- }
-
- public List DiscoverTests()
- {
- var waitHandle = new AutoResetEvent(false);
- var handler = new DiscoveryEventHandler(waitHandle);
-
- _consoleWrapper.DiscoverTests(new List { _config.TestAssemblyPath }, _runSettings, handler);
-
- waitHandle.WaitOne();
-
- return handler.DiscoveredTestCases;
- }
-
- public List RunSelectedTests(IEnumerable testCases)
- {
- var waitHandle = new AutoResetEvent(false);
- var handler = new RunEventHandler(waitHandle);
-
- _consoleWrapper.RunTests(testCases, _runSettings, handler);
-
- waitHandle.WaitOne();
-
- return handler.TestResults;
- }
-}
\ No newline at end of file
diff --git a/TmsRunner/Services/FilterService.cs b/TmsRunner/Services/FilterService.cs
index 6877e06..757f56f 100644
--- a/TmsRunner/Services/FilterService.cs
+++ b/TmsRunner/Services/FilterService.cs
@@ -1,36 +1,27 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using System.Data;
using System.Reflection;
using System.Text.RegularExpressions;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
-using Serilog;
using Tms.Adapter.Attributes;
using Tms.Adapter.Utils;
+using TmsRunner.Configuration;
using TmsRunner.Extensions;
-using TmsRunner.Logger;
-using TmsRunner.Options;
namespace TmsRunner.Services;
-public class FilterService
+public sealed class FilterService(ILogger logger, Replacer replacer)
{
- private readonly Replacer _replacer;
- private readonly ILogger _log;
- private static readonly Regex _parametersRegex = new Regex("\\((.*)\\)");
-
- public FilterService(Replacer replacer)
- {
- _replacer = replacer;
- _log = LoggerFactory.GetLogger(false).ForContext();
- }
+ private static readonly Regex _parametersRegex = new("\\((.*)\\)");
// TODO: write unit tests
public List FilterTestCases(
- string assemblyPath,
- IEnumerable externalIds,
+ string? assemblyPath,
+ IEnumerable? externalIds,
IEnumerable testCases)
{
var testCasesToRun = new List();
- var assembly = Assembly.LoadFrom(assemblyPath);
+ var assembly = Assembly.LoadFrom(assemblyPath ?? string.Empty);
var allTestMethods = new List(assembly.GetExportedTypes().SelectMany(type => type.GetMethods()));
foreach (var testCase in testCases)
@@ -41,13 +32,13 @@ public List FilterTestCases(
if (testMethod == null)
{
- _log.Error("TestMethod {@FullyQualifiedName} not found", testCase.FullyQualifiedName);
+ logger.LogError("TestMethod {@FullyQualifiedName} not found", testCase.FullyQualifiedName);
continue;
}
var externalId = GetExternalId(testCase, testMethod);
- if (externalIds.Contains(externalId))
+ if (externalIds?.Contains(externalId) ?? false)
{
testCasesToRun.Add(testCase);
}
@@ -67,9 +58,10 @@ private string GetExternalId(TestCase testCase, MethodInfo testMethod)
var parameterNames = testMethod.GetParameters().Select(x => x.Name?.ToString());
var parameterValues = _parametersRegex.Match(testCase.DisplayName).Groups[1].Value.Split(',').Select(x => x.Replace("\"", string.Empty));
var parameterDictionary = parameterNames
+ .Select(x => x ?? string.Empty)
.Zip(parameterValues, (k, v) => new { k, v })
.ToDictionary(x => x.k, x => x.v);
- return _replacer.ReplaceParameters(externalId.Value, parameterDictionary!);
+ return replacer.ReplaceParameters(externalId.Value, parameterDictionary!);
}
}
@@ -80,10 +72,10 @@ public List FilterTestCasesByLabels(
AdapterConfig config,
IEnumerable testCases)
{
- var labelsToRun = config.TmsLabelsOfTestsToRun.Split(',').Select(x => x.Trim()).ToList();
+ var labelsToRun = config.TmsLabelsOfTestsToRun?.Split(',').Select(x => x.Trim()).ToList();
var testCasesName = testCases.Select(t => t.FullyQualifiedName);
var testCasesToRun = new List();
- var assembly = Assembly.LoadFrom(config.TestAssemblyPath);
+ var assembly = Assembly.LoadFrom(config.TestAssemblyPath ?? string.Empty);
var testMethods = new List(
assembly.GetExportedTypes()
.SelectMany(type => type.GetMethods())
@@ -92,18 +84,24 @@ public List FilterTestCasesByLabels(
foreach (var testMethod in testMethods)
{
- var fullName = testMethod.DeclaringType!.FullName + "." + testMethod.Name;
+ var fullName = testMethod?.DeclaringType?.FullName + "." + testMethod?.Name;
+ var customAttributes = testMethod?.GetCustomAttributes(false) ?? [];
- foreach (var attribute in testMethod.GetCustomAttributes(false))
+ foreach (var attribute in customAttributes)
{
if (attribute is LabelsAttribute labelsAttr)
{
- if (labelsAttr.Value.Any(labelsToRun.Contains))
+ if (labelsAttr.Value?.Any(x => labelsToRun?.Contains(x) ?? false) ?? false)
{
- testCasesToRun.Add(testCases.FirstOrDefault(x => x.FullyQualifiedName == fullName));
+ var testCase = testCases.FirstOrDefault(x => x.FullyQualifiedName == fullName);
+
+ if (testCase != null)
+ {
+ testCasesToRun.Add(testCase);
+ }
}
}
- }
+ }
}
return testCasesToRun;
diff --git a/TmsRunner/Services/ProcessorService.cs b/TmsRunner/Services/ProcessorService.cs
index 471e575..0016202 100644
--- a/TmsRunner/Services/ProcessorService.cs
+++ b/TmsRunner/Services/ProcessorService.cs
@@ -1,53 +1,36 @@
-using System.Text;
+using Microsoft.Extensions.Logging;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
-using Serilog;
using Tms.Adapter.Models;
using TmsRunner.Client;
-using TmsRunner.Logger;
using TmsRunner.Models;
using TmsRunner.Utils;
using File = Tms.Adapter.Models.File;
-namespace TmsRunner.Services
+namespace TmsRunner.Services;
+
+public sealed class ProcessorService(ILogger logger, ITmsClient apiClient, TmsSettings tmsSettings, LogParser parser)
{
- public class ProcessorService
+ private async Task> GetStepsWithAttachmentsAsync(string? traceJson, ICollection attachmentIds)
{
- private readonly ITmsClient _apiClient;
- private readonly TmsSettings _tmsSettings;
- private readonly LogParser _parser;
- private readonly ILogger _logger = LoggerFactory.GetLogger().ForContext();
-
- public ProcessorService(
- ITmsClient apiClient,
- TmsSettings tmsSettings,
- LogParser parser)
- {
- _apiClient = apiClient;
- _tmsSettings = tmsSettings;
- _parser = parser;
- }
-
- private async Task> GetStepsWithAttachments(
- string? traceJson, ICollection attachmentIds)
- {
- var messages = _parser.GetMessages(traceJson);
+ var messages = parser.GetMessages(traceJson ?? string.Empty);
- var testCaseStepsHierarchical = new List();
- Step? parentStep = null;
- var nestingLevel = 1;
+ var testCaseStepsHierarchical = new List();
+ Step? parentStep = null;
+ var nestingLevel = 1;
- foreach (var message in messages)
+ foreach (var message in messages)
+ {
+ switch (message.Type)
{
- switch (message.Type)
- {
- case MessageType.TmsStep:
+ case MessageType.TmsStep:
{
- var step = JsonSerializer.Deserialize(message.Value);
+ var step = JsonSerializer.Deserialize(message?.Value ?? string.Empty);
if (step == null)
{
- _logger.Warning("Can not deserialize step: {Step}", message.Value);
+ logger.LogWarning("Can not deserialize step: {Step}", message?.Value);
break;
}
@@ -89,13 +72,13 @@ private async Task> GetStepsWithAttachments(
break;
}
- case MessageType.TmsStepResult:
+ case MessageType.TmsStepResult:
{
- var stepResult = JsonSerializer.Deserialize(message.Value);
+ var stepResult = JsonSerializer.Deserialize(message?.Value ?? string.Empty);
if (stepResult == null)
{
- _logger.Warning("Can not deserialize step result: {StepResult}", message.Value);
+ logger.LogWarning("Can not deserialize step result: {StepResult}", message?.Value ?? string.Empty);
break;
}
@@ -108,12 +91,12 @@ private async Task> GetStepsWithAttachments(
break;
}
- case MessageType.TmsStepAttachmentAsText:
+ case MessageType.TmsStepAttachmentAsText:
{
- var attachment = JsonSerializer.Deserialize(message.Value);
+ var attachment = JsonSerializer.Deserialize(message?.Value ?? string.Empty);
using var ms = new MemoryStream(Encoding.UTF8.GetBytes(attachment!.Content));
var createdAttachment =
- await _apiClient.UploadAttachment(Path.GetFileName(attachment.Name), ms);
+ await apiClient.UploadAttachmentAsync(Path.GetFileName(attachment.Name), ms).ConfigureAwait(false);
if (parentStep is not null)
{
@@ -129,14 +112,14 @@ private async Task> GetStepsWithAttachments(
break;
}
- case MessageType.TmsStepAttachment:
+ case MessageType.TmsStepAttachment:
{
- var file = JsonSerializer.Deserialize(message.Value);
+ var file = JsonSerializer.Deserialize(message?.Value ?? string.Empty);
if (System.IO.File.Exists(file!.PathToFile))
{
using var fs = new FileStream(file.PathToFile, FileMode.Open, FileAccess.Read);
- var attachment = await _apiClient.UploadAttachment(Path.GetFileName(file.PathToFile), fs);
+ var attachment = await apiClient.UploadAttachmentAsync(Path.GetFileName(file.PathToFile), fs).ConfigureAwait(false);
if (parentStep is not null)
{
@@ -153,150 +136,151 @@ private async Task> GetStepsWithAttachments(
break;
}
- default:
- _logger.Debug("Un support message type: {MessageType}", message.Type);
- break;
- }
+ default:
+ logger.LogDebug("Un support message type: {MessageType}", message.Type);
+ break;
}
-
- return testCaseStepsHierarchical;
}
- private static string? GetCalledMethod(string? calledMethod)
- {
- if (calledMethod == null || !calledMethod.Contains("<")) return calledMethod;
-
- const string pattern = "(?<=\\<)(.*)(?=\\>)";
- var regex = new Regex(pattern);
- var match = regex.Match(calledMethod);
+ return testCaseStepsHierarchical;
+ }
- return match.Groups[1].Value;
+ private static string? GetCalledMethod(string? calledMethod)
+ {
+ if (calledMethod == null || !calledMethod.Contains('<'))
+ {
+ return calledMethod;
}
- public async Task ProcessAutoTest(TestResult testResult)
- {
- var traceJson = GetTraceJson(testResult);
- var parameters = _parser.GetParameters(traceJson);
- var autoTest = _parser.GetAutoTest(testResult, parameters);
- autoTest.Message = _parser.GetMessage(traceJson);
+ const string pattern = "(?<=\\<)(.*)(?=\\>)";
+ var regex = new Regex(pattern);
+ var match = regex.Match(calledMethod);
- var attachmentIds = new List();
- var testCaseSteps =
- await GetStepsWithAttachments(traceJson, attachmentIds);
+ return match.Groups[1].Value;
+ }
- autoTest.Setup = testCaseSteps
- .Where(x => x.CallerMethodType == CallerMethodType.Setup)
- .Select(AutoTestStep.ConvertFromStep)
- .ToList();
+ public async Task ProcessAutoTestAsync(TestResult testResult)
+ {
+ var traceJson = GetTraceJson(testResult);
+ var parameters = parser.GetParameters(traceJson);
+ var autoTest = parser.GetAutoTest(testResult, parameters);
+ autoTest.Message = LogParser.GetMessage(traceJson);
- autoTest.Steps = testCaseSteps
- .Where(x => x.CallerMethodType == CallerMethodType.TestMethod)
- .Select(AutoTestStep.ConvertFromStep)
- .ToList();
+ var attachmentIds = new List();
+ var testCaseSteps = await GetStepsWithAttachmentsAsync(traceJson, attachmentIds).ConfigureAwait(false);
- autoTest.Teardown = testCaseSteps
- .Where(x => x.CallerMethodType == CallerMethodType.Teardown)
- .Select(AutoTestStep.ConvertFromStep)
- .ToList();
+ autoTest.Setup = testCaseSteps
+ .Where(x => x.CallerMethodType == CallerMethodType.Setup)
+ .Select(AutoTestStep.ConvertFromStep)
+ .ToList();
+ autoTest.Steps = testCaseSteps
+ .Where(x => x.CallerMethodType == CallerMethodType.TestMethod)
+ .Select(AutoTestStep.ConvertFromStep)
+ .ToList();
- var existAutotest = await _apiClient.GetAutotestByExternalId(autoTest.ExternalId);
+ autoTest.Teardown = testCaseSteps
+ .Where(x => x.CallerMethodType == CallerMethodType.Teardown)
+ .Select(AutoTestStep.ConvertFromStep)
+ .ToList();
- if (existAutotest == null)
- {
- existAutotest = await _apiClient.CreateAutotest(autoTest);
- }
- else
- {
- autoTest.IsFlaky = existAutotest.IsFlaky;
- await _apiClient.UpdateAutotest(autoTest);
- }
+ var existAutotest = await apiClient.GetAutotestByExternalIdAsync(autoTest.ExternalId).ConfigureAwait(false);
- if (autoTest.WorkItemIds.Count > 0)
- {
- if (!await _apiClient.TryLinkAutoTestToWorkItem(existAutotest.Id.ToString(), autoTest.WorkItemIds))
- {
- return;
- }
- }
+ if (existAutotest == null)
+ {
+ existAutotest = await apiClient.CreateAutotestAsync(autoTest).ConfigureAwait(false);
+ }
+ else
+ {
+ autoTest.IsFlaky = existAutotest.IsFlaky;
- if (!string.IsNullOrEmpty(testResult.ErrorMessage))
+ await apiClient.UpdateAutotestAsync(autoTest).ConfigureAwait(false);
+ }
+
+ if (autoTest.WorkItemIds.Count > 0)
+ {
+ if (!await apiClient.TryLinkAutoTestToWorkItemAsync(existAutotest.Id.ToString(), autoTest.WorkItemIds).ConfigureAwait(false))
{
- autoTest.Message += Environment.NewLine + testResult.ErrorMessage;
+ return;
}
-
- var autoTestResultRequestBody = GetAutoTestResultsForTestRunModel(testResult, testCaseSteps, autoTest,
- traceJson, parameters, attachmentIds);
-
- await _apiClient.SubmitResultToTestRun(_tmsSettings.TestRunId, autoTestResultRequestBody);
}
- private AutoTestResult GetAutoTestResultsForTestRunModel(TestResult testResult,
- IReadOnlyCollection testCaseSteps,
- AutoTest autoTest, string traceJson, Dictionary? parameters,
- List attachmentIds)
+ if (!string.IsNullOrEmpty(testResult.ErrorMessage))
{
- var stepResults =
- testCaseSteps
- .Where(x => x.CallerMethodType == CallerMethodType.TestMethod)
- .Select(AutoTestStepResult.ConvertFromStep).ToList();
+ autoTest.Message += Environment.NewLine + testResult.ErrorMessage;
+ }
- var setupResults =
- testCaseSteps
- .Where(x => x.CallerMethodType == CallerMethodType.Setup)
- .Select(AutoTestStepResult.ConvertFromStep).ToList();
+ var autoTestResultRequestBody = GetAutoTestResultsForTestRunModel(testResult, testCaseSteps, autoTest,
+ traceJson, parameters, attachmentIds);
- var teardownResults =
- testCaseSteps
- .Where(x => x.CallerMethodType == CallerMethodType.Teardown)
- .Select(AutoTestStepResult.ConvertFromStep).ToList();
+ await apiClient.SubmitResultToTestRunAsync(tmsSettings.TestRunId, autoTestResultRequestBody).ConfigureAwait(false);
+ }
+ private AutoTestResult GetAutoTestResultsForTestRunModel(TestResult testResult,
+ IReadOnlyCollection testCaseSteps,
+ AutoTest autoTest, string traceJson, Dictionary? parameters,
+ List attachmentIds)
+ {
+ var stepResults =
+ testCaseSteps
+ .Where(x => x.CallerMethodType == CallerMethodType.TestMethod)
+ .Select(AutoTestStepResult.ConvertFromStep).ToList();
- var autoTestResultRequestBody = new AutoTestResult
- {
- ExternalId = autoTest.ExternalId,
- Outcome = testResult.Outcome,
- StartedOn = testResult.StartTime.UtcDateTime,
- CompletedOn = testResult.EndTime.UtcDateTime,
- Duration = (long)testResult.Duration.TotalMilliseconds,
- StepResults = stepResults,
- SetupResults = setupResults,
- TeardownResults = teardownResults,
- Links = _parser.GetLinks(traceJson),
- Message = autoTest.Message!.TrimStart(Environment.NewLine.ToCharArray()),
- Parameters = parameters!,
- Attachments = attachmentIds,
- };
- if (!string.IsNullOrEmpty(testResult.ErrorStackTrace))
- {
- autoTestResultRequestBody.Traces = testResult.ErrorStackTrace.TrimStart();
- }
+ var setupResults =
+ testCaseSteps
+ .Where(x => x.CallerMethodType == CallerMethodType.Setup)
+ .Select(AutoTestStepResult.ConvertFromStep).ToList();
- return autoTestResultRequestBody;
- }
+ var teardownResults =
+ testCaseSteps
+ .Where(x => x.CallerMethodType == CallerMethodType.Teardown)
+ .Select(AutoTestStepResult.ConvertFromStep).ToList();
- private static string GetTraceJson(TestResult testResult)
- {
- var debugTraceMessages = testResult.Messages.Select(x => x.Text);
- var traceJson = string.Join("\n", debugTraceMessages);
- return traceJson;
+ var autoTestResultRequestBody = new AutoTestResult
+ {
+ ExternalId = autoTest.ExternalId,
+ Outcome = testResult.Outcome,
+ StartedOn = testResult.StartTime.UtcDateTime,
+ CompletedOn = testResult.EndTime.UtcDateTime,
+ Duration = (long)testResult.Duration.TotalMilliseconds,
+ StepResults = stepResults,
+ SetupResults = setupResults,
+ TeardownResults = teardownResults,
+ Links = LogParser.GetLinks(traceJson),
+ Message = autoTest.Message!.TrimStart(Environment.NewLine.ToCharArray()),
+ Parameters = parameters!,
+ Attachments = attachmentIds,
+ };
+ if (!string.IsNullOrEmpty(testResult.ErrorStackTrace))
+ {
+ autoTestResultRequestBody.Traces = testResult.ErrorStackTrace.TrimStart();
}
- private static Step? MapStep(Step? step, StepResult stepResult)
- {
- if (step == null)
- {
- return null;
- }
+ return autoTestResultRequestBody;
+ }
- step.CompletedOn = stepResult.CompletedOn;
- step.Duration = stepResult.Duration;
- step.Result = stepResult.Result;
- step.Outcome = stepResult.Outcome;
+ private static string GetTraceJson(TestResult testResult)
+ {
+ var debugTraceMessages = testResult.Messages.Select(x => x.Text);
+ var traceJson = string.Join("\n", debugTraceMessages);
+
+ return traceJson;
+ }
- return step;
+ private static Step? MapStep(Step? step, StepResult stepResult)
+ {
+ if (step == null)
+ {
+ return null;
}
+
+ step.CompletedOn = stepResult.CompletedOn;
+ step.Duration = stepResult.Duration;
+ step.Result = stepResult.Result;
+ step.Outcome = stepResult.Outcome;
+
+ return step;
}
}
\ No newline at end of file
diff --git a/TmsRunner/Services/Runner.cs b/TmsRunner/Services/Runner.cs
new file mode 100644
index 0000000..e2b22d1
--- /dev/null
+++ b/TmsRunner/Services/Runner.cs
@@ -0,0 +1,53 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using TmsRunner.Configuration;
+using TmsRunner.Handlers;
+
+namespace TmsRunner.Services;
+
+public sealed class Runner(ILogger logger, AdapterConfig config, IVsTestConsoleWrapper consoleWrapper, DiscoveryEventHandler discoveryEventHandler, RunEventHandler runEventHandler)
+{
+ public void InitialiseRunner()
+ {
+ consoleWrapper.StartSession();
+
+ logger.LogInformation("Start session");
+
+ var extensions = new List();
+
+ if (File.Exists(config.TestAdapterPath))
+ {
+ extensions.Add(config.TestAdapterPath);
+
+ logger.LogDebug("Added test adapter extension");
+ }
+
+ if (File.Exists(config.LoggerPath))
+ {
+ extensions.Add(config.LoggerPath);
+
+ logger.LogDebug("Added logger extension");
+ }
+
+ if (extensions.Count > 0)
+ {
+ consoleWrapper.InitializeExtensions(extensions);
+ }
+ }
+
+ public List DiscoverTests()
+ {
+ consoleWrapper.DiscoverTests([config.TestAssemblyPath ?? string.Empty], config.TmsRunSettings, discoveryEventHandler);
+ discoveryEventHandler.WaitForEnd();
+
+ return discoveryEventHandler.DiscoveredTestCases;
+ }
+
+ public async Task RunSelectedTestsAsync(IEnumerable testCases)
+ {
+ consoleWrapper.RunTests(testCases, config.TmsRunSettings, runEventHandler);
+ runEventHandler.WaitForEnd();
+ await Task.WhenAll(runEventHandler.ProcessTestResultsTasks).ConfigureAwait(false);
+ }
+}
\ No newline at end of file
diff --git a/TmsRunner/TmsRunner.csproj b/TmsRunner/TmsRunner.csproj
index 17aac8e..9d11e52 100644
--- a/TmsRunner/TmsRunner.csproj
+++ b/TmsRunner/TmsRunner.csproj
@@ -19,24 +19,19 @@
-
-
-
-
-
-
-
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
+
+
+
+
+
@@ -44,10 +39,6 @@
-
-
-
-
Always
diff --git a/TmsRunner/Utils/Converter.cs b/TmsRunner/Utils/Converter.cs
new file mode 100644
index 0000000..4629a4e
--- /dev/null
+++ b/TmsRunner/Utils/Converter.cs
@@ -0,0 +1,120 @@
+using TestIT.ApiClient.Model;
+using TmsRunner.Models;
+
+namespace TmsRunner.Utils;
+
+public sealed class Converter
+{
+ public static CreateAutoTestRequest ConvertAutoTestDtoToPostModel(AutoTest dto, string? projectId)
+ {
+ var links = dto.Links?.Select(l =>
+ new LinkPostModel(
+ l.Title,
+ l.Url,
+ l.Description,
+ Enum.Parse(l.Type.ToString()!))
+ ).ToList();
+
+ return new CreateAutoTestRequest(externalId: dto.ExternalId ?? string.Empty, name: dto.Name ?? string.Empty)
+ {
+ ExternalId = dto.ExternalId ?? string.Empty,
+ Links = links!,
+ ProjectId = new Guid(projectId ?? string.Empty),
+ Namespace = dto.Namespace ?? string.Empty,
+ Classname = dto.Classname ?? string.Empty,
+ Steps = ConvertStepsToModel(dto.Steps) ?? [],
+ Setup = ConvertStepsToModel(dto.Setup) ?? [],
+ Teardown = ConvertStepsToModel(dto.Teardown) ?? [],
+ Title = dto.Title ?? string.Empty,
+ Description = dto.Description ?? string.Empty,
+ Labels = ConvertLabelsToModel(dto.Labels) ?? []
+ };
+ }
+
+ public static UpdateAutoTestRequest ConvertAutoTestDtoToPutModel(AutoTest dto, string? projectId)
+ {
+ var links = dto.Links?.Select(l =>
+ new LinkPutModel(
+ title: l.Title,
+ url: l.Url,
+ description: l.Description,
+ type: Enum.Parse(l.Type.ToString()!))
+ ).ToList();
+
+
+ return new UpdateAutoTestRequest(externalId: dto.ExternalId ?? string.Empty, name: dto.Name ?? string.Empty)
+ {
+ Links = links ?? [],
+ ProjectId = new Guid(projectId ?? string.Empty),
+ Name = dto.Name ?? string.Empty,
+ Namespace = dto.Namespace ?? string.Empty,
+ Classname = dto.Classname ?? string.Empty,
+ Steps = ConvertStepsToModel(dto.Steps) ?? [],
+ Setup = ConvertStepsToModel(dto.Setup) ?? [],
+ Teardown = ConvertStepsToModel(dto.Teardown) ?? [],
+ Title = dto.Title ?? string.Empty,
+ Description = dto.Description ?? string.Empty,
+ Labels = ConvertLabelsToModel(dto.Labels) ?? [],
+ IsFlaky = dto.IsFlaky
+ };
+ }
+
+ public static AutoTestResultsForTestRunModel ConvertResultToModel(AutoTestResult dto, string? configurationId)
+ {
+ var links = dto.Links?.Select(l =>
+ new LinkPostModel(
+ l.Title,
+ l.Url,
+ l.Description,
+ Enum.Parse(l.Type.ToString()!))
+ ).ToList();
+
+ return new AutoTestResultsForTestRunModel(
+ autoTestExternalId: dto.ExternalId ?? string.Empty,
+ outcome: Enum.Parse(dto?.Outcome?.ToString() ?? string.Empty))
+ {
+ ConfigurationId = new Guid(configurationId ?? string.Empty),
+ Links = links ?? [],
+ Message = dto?.Message ?? string.Empty,
+ Traces = dto?.Traces ?? string.Empty,
+ StartedOn = dto?.StartedOn,
+ CompletedOn = dto?.CompletedOn,
+ Duration = dto?.Duration,
+ Attachments = dto?.Attachments?.Select(a => new AttachmentPutModel(a)).ToList() ?? [],
+ Parameters = dto?.Parameters ?? [],
+ StepResults = ConvertResultStepToModel(dto?.StepResults),
+ SetupResults = ConvertResultStepToModel(dto?.SetupResults),
+ TeardownResults = ConvertResultStepToModel(dto?.TeardownResults)
+ };
+ }
+
+ private static List? ConvertLabelsToModel(IEnumerable? labels)
+ {
+ return labels?.Select(l => new LabelPostModel(l)).ToList();
+ }
+
+ private static List ConvertResultStepToModel(
+ IEnumerable? dtos)
+ {
+ return dtos?.Select(s => new AttachmentPutModelAutoTestStepResultsModel
+ {
+ Title = s.Title ?? string.Empty,
+ Description = s.Description ?? string.Empty,
+ StartedOn = s.StartedOn,
+ CompletedOn = s.CompletedOn,
+ Duration = s.Duration,
+ Attachments = s.Attachments?.Select(a => new AttachmentPutModel(a)).ToList() ?? [],
+ Parameters = s.Parameters ?? [],
+ StepResults = ConvertResultStepToModel(s?.Steps),
+ Outcome = Enum.Parse(s?.Outcome ?? string.Empty)
+ }).ToList() ?? [];
+ }
+
+ private static List? ConvertStepsToModel(IEnumerable? stepDtos)
+ {
+ return stepDtos?.Select(s => new AutoTestStepModel(
+ s.Title ?? string.Empty,
+ s.Description ?? string.Empty,
+ ConvertStepsToModel(s.Steps) ?? [])).ToList();
+ }
+}
\ No newline at end of file
diff --git a/TmsRunner/Utils/LogParser.cs b/TmsRunner/Utils/LogParser.cs
index caffc97..10ac126 100644
--- a/TmsRunner/Utils/LogParser.cs
+++ b/TmsRunner/Utils/LogParser.cs
@@ -1,6 +1,6 @@
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using System.Text.Json;
using System.Text.RegularExpressions;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Tms.Adapter.Attributes;
using Tms.Adapter.Models;
using Tms.Adapter.Utils;
@@ -9,17 +9,8 @@
namespace TmsRunner.Utils;
-public class LogParser
+public sealed class LogParser(Replacer replacer, Reflector reflector)
{
- private readonly Replacer _replacer;
- private readonly Reflector _reflector;
-
- public LogParser(Replacer replacer, Reflector reflector)
- {
- _replacer = replacer;
- _reflector = reflector;
- }
-
public Dictionary? GetParameters(string traceJson)
{
var pattern = $"{MessageType.TmsParameters}:\\s*([^\\n\\r]*)";
@@ -30,7 +21,7 @@ public LogParser(Replacer replacer, Reflector reflector)
return string.IsNullOrEmpty(json) ? null : JsonSerializer.Deserialize>(json);
}
- public string GetMessage(string traceJson)
+ public static string GetMessage(string traceJson)
{
var pattern = $"{MessageType.TmsStepMessage}:\\s*([^\\n\\r]*)";
var messageRegex = new Regex(pattern);
@@ -40,7 +31,7 @@ public string GetMessage(string traceJson)
return message;
}
- public List? GetLinks(string traceJson)
+ public static List? GetLinks(string traceJson)
{
var pattern = $"{MessageType.TmsStepLinks}:\\s*\\[([^\\n\\r]*)\\]";
var regex = new Regex(pattern);
@@ -52,7 +43,7 @@ public string GetMessage(string traceJson)
}
var linksJsonArray = $"[ {string.Join(", ", matches.Select(m => m.Groups[1].Value))} ]";
-
+
return JsonSerializer.Deserialize>(linksJsonArray);
}
@@ -60,7 +51,7 @@ public string GetMessage(string traceJson)
public AutoTest GetAutoTest(TestResult testResult, Dictionary? parameters)
{
var methodFullName = GetFullyQualifiedMethodName(testResult.TestCase.FullyQualifiedName);
- var method = _reflector.GetMethodMetadata(testResult.TestCase.Source, methodFullName, parameters);
+ var method = Reflector.GetMethodMetadata(testResult.TestCase.Source, methodFullName, parameters);
var autoTest = new AutoTest
{
@@ -69,50 +60,52 @@ public AutoTest GetAutoTest(TestResult testResult, Dictionary? p
MethodName = method.Name
};
- foreach (var attribute in method.Attributes)
+ var attributes = method.Attributes ?? [];
+
+ foreach (var attribute in attributes)
{
switch (attribute)
{
case ExternalIdAttribute externalId:
- autoTest.ExternalId = _replacer.ReplaceParameters(externalId.Value, parameters);
+ autoTest.ExternalId = replacer.ReplaceParameters(externalId.Value, parameters);
break;
case DisplayNameAttribute displayName:
- autoTest.Name = _replacer.ReplaceParameters(displayName.Value, parameters);
+ autoTest.Name = replacer.ReplaceParameters(displayName.Value, parameters);
break;
case TitleAttribute title:
- autoTest.Title = _replacer.ReplaceParameters(title.Value, parameters);
+ autoTest.Title = replacer.ReplaceParameters(title.Value, parameters);
break;
case DescriptionAttribute description:
- autoTest.Description = _replacer.ReplaceParameters(description.Value, parameters);
+ autoTest.Description = replacer.ReplaceParameters(description.Value, parameters);
break;
case WorkItemIdsAttribute ids:
- {
- var workItemIds = ids.Value
- .Select(id => _replacer.ReplaceParameters(id, parameters))
- .ToList();
+ {
+ var workItemIds = ids.Value?
+ .Select(id => replacer.ReplaceParameters(id, parameters))
+ .ToList();
- autoTest.WorkItemIds = workItemIds;
- break;
- }
+ autoTest.WorkItemIds = workItemIds ?? [];
+ break;
+ }
case LinksAttribute links:
- {
- if (links.Value is not null)
{
- links.Value.Title = _replacer.ReplaceParameters(links.Value.Title, parameters);
- links.Value.Url = _replacer.ReplaceParameters(links.Value.Url, parameters);
- links.Value.Description =
- _replacer.ReplaceParameters(links.Value.Description, parameters);
+ if (links.Value is not null)
+ {
+ links.Value.Title = replacer.ReplaceParameters(links.Value.Title, parameters);
+ links.Value.Url = replacer.ReplaceParameters(links.Value.Url, parameters);
+ links.Value.Description =
+ replacer.ReplaceParameters(links.Value.Description, parameters);
- autoTest.Links.Add(links.Value);
- }
+ autoTest.Links?.Add(links.Value);
+ }
- break;
- }
+ break;
+ }
case LabelsAttribute labels:
- {
- autoTest.Labels = labels.Value;
- break;
- }
+ {
+ autoTest.Labels = labels.Value;
+ break;
+ }
}
}
diff --git a/TmsRunner/Utils/Reflector.cs b/TmsRunner/Utils/Reflector.cs
index d9b9762..0865764 100644
--- a/TmsRunner/Utils/Reflector.cs
+++ b/TmsRunner/Utils/Reflector.cs
@@ -3,32 +3,25 @@
namespace TmsRunner.Utils;
-public class Reflector
+public sealed class Reflector
{
- public MethodMetadata GetMethodMetadata(string assemblyPath, string methodName,
+ public static MethodMetadata GetMethodMetadata(string assemblyPath, string methodName,
Dictionary? parameters)
{
var assembly = Assembly.LoadFrom(assemblyPath);
var fullyQualifiedNameArray = methodName.Split(".");
var type = assembly.GetType(string.Join(".", fullyQualifiedNameArray[..^1]));
- var methods = type.GetMethods()
+ var methods = type?.GetMethods()
.Where(m => m.Name.Equals(fullyQualifiedNameArray[^1])).ToList();
if (parameters is not null)
{
- methods = methods
+ methods = methods?
.Where(m => CompareParameters(parameters, m.GetParameters()))
.ToList();
}
- var method = methods.FirstOrDefault();
-
- if (method is null)
- {
- throw new ApplicationException(
- $"Method {fullyQualifiedNameArray[^1]} not found!");
- }
-
+ var method = (methods?.FirstOrDefault()) ?? throw new ApplicationException($"Method {fullyQualifiedNameArray[^1]} not found!");
var attributes = method.GetCustomAttributes(false)
.Select(a => (Attribute)a)
.ToList();
@@ -46,7 +39,9 @@ private static bool CompareParameters(Dictionary parameters,
IReadOnlyList methodParameters)
{
if (methodParameters.Count != parameters.Count)
+ {
return false;
+ }
var i = 0;
foreach (var parameter in parameters)
diff --git a/TmsRunnerTests/TmsRunnerTests.csproj b/TmsRunnerTests/TmsRunnerTests.csproj
index d491fce..9629550 100644
--- a/TmsRunnerTests/TmsRunnerTests.csproj
+++ b/TmsRunnerTests/TmsRunnerTests.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/TmsRunnerTests/Utils/LogParserTests.cs b/TmsRunnerTests/Utils/LogParserTests.cs
index 0d5cf08..4f3be49 100644
--- a/TmsRunnerTests/Utils/LogParserTests.cs
+++ b/TmsRunnerTests/Utils/LogParserTests.cs
@@ -70,7 +70,7 @@ public void GetMessage_TraceIsEmpty()
{
var parser = new LogParser(_replacer, _reflector);
- var result = parser.GetMessage(string.Empty);
+ var result = LogParser.GetMessage(string.Empty);
Assert.AreEqual(string.Empty, result);
}
@@ -80,7 +80,7 @@ public void GetMessage_TraceWithMessage()
{
var parser = new LogParser(_replacer, _reflector);
- var result = parser.GetMessage(message);
+ var result = LogParser.GetMessage(message);
Assert.AreEqual(MessageValue, result);
}
@@ -91,7 +91,7 @@ public void GetMessage_TraceWithoutMessage()
var parser = new LogParser(_replacer, _reflector);
const string trace = "some trace";
- var result = parser.GetMessage(trace);
+ var result = LogParser.GetMessage(trace);
Assert.AreEqual(string.Empty, result);
}
@@ -101,7 +101,7 @@ public void GetLinks_TraceIsEmpty()
{
var parser = new LogParser(_replacer, _reflector);
- var result = parser.GetLinks(string.Empty);
+ var result = LogParser.GetLinks(string.Empty);
Assert.IsNull(result);
}
@@ -126,7 +126,7 @@ public void GetLinks_TraceWithLinks()
Type = LinkType.Defect
};
- var result = parser.GetLinks(message);
+ var result = LogParser.GetLinks(message);
Assert.IsNotNull(result);
Assert.AreEqual(ValueCount, result.Count);
@@ -140,7 +140,7 @@ public void GetLinks_TraceWithoutLinks()
var parser = new LogParser(_replacer, _reflector);
const string trace = "some trace";
- var result = parser.GetLinks(trace);
+ var result = LogParser.GetLinks(trace);
Assert.IsNull(result);
}