Skip to content

Commit

Permalink
Merge pull request #56 from testit-tms/feature/add_automatic_updation…
Browse files Browse the repository at this point in the history
…_links_to_test_cases_config_parameter

Added the "automaticUpdationLinksToTestCases" configuration parameter.
  • Loading branch information
PavelButuzov authored Jun 30, 2024
2 parents 1cd23a3 + 7374cba commit 173b4f1
Show file tree
Hide file tree
Showing 22 changed files with 256 additions and 98 deletions.
6 changes: 5 additions & 1 deletion Tms.Adapter.Core/Client/ITmsClient.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using TestIT.ApiClient.Model;
using Tms.Adapter.Core.Models;

namespace Tms.Adapter.Core.Client;
Expand All @@ -8,9 +9,12 @@ public interface ITmsClient
Task CreateAutotest(TestContainer result, ClassContainer container);
Task UpdateAutotest(TestContainer result, ClassContainer container);
Task UpdateAutotest(string externalId, List<Link> links);
Task<bool> TryLinkAutoTestToWorkItems(string externalId, IEnumerable<string> workItemIds);
Task LinkAutoTestToWorkItems(string autotestId, IEnumerable<string> workItemIds);
Task DeleteAutoTestLinkFromWorkItem(string autotestId, string workItemId);
Task<List<WorkItemIdentifierModel>> GetWorkItemsLinkedToAutoTest(string autotestId);
Task SubmitTestCaseResult(TestContainer result, ClassContainer container);
Task<string> UploadAttachment(string fileName, Stream content);
Task CreateTestRun();
Task CompleteTestRun();
Task<AutoTestModel?> GetAutotestByExternalId(string externalId);
}
80 changes: 56 additions & 24 deletions Tms.Adapter.Core/Client/TmsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class TmsClient : ITmsClient
private readonly TestRunsApi _testRuns;
private readonly AttachmentsApi _attachments;
private readonly AutoTestsApi _autoTests;
private readonly int MAX_TRIES = 10;
private readonly int WAITING_TIME = 200;

public TmsClient(ILogger<TmsClient> logger, TmsSettings settings)
{
Expand Down Expand Up @@ -102,45 +104,75 @@ public async Task UpdateAutotest(string externalId, List<Link> links)
_logger.LogDebug("Update autotest {ExternalId} is successfully", externalId);
}

public async Task<bool> TryLinkAutoTestToWorkItems(string externalId, IEnumerable<string> workItemIds)
public async Task LinkAutoTestToWorkItems(string autotestId, IEnumerable<string> workItemIds)
{
var autotest = await GetAutotestByExternalId(externalId);

if (autotest == null)
{
_logger.LogError("Autotest with {ID} not found", externalId);

return false;
}

foreach (var workItemId in workItemIds)
{
_logger.LogDebug(
"Linking autotest {AutotestId} to work item {WorkItemId}",
autotest.Id,
"Linking autotest {AutotestId} to workitem {WorkitemId}",
autotestId,
workItemId);

for (var attempts = 0; attempts < MAX_TRIES; attempts++)
{
try
{
await _autoTests.LinkAutoTestToWorkItemAsync(autotestId, new LinkAutoTestToWorkItemRequest(workItemId ?? string.Empty)).ConfigureAwait(false);
_logger.LogDebug(
"Link autotest {AutotestId} to workitem {WorkitemId} is successfully",
autotestId,
workItemId);

return;
}
catch (ApiException e)
{
_logger.LogError(
"Cannot link autotest {AutotestId} to work item {WorkItemId}: work item does not exist",
autotestId,
workItemId);

Thread.Sleep(WAITING_TIME);
}
}
}

}

public async Task DeleteAutoTestLinkFromWorkItem(string autotestId, string workItemId)
{
_logger.LogDebug(
"Unlink autotest {AutotestId} from workitem {WorkitemId}",
autotestId,
workItemId);

for (var attempts = 0; attempts < MAX_TRIES; attempts++)
{
try
{
await _autoTests.LinkAutoTestToWorkItemAsync(autotest.Id.ToString(), new LinkAutoTestToWorkItemRequest(workItemId));
await _autoTests.DeleteAutoTestLinkFromWorkItemAsync(autotestId, workItemId);
_logger.LogDebug(
"Unlink autotest {AutotestId} from workitem {WorkitemId} is successfully",
autotestId,
workItemId);

return;
}
catch (ApiException e) when (e.Message.Contains("does not exist"))
catch (ApiException e)
{
_logger.LogError(
"Cannot link autotest {AutotestId} to work item {WorkItemId}: work item does not exist",
autotest.Id,
"Cannot link autotest {AutotestId} to work item {WorkitemId}",
autotestId,
workItemId);

return false;
Thread.Sleep(WAITING_TIME);
}

_logger.LogDebug(
"Link autotest {AutotestId} to work item {WorkItemId} is successfully",
autotest.Id,
workItemId);
}
}

return true;
public async Task<List<WorkItemIdentifierModel>> GetWorkItemsLinkedToAutoTest(string autotestId)
{
return await _autoTests.GetWorkItemsLinkedToAutoTestAsync(autotestId);
}

public async Task SubmitTestCaseResult(TestContainer result, ClassContainer container)
Expand Down Expand Up @@ -212,7 +244,7 @@ public async Task CompleteTestRun()
_logger.LogDebug("Complete test run is successfully");
}

private async Task<AutoTestModel?> GetAutotestByExternalId(string externalId)
public async Task<AutoTestModel?> GetAutotestByExternalId(string externalId)
{
_logger.LogDebug("Getting autotest by external id {Id}", externalId);

Expand Down
8 changes: 8 additions & 0 deletions Tms.Adapter.Core/Configurator/Configurator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class Configurator
private const string TmsTestRunId = "TMS_TEST_RUN_ID";
private const string TmsTestRunName = "TMS_TEST_RUN_NAME";
private const string TmsAutomaticCreationTestCases = "TMS_AUTOMATIC_CREATION_TEST_CASES";
private const string TmsAutomaticUpdationLinksToTestCases = "TMS_AUTOMATIC_UPDATION_LINKS_TO_TEST_CASES";
private const string TmsCertValidation = "TMS_CERT_VALIDATION";
private const string ConfigFile = "TMS_CONFIG_FILE";
private static readonly JsonSerializerOptions SerializerOptions = new() { PropertyNameCaseInsensitive = true };
Expand All @@ -22,6 +23,7 @@ public static TmsSettings GetConfig()
var config = new TmsSettings
{
AutomaticCreationTestCases = false,
AutomaticUpdationLinksToTestCases = false,
CertValidation = true
};

Expand Down Expand Up @@ -98,6 +100,12 @@ private static void ApplyEnv(TmsSettings settings)
settings.AutomaticCreationTestCases = value;
}

var updateLinksToTestCase = Environment.GetEnvironmentVariable(TmsAutomaticUpdationLinksToTestCases);
if (bool.TryParse(updateLinksToTestCase, out var updateLinks) && updateLinks)
{
settings.AutomaticUpdationLinksToTestCases = updateLinks;
}

if (bool.TryParse(Environment.GetEnvironmentVariable(TmsCertValidation), out var validCert) && !validCert)
{
settings.CertValidation = false;
Expand Down
1 change: 1 addition & 0 deletions Tms.Adapter.Core/Configurator/TmsSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public string Url
public string TestRunId { get; set; }

Check warning on line 16 in Tms.Adapter.Core/Configurator/TmsSettings.cs

View workflow job for this annotation

GitHub Actions / build (./Tms.Adapter.Core)

Non-nullable property 'TestRunId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 16 in Tms.Adapter.Core/Configurator/TmsSettings.cs

View workflow job for this annotation

GitHub Actions / build (./Tms.Adapter.SpecFlowPlugin)

Non-nullable property 'TestRunId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public string TestRunName { get; set; }

Check warning on line 17 in Tms.Adapter.Core/Configurator/TmsSettings.cs

View workflow job for this annotation

GitHub Actions / build (./Tms.Adapter.Core)

Non-nullable property 'TestRunName' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 17 in Tms.Adapter.Core/Configurator/TmsSettings.cs

View workflow job for this annotation

GitHub Actions / build (./Tms.Adapter.SpecFlowPlugin)

Non-nullable property 'TestRunName' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public bool AutomaticCreationTestCases { get; set; }
public bool AutomaticUpdationLinksToTestCases { get; set; }
public bool CertValidation { get; set; }
public bool IsDebug { get; set; }
}
2 changes: 1 addition & 1 deletion Tms.Adapter.Core/Service/AdapterManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public AdapterManager()
_logger = logger.CreateLogger<AdapterManager>();
_client = new TmsClient(logger.CreateLogger<TmsClient>(), config);
_storage = new ResultStorage();
_writer = new Writer.Writer(logger.CreateLogger<Writer.Writer>(), _client);
_writer = new Writer.Writer(logger.CreateLogger<Writer.Writer>(), _client, config);
}

public virtual AdapterManager StartTestContainer(ClassContainer container)
Expand Down
2 changes: 1 addition & 1 deletion Tms.Adapter.Core/Tms.Adapter.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>1.6.0</Version>
<Version>1.6.1</Version>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>true</IsPackable>
Expand Down
44 changes: 39 additions & 5 deletions Tms.Adapter.Core/Writer/Writer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Tms.Adapter.Core.Configurator;
using Tms.Adapter.Core.Client;
using Tms.Adapter.Core.Models;

Expand All @@ -8,11 +9,13 @@ public class Writer : IWriter
{
private readonly ILogger<Writer> _logger;
private readonly ITmsClient _client;
private readonly TmsSettings _tmsSettings;

public Writer(ILogger<Writer> logger, ITmsClient client)
public Writer(ILogger<Writer> logger, ITmsClient client, TmsSettings tmsSettings)
{
_logger = logger;
_client = client;
_tmsSettings = tmsSettings;
}

public async Task Write(TestContainer result, ClassContainer container)
Expand Down Expand Up @@ -44,10 +47,7 @@ public async Task Write(TestContainer result, ClassContainer container)

if (result.WorkItemIds.Count > 0)
{
if (!await _client.TryLinkAutoTestToWorkItems(result.ExternalId, result.WorkItemIds))
{
return;
}
await UpdateTestLinkToWorkItems(result.ExternalId, result.WorkItemIds);
}

await _client.SubmitTestCaseResult(result, container);
Expand All @@ -59,4 +59,38 @@ public async Task Write(TestContainer result, ClassContainer container)
_logger.LogError(e, "Can not write autotest with ID {ID}", result.ExternalId);
}
}

private async Task UpdateTestLinkToWorkItems(string externalId, List<string> workItemIds)
{
var autotest = await _client.GetAutotestByExternalId(externalId);

if (autotest == null)
{
_logger.LogError("Autotest with {ID} not found", externalId);
return;
}

var autotestId = autotest.Id.ToString();

var linkedWorkItems = await _client.GetWorkItemsLinkedToAutoTest(autotestId);

foreach (var linkedWorkItem in linkedWorkItems)
{
var linkedWorkItemId = linkedWorkItem.GlobalId.ToString();

if (workItemIds.Contains(linkedWorkItemId))
{
workItemIds.Remove(linkedWorkItemId);

continue;
}

if (_tmsSettings.AutomaticUpdationLinksToTestCases)
{
await _client.DeleteAutoTestLinkFromWorkItem(autotestId, linkedWorkItemId);
}
}

await _client.LinkAutoTestToWorkItems(autotestId, workItemIds);
}
}
24 changes: 13 additions & 11 deletions Tms.Adapter.SpecFlowPlugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,18 @@ Also you need to add following lines to `specflow.json`:

### Configuration

| Description | File property | Environment variable |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|-----------------------------------|
| Location of the TMS instance | url | TMS_URL |
| API secret key [How to getting API secret key?](https://github.com/testit-tms/.github/tree/main/configuration#privatetoken) | privateToken | TMS_PRIVATE_TOKEN |
| ID of project in TMS instance [How to getting project ID?](https://github.com/testit-tms/.github/tree/main/configuration#projectid) | projectId | TMS_PROJECT_ID |
| ID of configuration in TMS instance [How to getting configuration ID?](https://github.com/testit-tms/.github/tree/main/configuration#configurationid) | configurationId | TMS_CONFIGURATION_ID |
| ID of the created test run in TMS instance. If you don't provide a test run ID, the adapter will automatically create one. | testRunId | TMS_TEST_RUN_ID |
| Parameter for specifying the name of test run in TMS instance (**It's optional**). If it is not provided, it is created automatically | testRunName | TMS_TEST_RUN_NAME |
| It enables/disables certificate validation (**It's optional**). Default value - true | certValidation | TMS_CERT_VALIDATION |
| Mode of automatic creation test cases (**It's optional**). Default value - false. The adapter supports following modes:<br/>true - in this mode, the adapter will create a test case linked to the created autotest (not to the updated autotest)<br/>false - in this mode, the adapter will not create a test case | automaticCreationTestCases | TMS_AUTOMATIC_CREATION_TEST_CASES |
| Enable debug logs (**It's optional**). Default value - false | isDebug | - |
| Description | File property | Environment variable |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|--------------------------------------------|
| Location of the TMS instance | url | TMS_URL |
| API secret key [How to getting API secret key?](https://github.com/testit-tms/.github/tree/main/configuration#privatetoken) | privateToken | TMS_PRIVATE_TOKEN |
| ID of project in TMS instance [How to getting project ID?](https://github.com/testit-tms/.github/tree/main/configuration#projectid) | projectId | TMS_PROJECT_ID |
| ID of configuration in TMS instance [How to getting configuration ID?](https://github.com/testit-tms/.github/tree/main/configuration#configurationid) | configurationId | TMS_CONFIGURATION_ID |
| ID of the created test run in TMS instance. If you don't provide a test run ID, the adapter will automatically create one. | testRunId | TMS_TEST_RUN_ID |
| Parameter for specifying the name of test run in TMS instance (**It's optional**). If it is not provided, it is created automatically | testRunName | TMS_TEST_RUN_NAME |
| It enables/disables certificate validation (**It's optional**). Default value - true | certValidation | TMS_CERT_VALIDATION |
| Mode of automatic creation test cases (**It's optional**). Default value - false. The adapter supports following modes:<br/>true - in this mode, the adapter will create a test case linked to the created autotest (not to the updated autotest)<br/>false - in this mode, the adapter will not create a test case | automaticCreationTestCases | TMS_AUTOMATIC_CREATION_TEST_CASES |
| Mode of automatic updation links to test cases (**It's optional**). Default value - false. The adapter supports following modes:<br/>true - in this mode, the adapter will update links to test cases<br/>false - in this mode, the adapter will not update link to test cases | automaticUpdationLinksToTestCases | TMS_AUTOMATIC_UPDATION_LINKS_TO_TEST_CASES |
| Enable debug logs (**It's optional**). Default value - false | isDebug | - |

#### File

Expand All @@ -57,6 +58,7 @@ Create **Tms.config.json** file in the project directory:
"testRunId": "TEST_RUN_ID",
"testRunName": "TEST_RUN_NAME",
"automaticCreationTestCases": false,
"automaticUpdationLinksToTestCases": false,
"certValidation": true,
"isDebug": true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>1.6.0</Version>
<Version>1.6.1</Version>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>true</IsPackable>
Expand Down
Loading

0 comments on commit 173b4f1

Please sign in to comment.