From b554545b46b516eeeea6cc602b7ec27934c5a489 Mon Sep 17 00:00:00 2001 From: mg-diego Date: Sun, 20 Aug 2023 11:22:46 +0200 Subject: [PATCH 1/5] Add MongoDB engine --- TestWare.sln | 14 ++ .../Features/Database.feature | 25 ++++ samples/TestWare.Samples.MongoDB/Hook.cs | 114 ++++++++++++++ .../ImplicitUsings.cs | 3 + samples/TestWare.Samples.MongoDB/LifeCycle.cs | 36 +++++ .../Scripts/docker-compose.yml | 15 ++ .../Scripts/initialize-mongodb-docker.ps1 | 1 + .../Scripts/mongo-init.js | 12 ++ .../Seeder/DatabaseSeeder.cs | 27 ++++ .../DatabaseStepDefinitions.cs | 61 ++++++++ .../TestConfiguration.MongoDB.json | 14 ++ .../TestWare.Samples.MongoDB.csproj | 36 +++++ .../TestWare.Samples.MongoDB.csproj.user | 9 ++ .../TestWare.Engines.API/ApiManager.cs | 8 +- .../Configuration/Capabilities.cs | 8 + .../Factory/ClientFactory.cs | 11 ++ .../Factory/ConfigurationTags.cs | 7 + .../Factory/IMongoDbClient.cs | 34 +++++ .../Factory/MongoDbClient.cs | 140 ++++++++++++++++++ .../MongoDbManager.cs | 73 +++++++++ .../TestWare.Engines.MongoDB.csproj | 17 +++ 21 files changed, 664 insertions(+), 1 deletion(-) create mode 100644 samples/TestWare.Samples.MongoDB/Features/Database.feature create mode 100644 samples/TestWare.Samples.MongoDB/Hook.cs create mode 100644 samples/TestWare.Samples.MongoDB/ImplicitUsings.cs create mode 100644 samples/TestWare.Samples.MongoDB/LifeCycle.cs create mode 100644 samples/TestWare.Samples.MongoDB/Scripts/docker-compose.yml create mode 100644 samples/TestWare.Samples.MongoDB/Scripts/initialize-mongodb-docker.ps1 create mode 100644 samples/TestWare.Samples.MongoDB/Scripts/mongo-init.js create mode 100644 samples/TestWare.Samples.MongoDB/Seeder/DatabaseSeeder.cs create mode 100644 samples/TestWare.Samples.MongoDB/StepDefinitions/DatabaseStepDefinitions.cs create mode 100644 samples/TestWare.Samples.MongoDB/TestConfiguration.MongoDB.json create mode 100644 samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj create mode 100644 samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj.user create mode 100644 src/Engines/TestWare.Engines.MongoDB/Configuration/Capabilities.cs create mode 100644 src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs create mode 100644 src/Engines/TestWare.Engines.MongoDB/Factory/ConfigurationTags.cs create mode 100644 src/Engines/TestWare.Engines.MongoDB/Factory/IMongoDbClient.cs create mode 100644 src/Engines/TestWare.Engines.MongoDB/Factory/MongoDbClient.cs create mode 100644 src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs create mode 100644 src/Engines/TestWare.Engines.MongoDB/TestWare.Engines.MongoDB.csproj diff --git a/TestWare.sln b/TestWare.sln index 3c7ff8cc..54e2ac0c 100644 --- a/TestWare.sln +++ b/TestWare.sln @@ -38,6 +38,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.ExtentReport", "sr EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Reporting", "Reporting", "{DCCEF363-0EBE-46EA-B02B-CD59010626F6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWare.Engines.MongoDB", "src\Engines\TestWare.Engines.MongoDB\TestWare.Engines.MongoDB.csproj", "{4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestWare.Samples.MongoDB", "samples\TestWare.Samples.MongoDB\TestWare.Samples.MongoDB.csproj", "{5378DE68-675E-440D-AAA9-7D3AF8AA680E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -84,6 +88,14 @@ Global {94025C6B-DF0D-4AC4-BBC5-A94A9FA3AB0A}.Debug|Any CPU.Build.0 = Debug|Any CPU {94025C6B-DF0D-4AC4-BBC5-A94A9FA3AB0A}.Release|Any CPU.ActiveCfg = Release|Any CPU {94025C6B-DF0D-4AC4-BBC5-A94A9FA3AB0A}.Release|Any CPU.Build.0 = Release|Any CPU + {4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11}.Release|Any CPU.Build.0 = Release|Any CPU + {5378DE68-675E-440D-AAA9-7D3AF8AA680E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5378DE68-675E-440D-AAA9-7D3AF8AA680E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5378DE68-675E-440D-AAA9-7D3AF8AA680E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5378DE68-675E-440D-AAA9-7D3AF8AA680E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -102,6 +114,8 @@ Global {71120454-DD7A-484C-93F2-699B4C363297} = {58B1446D-98A3-46A2-A668-305F0170B39F} {94025C6B-DF0D-4AC4-BBC5-A94A9FA3AB0A} = {DCCEF363-0EBE-46EA-B02B-CD59010626F6} {DCCEF363-0EBE-46EA-B02B-CD59010626F6} = {4678C707-68DB-4E06-9184-A07FB398832C} + {4DFC2BE5-D3EF-4F39-AAD4-B8213DE92A11} = {A2E4E1F7-CB61-48DC-AA38-A74F7DC74CA2} + {5378DE68-675E-440D-AAA9-7D3AF8AA680E} = {58B1446D-98A3-46A2-A668-305F0170B39F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4F88CB24-23C8-4E0E-8B83-29023C1642B8} diff --git a/samples/TestWare.Samples.MongoDB/Features/Database.feature b/samples/TestWare.Samples.MongoDB/Features/Database.feature new file mode 100644 index 00000000..a381f355 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/Features/Database.feature @@ -0,0 +1,25 @@ +@MongoDB +Feature: Database + + +Scenario: Insert at database + When the following document is inserted in 'collection-example' collection at 'database-example' database + | NAME | + | Didac | + Then the following document is saved in 'collection-example' collection at 'database-example' database + | NAME | + | Didac | + + +Scenario: Delete at database + Given the following document is saved in 'collection-example' collection at 'database-example' database + | NAME | + | Diego | + When the following document is deleted in 'collection-example' collection at 'database-example' database + | NAME | + | Diego | + Then no documents are saved in 'collection-example' collection at 'database-example' database with values + | NAME | + | Diego | + + diff --git a/samples/TestWare.Samples.MongoDB/Hook.cs b/samples/TestWare.Samples.MongoDB/Hook.cs new file mode 100644 index 00000000..793e5a2f --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/Hook.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using TestWare.Reporting.ExtentReport; +using TestWare.Samples.MongoDB.Seeder; + +namespace TestWare.Samples.MongoDB; + +[Binding] +public sealed class Hook +{ + private readonly TestContext _testContext; + private int _stepCounter; + private static readonly LifeCycle _lifeCycle = new(); + private static ExtentReport _testReport; + + public Hook(TestContext testContext) + { + _testContext = testContext; + } + + [BeforeFeature] + public static void BeforeFeature(FeatureContext featureContext) + { + var name = featureContext.FeatureInfo.Title; + var tags = featureContext.FeatureInfo.Tags; + + _lifeCycle.BeginTestSuite(name); + _testReport.CreateFeature(name, tags); + } + + [AfterFeature] + public static void AfterFeature(FeatureContext featureContext) + { + _lifeCycle.EndTestSuite(); + } + + [BeforeScenario] + public void BeforeScenario(FeatureContext featureContext, ScenarioContext scenarioContext) + { + var name = scenarioContext.ScenarioInfo.Arguments.Count > 0 + ? $"{DateTime.UtcNow.ToString("yyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture)} - {scenarioContext.ScenarioInfo.Title}" + : scenarioContext.ScenarioInfo.Title; + + var description = scenarioContext.ScenarioInfo.Description ?? ""; + var scenarioTags = scenarioContext.ScenarioInfo.Tags; + _testReport.CreateTestCase(name, description, scenarioTags); + + _testContext.WriteLine("----------------------------------------- \r\n"); + _testContext.WriteLine($"Feature: {featureContext.FeatureInfo.Title}"); + _testContext.WriteLine($" Scenario: {scenarioContext.ScenarioInfo.Title} \r\n"); + + _stepCounter = 1; + var tags = GetTags(featureContext, scenarioContext); + _lifeCycle.BeginTestCase(name, tags); + + var databaseSeeder = new DatabaseSeeder(); + databaseSeeder.InitializeDatabase(); + } + + [AfterScenario] + public void AfterScenario() + { + _testReport.SetTestcaseOutcome(_testContext.CurrentTestOutcome); + _lifeCycle.EndTestCase(); + } + + [BeforeTestRun] + public static void BeforeTestRun() + { + _lifeCycle.BeginTestExecution(); + _testReport = new ExtentReport(_lifeCycle.GetCurrentResultsDirectory()); + } + + [AfterTestRun] + public static void AfterTestRun() + { + _lifeCycle.EndTestExecution(); + _testReport.CreateTestReportFile(); + } + + [BeforeStep] + public void BeforeStep(ScenarioContext scenarioContext) + { + var name = scenarioContext.CurrentScenarioBlock.ToString(); + var description = scenarioContext.StepContext.StepInfo.Text; + _testReport.CreateStep(name, description); + + var stepId = $"{_stepCounter:00} {description}"; + _stepCounter++; + _lifeCycle.BeginTestStep(stepId); + } + + [AfterStep] + public void AfterStep(ScenarioContext scenarioContext) + { + _lifeCycle.EndTestStep(); + var evidencesPath = _lifeCycle.GetStepEvidences(); + + foreach (var evidence in evidencesPath) + { + _testReport.AddScreenshotToStep(evidence); + _testContext.AddResultFile(evidence); + } + } + + private static List GetTags(FeatureContext featureContext, ScenarioContext scenarioContext) + { + var tags = featureContext.FeatureInfo.Tags.ToList(); + tags.AddRange(scenarioContext.ScenarioInfo.Tags.ToList()); + return tags; + } +} diff --git a/samples/TestWare.Samples.MongoDB/ImplicitUsings.cs b/samples/TestWare.Samples.MongoDB/ImplicitUsings.cs new file mode 100644 index 00000000..8022d597 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/ImplicitUsings.cs @@ -0,0 +1,3 @@ +global using FluentAssertions; +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using TechTalk.SpecFlow; diff --git a/samples/TestWare.Samples.MongoDB/LifeCycle.cs b/samples/TestWare.Samples.MongoDB/LifeCycle.cs new file mode 100644 index 00000000..bc4eadc4 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/LifeCycle.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Reflection; +using TestWare.Core; +using TestWare.Core.Configuration; +using TestWare.Core.Interfaces; +using TestWare.Engines.MongoDB; + +namespace TestWare.Samples.MongoDB; + +internal class LifeCycle : AutomationLifeCycleBase +{ + protected override IEnumerable GetTestWareComponentAssemblies() + { + IEnumerable assemblies = new[] + { + typeof(Hook).Assembly + }; + + return assemblies; + } + + protected override IEnumerable GetTestWareEngines() + { + IEnumerable engines = new[] + { + new MongoDbManager() + }; + + return engines; + } + + protected override TestConfiguration GetConfiguration() + { + return ConfigurationManager.ReadConfigurationFile("TestConfiguration.MongoDB.json"); + } +} diff --git a/samples/TestWare.Samples.MongoDB/Scripts/docker-compose.yml b/samples/TestWare.Samples.MongoDB/Scripts/docker-compose.yml new file mode 100644 index 00000000..f022887d --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/Scripts/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.7' + +services: + mongodb: + image: mongo:latest + container_name: mongodb + restart: always + environment: + MONGO_INITDB_ROOT_USERNAME: guest + MONGO_INITDB_ROOT_PASSWORD: guest + MONGO_INITDB_DATABASE: admin + ports: + - 27017:27017 + volumes: + - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro \ No newline at end of file diff --git a/samples/TestWare.Samples.MongoDB/Scripts/initialize-mongodb-docker.ps1 b/samples/TestWare.Samples.MongoDB/Scripts/initialize-mongodb-docker.ps1 new file mode 100644 index 00000000..453dde20 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/Scripts/initialize-mongodb-docker.ps1 @@ -0,0 +1 @@ +docker-compose up --build -d mongodb \ No newline at end of file diff --git a/samples/TestWare.Samples.MongoDB/Scripts/mongo-init.js b/samples/TestWare.Samples.MongoDB/Scripts/mongo-init.js new file mode 100644 index 00000000..6471b784 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/Scripts/mongo-init.js @@ -0,0 +1,12 @@ +db.createUser( + { + user: "guest", + pwd: "guest", + roles: [ + { + role: "readWrite", + db: "database-example" + } + ] + } +); \ No newline at end of file diff --git a/samples/TestWare.Samples.MongoDB/Seeder/DatabaseSeeder.cs b/samples/TestWare.Samples.MongoDB/Seeder/DatabaseSeeder.cs new file mode 100644 index 00000000..d1440145 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/Seeder/DatabaseSeeder.cs @@ -0,0 +1,27 @@ +using MongoDB.Bson; +using TestWare.Core; +using TestWare.Engines.MongoDB.Factory; + +namespace TestWare.Samples.MongoDB.Seeder; + +internal class DatabaseSeeder +{ + private readonly IMongoDbClient _mongoDbClient; + private const string DATABASE_NAME = "database-example"; + private const string COLLECTION_NAME = "collection-example"; + + public DatabaseSeeder() + { + _mongoDbClient = ContainerManager.GetTestWareComponent(); + } + + public void InitializeDatabase() + { + _mongoDbClient.DropDatabase(DATABASE_NAME); + + _mongoDbClient.CreateDatabase(DATABASE_NAME); + _mongoDbClient.CreateCollection(DATABASE_NAME, COLLECTION_NAME); + + _mongoDbClient.InsertOne(new BsonDocument("name", "Diego"), DATABASE_NAME, COLLECTION_NAME); + } +} diff --git a/samples/TestWare.Samples.MongoDB/StepDefinitions/DatabaseStepDefinitions.cs b/samples/TestWare.Samples.MongoDB/StepDefinitions/DatabaseStepDefinitions.cs new file mode 100644 index 00000000..ff800afe --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/StepDefinitions/DatabaseStepDefinitions.cs @@ -0,0 +1,61 @@ +using FluentAssertions.Execution; +using MongoDB.Bson; +using TestWare.Core; +using TestWare.Engines.MongoDB.Factory; + +namespace TestWare.Samples.MongoDB.StepDefinitions; + +[Binding] +public class DatabaseStepDefinitions +{ + private readonly IMongoDbClient _mongoDbClient; + + public DatabaseStepDefinitions() + { + _mongoDbClient = ContainerManager.GetTestWareComponent(); + } + + [When(@"the following document is inserted in '([^']*)' collection at '([^']*)' database")] + public void TheFollowingDocumentIsInsertedInCollectionAtDatabase(string collectionName, string databaseName, Table table) + { + var value = table.Rows[0]["NAME"].ToString(); + + _mongoDbClient.InsertOne(new BsonDocument("name", value), databaseName, collectionName); + } + + [When(@"the following document is deleted in '([^']*)' collection at '([^']*)' database")] + public void TheFollowingDocumentIsDeletedInCollectionAtDatabase(string collectionName, string databaseName, Table table) + { + var value = table.Rows[0]["NAME"].ToString(); + + _mongoDbClient.DeleteOne(new BsonDocument("name", value), databaseName, collectionName); + } + + + [Given(@"the following document is saved in '([^']*)' collection at '([^']*)' database")] + [Then(@"the following document is saved in '([^']*)' collection at '([^']*)' database")] + public void TheFollowingDocumentIsSavedInCollectionAtDatabase(string collectionName, string databaseName, Table table) + { + var value = table.Rows[0]["NAME"].ToString(); + + var result = _mongoDbClient.Find(new BsonDocument("name", value), databaseName, collectionName).Result; + + using (new AssertionScope()) + { + result.Should().NotBeNull(); + result.Count.Should().Be(1); + result[0].GetValue("name").RawValue.Should().Be(value); + } + } + + [Then(@"no documents are saved in '([^']*)' collection at '([^']*)' database with values")] + public void ThenNoDocumentsAreSavedInCollectionAtDatabaseWithValues(string collectionName, string databaseName, Table table) + { + var value = table.Rows[0]["NAME"].ToString(); + + var result = _mongoDbClient.Find(new BsonDocument("name", value), databaseName, collectionName).Result; + + result.Count.Should().Be(0); + } + +} diff --git a/samples/TestWare.Samples.MongoDB/TestConfiguration.MongoDB.json b/samples/TestWare.Samples.MongoDB/TestConfiguration.MongoDB.json new file mode 100644 index 00000000..17840e62 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/TestConfiguration.MongoDB.json @@ -0,0 +1,14 @@ +{ + "Configurations": [ + { + "Tag": "MongoDB", + "Capabilities": [ + { + "Name": "MongoDB", + "ConnectionString": "mongodb://guest:guest@localhost:27017/" + } + ] + } + ], + "TestResultPath": "C:\\workspace\\ERNI\\results\\" +} \ No newline at end of file diff --git a/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj b/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj new file mode 100644 index 00000000..5f7c44b4 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj @@ -0,0 +1,36 @@ + + + + net6.0 + enable + + false + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + + diff --git a/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj.user b/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj.user new file mode 100644 index 00000000..7421e458 --- /dev/null +++ b/samples/TestWare.Samples.MongoDB/TestWare.Samples.MongoDB.csproj.user @@ -0,0 +1,9 @@ + + + + + + Code + + + \ No newline at end of file diff --git a/src/Engines/TestWare.Engines.API/ApiManager.cs b/src/Engines/TestWare.Engines.API/ApiManager.cs index 19f44d44..aafa0bbd 100644 --- a/src/Engines/TestWare.Engines.API/ApiManager.cs +++ b/src/Engines/TestWare.Engines.API/ApiManager.cs @@ -1,5 +1,6 @@ using Autofac; using System.Linq; +using System.Text.Encodings.Web; using System.Text.Json; using TestWare.Core; using TestWare.Core.Configuration; @@ -70,7 +71,12 @@ public string CollectEvidence(string destinationPath, string evidenceName) { var responses = apiClient.GetRestResponses(); var instanceName = ContainerManager.GetNameFromInstance(apiClient); - var evidenceData = JsonSerializer.Serialize(responses); + var serializeOptions = new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + var evidenceData = JsonSerializer.Serialize(responses, serializeOptions); var evidencePath = Path.Combine(destinationPath, $"{evidenceName} - {instanceName}.json"); File.WriteAllText(evidencePath, evidenceData); apiClient.ClearResponseQueue(); diff --git a/src/Engines/TestWare.Engines.MongoDB/Configuration/Capabilities.cs b/src/Engines/TestWare.Engines.MongoDB/Configuration/Capabilities.cs new file mode 100644 index 00000000..34563ada --- /dev/null +++ b/src/Engines/TestWare.Engines.MongoDB/Configuration/Capabilities.cs @@ -0,0 +1,8 @@ +namespace TestWare.Engines.MongoDB.Configuration; + +internal class Capabilities +{ + public string Name { get; set; } + + public string ConnectionString { get; set; } +} diff --git a/src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs b/src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs new file mode 100644 index 00000000..4cad0439 --- /dev/null +++ b/src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs @@ -0,0 +1,11 @@ +using TestWare.Engines.MongoDB.Configuration; + +namespace TestWare.Engines.MongoDB.Factory; + +internal class ClientFactory +{ + public static IMongoDbClient Create(Capabilities capabilities) + { + return new MongoDbClient(capabilities.ConnectionString); + } +} diff --git a/src/Engines/TestWare.Engines.MongoDB/Factory/ConfigurationTags.cs b/src/Engines/TestWare.Engines.MongoDB/Factory/ConfigurationTags.cs new file mode 100644 index 00000000..942eca07 --- /dev/null +++ b/src/Engines/TestWare.Engines.MongoDB/Factory/ConfigurationTags.cs @@ -0,0 +1,7 @@ +namespace TestWare.Engines.MongoDB.Factory; + +public enum ConfigurationTags +{ + none = 0, + mongodb = 1 +} diff --git a/src/Engines/TestWare.Engines.MongoDB/Factory/IMongoDbClient.cs b/src/Engines/TestWare.Engines.MongoDB/Factory/IMongoDbClient.cs new file mode 100644 index 00000000..440571a2 --- /dev/null +++ b/src/Engines/TestWare.Engines.MongoDB/Factory/IMongoDbClient.cs @@ -0,0 +1,34 @@ +using MongoDB.Bson; + +namespace TestWare.Engines.MongoDB.Factory; + +public interface IMongoDbClient +{ + void CreateDatabase(string databaseName); + + void DropDatabase(string databaseName); + + void CreateCollection(string databaseName, string collectionName); + + void DropCollection(string databaseName, string collectionName); + + void InsertOne(BsonDocument document, string databaseName, string collectionName); + + void InsertMany(IEnumerable documentList, string databaseName, string collectionName); + + void UpdateOne(BsonDocument document, string databaseName, string collectionName); + + void UpdateMany(BsonDocument document, string databaseName, string collectionName); + + void DeleteOne(BsonDocument document, string databaseName, string collectionName); + + void DeleteMany(BsonDocument document, string databaseName, string collectionName); + + Task Count(BsonDocument document, string databaseName, string collectionName); + + Task> Find(BsonDocument document, string databaseName, string collectionName); + + List GetClientLogs(); + + void ClearClientLogs(); +} diff --git a/src/Engines/TestWare.Engines.MongoDB/Factory/MongoDbClient.cs b/src/Engines/TestWare.Engines.MongoDB/Factory/MongoDbClient.cs new file mode 100644 index 00000000..f78fcf22 --- /dev/null +++ b/src/Engines/TestWare.Engines.MongoDB/Factory/MongoDbClient.cs @@ -0,0 +1,140 @@ +using MongoDB.Bson; +using MongoDB.Driver; +using MongoDB.Driver.Core.Events; + +namespace TestWare.Engines.MongoDB.Factory; + +internal class MongoDbClient : MongoClient, IMongoDbClient +{ + private readonly MongoClient mongoClient; + + private List clientLogs; + + public MongoDbClient(string connectionString) + { + clientLogs = new List(); + var mongoConnectionUrl = new MongoUrl(connectionString); + var mongoClientSettings = MongoClientSettings.FromUrl(mongoConnectionUrl); + + mongoClientSettings.ClusterConfigurator = cb => + { + cb.Subscribe(e => + { + clientLogs.Add($"{e.CommandName} - {e.Command.ToJson()}"); + }); + }; + + mongoClient = new MongoClient(mongoClientSettings); + } + + public void CreateDatabase(string databaseName) + { + GetDatabase(databaseName); + } + + public void DropDatabase(string databaseName) + { + mongoClient.DropDatabase(databaseName); + } + + public void CreateCollection(string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + database.CreateCollection(collectionName); + } + + public void DropCollection(string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + database.DropCollection(collectionName); + } + + public async void InsertOne(BsonDocument document, string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + var collection = GetCollection(database, collectionName); + + await collection.InsertOneAsync(document); + } + + public async void InsertMany(IEnumerable documentList, string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + var collection = GetCollection(database, collectionName); + + await collection.InsertManyAsync(documentList); + } + + public async void UpdateOne(BsonDocument document, string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + var collection = GetCollection(database, collectionName); + + throw new NotImplementedException(); + } + + public async void UpdateMany(BsonDocument document, string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + var collection = GetCollection(database, collectionName); + + throw new NotImplementedException(); + } + + public async void DeleteOne(BsonDocument document, string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + var collection = GetCollection(database, collectionName); + + await collection.DeleteOneAsync(document); + } + + public async void DeleteMany(BsonDocument document, string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + var collection = GetCollection(database, collectionName); + + await collection.DeleteManyAsync(document); + } + + public async Task Count(BsonDocument document, string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + var collection = GetCollection(database, collectionName); + + var count = await collection.CountDocumentsAsync(document); + + return count; + } + + public async Task> Find(BsonDocument document, string databaseName, string collectionName) + { + var database = GetDatabase(databaseName); + var collection = GetCollection(database, collectionName); + + var list = await collection.Find(document).ToListAsync(); + + return list; + } + + public List GetClientLogs() + { + return clientLogs; + } + + public void ClearClientLogs() + { + clientLogs = new List(); + } + + private IMongoDatabase GetDatabase(string databaseName) + { + return mongoClient.GetDatabase(databaseName); + } + + private static IMongoCollection GetCollection(IMongoDatabase database, string collectionName) + { + return database.GetCollection(collectionName); + } +} + diff --git a/src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs b/src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs new file mode 100644 index 00000000..e0b498aa --- /dev/null +++ b/src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs @@ -0,0 +1,73 @@ +using Autofac; +using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; +using TestWare.Core; +using TestWare.Core.Configuration; +using TestWare.Core.Interfaces; +using TestWare.Engines.MongoDB.Configuration; +using TestWare.Engines.MongoDB.Factory; + +namespace TestWare.Engines.MongoDB; + +public class MongoDbManager : EngineManagerBase, IEngineManager +{ + private const string _name = "MongoDb"; + + private static void RegisterSingle(IEnumerable tags, TestConfiguration testConfiguration) + { + var configName = Enum.GetName(ConfigurationTags.mongodb).ToUpperInvariant(); + var capabilities = ConfigurationManager.GetCapabilities(testConfiguration, configName); + var singleCapability = capabilities.FirstOrDefault(x => tags.Contains(x.Name.ToUpperInvariant())); + if (!ContainerManager.ExistsType(singleCapability.GetType())) + { + var driver = ClientFactory.Create(singleCapability); + ContainerManager.RegisterType(singleCapability.Name, driver); + } + } + + public string CollectEvidence(string destinationPath, string evidenceName) + { + var mongoDbClients = ContainerManager.Container.Resolve>(); + + foreach (var mongoDbClient in mongoDbClients) + { + var responses = mongoDbClient.GetClientLogs(); + var instanceName = ContainerManager.GetNameFromInstance(mongoDbClient); + var serializeOptions = new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + var evidenceData = JsonSerializer.Serialize(responses, serializeOptions); + var evidencePath = Path.Combine(destinationPath, $"{evidenceName} - {instanceName}.json"); + File.WriteAllText(evidencePath, evidenceData, Encoding.UTF8); + mongoDbClient.ClearClientLogs(); + } + + return destinationPath; + } + + public void Destroy() + { + //Do nothing, the client handles it automatically + } + + public string GetEngineName() + { + return _name; + } + + public void Initialize(IEnumerable tags, TestConfiguration testConfiguration) + { + var normalizedTags = tags.Select(x => x.ToUpperInvariant()).ToArray(); + var foundConfiguration = ConfigurationManager.GetValidConfiguration(normalizedTags); + + switch (foundConfiguration) + { + case ConfigurationTags.mongodb: + RegisterSingle(normalizedTags, testConfiguration); + break; + } + } +} diff --git a/src/Engines/TestWare.Engines.MongoDB/TestWare.Engines.MongoDB.csproj b/src/Engines/TestWare.Engines.MongoDB/TestWare.Engines.MongoDB.csproj new file mode 100644 index 00000000..35e71620 --- /dev/null +++ b/src/Engines/TestWare.Engines.MongoDB/TestWare.Engines.MongoDB.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + From 0193d5047fa5f691731cb1f4b11ecc8c4c17d204 Mon Sep 17 00:00:00 2001 From: mg-diego Date: Fri, 6 Oct 2023 18:02:34 +0200 Subject: [PATCH 2/5] Solve PR comments --- samples/TestWare.Samples.MongoDB/Hook.cs | 2 +- .../StepDefinitions/DatabaseStepDefinitions.cs | 2 +- .../Configuration/Capabilities.cs | 4 ++-- .../TestWare.Engines.MongoDB/Factory/MongoDbClient.cs | 8 ++++---- src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs | 9 ++++++--- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/samples/TestWare.Samples.MongoDB/Hook.cs b/samples/TestWare.Samples.MongoDB/Hook.cs index 793e5a2f..742a1318 100644 --- a/samples/TestWare.Samples.MongoDB/Hook.cs +++ b/samples/TestWare.Samples.MongoDB/Hook.cs @@ -13,7 +13,7 @@ public sealed class Hook private readonly TestContext _testContext; private int _stepCounter; private static readonly LifeCycle _lifeCycle = new(); - private static ExtentReport _testReport; + private static ExtentReport? _testReport; public Hook(TestContext testContext) { diff --git a/samples/TestWare.Samples.MongoDB/StepDefinitions/DatabaseStepDefinitions.cs b/samples/TestWare.Samples.MongoDB/StepDefinitions/DatabaseStepDefinitions.cs index ff800afe..af354e32 100644 --- a/samples/TestWare.Samples.MongoDB/StepDefinitions/DatabaseStepDefinitions.cs +++ b/samples/TestWare.Samples.MongoDB/StepDefinitions/DatabaseStepDefinitions.cs @@ -44,7 +44,7 @@ public void TheFollowingDocumentIsSavedInCollectionAtDatabase(string collectionN { result.Should().NotBeNull(); result.Count.Should().Be(1); - result[0].GetValue("name").RawValue.Should().Be(value); + BsonTypeMapper.MapToDotNetValue(result[0].GetValue("name")).ToString().Should().Be(value); } } diff --git a/src/Engines/TestWare.Engines.MongoDB/Configuration/Capabilities.cs b/src/Engines/TestWare.Engines.MongoDB/Configuration/Capabilities.cs index 34563ada..9f91e96f 100644 --- a/src/Engines/TestWare.Engines.MongoDB/Configuration/Capabilities.cs +++ b/src/Engines/TestWare.Engines.MongoDB/Configuration/Capabilities.cs @@ -2,7 +2,7 @@ internal class Capabilities { - public string Name { get; set; } + public string? Name { get; set; } - public string ConnectionString { get; set; } + public string? ConnectionString { get; set; } } diff --git a/src/Engines/TestWare.Engines.MongoDB/Factory/MongoDbClient.cs b/src/Engines/TestWare.Engines.MongoDB/Factory/MongoDbClient.cs index f78fcf22..9b9fcf44 100644 --- a/src/Engines/TestWare.Engines.MongoDB/Factory/MongoDbClient.cs +++ b/src/Engines/TestWare.Engines.MongoDB/Factory/MongoDbClient.cs @@ -65,20 +65,20 @@ public async void InsertMany(IEnumerable documentList, string data await collection.InsertManyAsync(documentList); } - public async void UpdateOne(BsonDocument document, string databaseName, string collectionName) + public void UpdateOne(BsonDocument document, string databaseName, string collectionName) { var database = GetDatabase(databaseName); var collection = GetCollection(database, collectionName); - throw new NotImplementedException(); + throw new NotImplementedException("Pending to implement"); } - public async void UpdateMany(BsonDocument document, string databaseName, string collectionName) + public void UpdateMany(BsonDocument document, string databaseName, string collectionName) { var database = GetDatabase(databaseName); var collection = GetCollection(database, collectionName); - throw new NotImplementedException(); + throw new NotImplementedException("Pending to implement"); } public async void DeleteOne(BsonDocument document, string databaseName, string collectionName) diff --git a/src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs b/src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs index e0b498aa..bbba2305 100644 --- a/src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs +++ b/src/Engines/TestWare.Engines.MongoDB/MongoDbManager.cs @@ -16,14 +16,17 @@ public class MongoDbManager : EngineManagerBase, IEngineManager private static void RegisterSingle(IEnumerable tags, TestConfiguration testConfiguration) { - var configName = Enum.GetName(ConfigurationTags.mongodb).ToUpperInvariant(); + var configName = Enum.GetName(ConfigurationTags.mongodb)?.ToUpperInvariant(); var capabilities = ConfigurationManager.GetCapabilities(testConfiguration, configName); - var singleCapability = capabilities.FirstOrDefault(x => tags.Contains(x.Name.ToUpperInvariant())); - if (!ContainerManager.ExistsType(singleCapability.GetType())) + var singleCapability = capabilities.FirstOrDefault(x => tags.Contains(x?.Name?.ToUpperInvariant())); + if (singleCapability != null && !ContainerManager.ExistsType(singleCapability.GetType())) { var driver = ClientFactory.Create(singleCapability); ContainerManager.RegisterType(singleCapability.Name, driver); } + else { + throw new NullReferenceException("No suitable capability found."); + } } public string CollectEvidence(string destinationPath, string evidenceName) From 3ee1e31137e5b44d7da1505b9f608908c2822560 Mon Sep 17 00:00:00 2001 From: mg-diego Date: Fri, 6 Oct 2023 18:14:26 +0200 Subject: [PATCH 3/5] Solve PR comments --- samples/TestWare.Samples.MongoDB/Hook.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/TestWare.Samples.MongoDB/Hook.cs b/samples/TestWare.Samples.MongoDB/Hook.cs index 742a1318..1f81171b 100644 --- a/samples/TestWare.Samples.MongoDB/Hook.cs +++ b/samples/TestWare.Samples.MongoDB/Hook.cs @@ -27,7 +27,7 @@ public static void BeforeFeature(FeatureContext featureContext) var tags = featureContext.FeatureInfo.Tags; _lifeCycle.BeginTestSuite(name); - _testReport.CreateFeature(name, tags); + _testReport?.CreateFeature(name, tags); } [AfterFeature] @@ -45,7 +45,7 @@ public void BeforeScenario(FeatureContext featureContext, ScenarioContext scenar var description = scenarioContext.ScenarioInfo.Description ?? ""; var scenarioTags = scenarioContext.ScenarioInfo.Tags; - _testReport.CreateTestCase(name, description, scenarioTags); + _testReport?.CreateTestCase(name, description, scenarioTags); _testContext.WriteLine("----------------------------------------- \r\n"); _testContext.WriteLine($"Feature: {featureContext.FeatureInfo.Title}"); @@ -62,7 +62,7 @@ public void BeforeScenario(FeatureContext featureContext, ScenarioContext scenar [AfterScenario] public void AfterScenario() { - _testReport.SetTestcaseOutcome(_testContext.CurrentTestOutcome); + _testReport?.SetTestcaseOutcome(_testContext.CurrentTestOutcome); _lifeCycle.EndTestCase(); } @@ -77,7 +77,7 @@ public static void BeforeTestRun() public static void AfterTestRun() { _lifeCycle.EndTestExecution(); - _testReport.CreateTestReportFile(); + _testReport?.CreateTestReportFile(); } [BeforeStep] @@ -85,7 +85,7 @@ public void BeforeStep(ScenarioContext scenarioContext) { var name = scenarioContext.CurrentScenarioBlock.ToString(); var description = scenarioContext.StepContext.StepInfo.Text; - _testReport.CreateStep(name, description); + _testReport?.CreateStep(name, description); var stepId = $"{_stepCounter:00} {description}"; _stepCounter++; @@ -100,7 +100,7 @@ public void AfterStep(ScenarioContext scenarioContext) foreach (var evidence in evidencesPath) { - _testReport.AddScreenshotToStep(evidence); + _testReport?.AddScreenshotToStep(evidence); _testContext.AddResultFile(evidence); } } From a1b7bbe41ea9c5d86661175458263ea415bd9449 Mon Sep 17 00:00:00 2001 From: mg-diego Date: Fri, 6 Oct 2023 18:21:25 +0200 Subject: [PATCH 4/5] Solve PR comments --- src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs b/src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs index 4cad0439..b542ec9f 100644 --- a/src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs +++ b/src/Engines/TestWare.Engines.MongoDB/Factory/ClientFactory.cs @@ -6,6 +6,7 @@ internal class ClientFactory { public static IMongoDbClient Create(Capabilities capabilities) { + if (capabilities == null || capabilities.ConnectionString == null) throw new ArgumentNullException(nameof(capabilities)); return new MongoDbClient(capabilities.ConnectionString); } } From ac06cd141f163967c919590b0a6c916aa6988fde Mon Sep 17 00:00:00 2001 From: Diego Martinez Date: Thu, 23 May 2024 14:23:26 +0200 Subject: [PATCH 5/5] Fix JDK version --- .github/workflows/Sonar_Scanner.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Sonar_Scanner.yml b/.github/workflows/Sonar_Scanner.yml index 8a4ab4f8..188eb1a0 100644 --- a/.github/workflows/Sonar_Scanner.yml +++ b/.github/workflows/Sonar_Scanner.yml @@ -31,10 +31,10 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: 6.0.x - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 1.11 + java-version: 17 - uses: actions/checkout@v2 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis