diff --git a/nx.json b/nx.json index ed55e800..1b48efa5 100644 --- a/nx.json +++ b/nx.json @@ -1,23 +1,4 @@ { "extends": "nx/presets/npm.json", - "$schema": "./node_modules/nx/schemas/nx-schema.json", - "tasksRunnerOptions": { - "default": { - "runner": "nx-cloud", - "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - "restore", - "format", - "sonarqube", - "pack", - "push" - ], - "accessToken": "NTAzMmE4OGMtY2FjMC00ZmFiLTgwMzktOGE5NDQxNTcxODVlfHJlYWQtd3JpdGU=" - } - } - } + "$schema": "./node_modules/nx/schemas/nx-schema.json" } \ No newline at end of file diff --git a/package.json b/package.json index c4d55d85..c8c7c893 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,13 @@ "name": "codedesignplus", "version": "0.0.0", "license": "LGPL", - "scripts": { + "scripts": { "affected": "npx nx show projects --affected --skip-nx-cache --head=HEAD --base=remotes/origin/main", "affected:restore": "npx nx affected --skip-nx-cache --target restore --head=HEAD --base=remotes/origin/main", "affected:format": "npx nx affected --skip-nx-cache --target format --head=HEAD --base=remotes/origin/main", "affected:build": "npx nx affected --skip-nx-cache --parallel 1 --target build --head=HEAD --base=remotes/origin/main", "affected:test": "npx nx affected --skip-nx-cache --target test --head=HEAD --base=remotes/origin/main", - "affected:sonarqube": "npx nx affected --skip-nx-cache --parallel 1 --target sonarqube --head=HEAD --base=remotes/origin/main", + "affected:sonarqube": "npx nx affected --skip-nx-cache --parallel 1 --target sonarqube --head=HEAD --base=remotes/origin/main", "affected:graph": "npx nx affected --skip-nx-cache --target dep-graph --head=HEAD --base=remotes/origin/main", "all:restore": "npx nx run-many --all --skip-nx-cache --target restore --parallel 1 ", "all:format": "npx nx run-many --all --skip-nx-cache --target format", @@ -22,13 +22,12 @@ "all-cache:sonarqube": "npx nx run-many --all --target sonarqube --parallel 1" }, "private": true, - "dependencies": { - }, "devDependencies": { + "@codedesignplus/netcore": "^1.0.3-rc.0", + "@nrwl/workspace": "^16.10.0", "@nx/js": "16.10.0", "nx": "16.10.0", - "nx-cloud": "latest", - "@codedesignplus/netcore": "^1.0.3-rc.0", - "@nrwl/workspace": "^16.10.0" + "nx-cloud": "latest", + "which": "^5.0.0" } } diff --git a/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/AggregateRootBase.cs b/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/AggregateRootBase.cs index a89659ac..f4de5201 100644 --- a/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/AggregateRootBase.cs +++ b/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/AggregateRootBase.cs @@ -4,7 +4,7 @@ namespace CodeDesignPlus.Net.Core.Abstractions; /// Represents the base class for aggregate roots in the domain. /// public abstract class AggregateRootBase : IAggregateRoot -{ +{ private ConcurrentQueue domainEvents = []; /// @@ -21,22 +21,31 @@ public abstract class AggregateRootBase : IAggregateRoot /// Gets or sets the timestamp when the aggregate root was created. /// public Instant CreatedAt { get; set; } - /// /// Gets or sets the unique identifier of the user who created the aggregate root. /// public Guid CreatedBy { get; set; } - /// /// Gets or sets the timestamp when the aggregate root was last updated. /// public Instant? UpdatedAt { get; set; } - /// /// Gets or sets the unique identifier of the user who last updated the aggregate root. /// public Guid? UpdatedBy { get; set; } - + /// + /// Gets or sets the timestamp when the aggregate root was deleted. + /// + public Instant? DeletedAt { get; set; } + /// + /// Gets or sets the unique identifier of the user who deleted the aggregate root. + /// + public Guid? DeletedBy { get; set; } + /// + /// Gets or sets a value indicating whether the aggregate root is deleted. + /// This property is used to mark the aggregate root as deleted without physically removing it from the database. + /// + public bool IsDeleted { get; set; } = false; /// /// Initializes a new instance of the class. diff --git a/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/IEntity.cs b/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/IEntity.cs index e5721502..a5987b6b 100644 --- a/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/IEntity.cs +++ b/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/IEntity.cs @@ -18,25 +18,38 @@ public interface IEntityBase /// public interface IEntity : IEntityBase { - /// /// Get or sets the is active /// bool IsActive { get; set; } + /// - /// Get or sets the creatae at + /// Gets or sets the timestamp when the aggregate root was created. /// Instant CreatedAt { get; set; } /// - /// Get or sets the create by + /// Gets or sets the unique identifier of the user who created the aggregate root. /// Guid CreatedBy { get; set; } /// - /// Get or sets the update at + /// Gets or sets the timestamp when the aggregate root was last updated. /// Instant? UpdatedAt { get; set; } /// - /// Get or sets the update by + /// Gets or sets the unique identifier of the user who last updated the aggregate root. /// Guid? UpdatedBy { get; set; } + /// + /// Gets or sets the timestamp when the aggregate root was deleted. + /// + Instant? DeletedAt { get; set; } + /// + /// Gets or sets the unique identifier of the user who deleted the aggregate root. + /// + Guid? DeletedBy { get; set; } + /// + /// Gets or sets a value indicating whether the aggregate root is deleted. + /// This property is used to mark the aggregate root as deleted without physically removing it from the database. + /// + bool IsDeleted { get; set; } } \ No newline at end of file diff --git a/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/Item.cs b/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/Item.cs new file mode 100644 index 00000000..e43f6678 --- /dev/null +++ b/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/Item.cs @@ -0,0 +1,9 @@ +namespace CodeDesignPlus.Net.Core.Abstractions; + +/// +/// Represents an item with a unique identifier and a value. +/// +/// The type of the value associated with the item. +/// The unique identifier of the item. +/// The value associated with the item. +public record Item(Guid Id, TValue Value); \ No newline at end of file diff --git a/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/Options/CoreOptions.cs b/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/Options/CoreOptions.cs index bfd334ae..e69307e6 100644 --- a/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/Options/CoreOptions.cs +++ b/packages/CodeDesignPlus.Net.Core/src/CodeDesignPlus.Net.Core.Abstractions/Options/CoreOptions.cs @@ -27,7 +27,8 @@ public class CoreOptions : IValidatableObject public required string AppName { get; set; } /// /// Gets or sets the type entry point (worker, rest, grpc) - /// + /// + [Required] public string TypeEntryPoint { get; set; } = null!; /// /// Gets or sets the version diff --git a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Abstractions/AggregateRootTest.cs b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Abstractions/AggregateRootTest.cs index f35aa9a1..080b68e8 100644 --- a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Abstractions/AggregateRootTest.cs +++ b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Abstractions/AggregateRootTest.cs @@ -27,6 +27,7 @@ public async Task AggregateRoot_ValidateState_Success() var createBy = Guid.NewGuid(); var updatedBy = Guid.NewGuid(); var tenant = Guid.NewGuid(); + var deletedBy = Guid.NewGuid(); var orderAggregate = OrderAggregate.Create(id, "Test", "Test Description", 10, tenant, createBy); @@ -47,7 +48,7 @@ public async Task AggregateRoot_ValidateState_Success() await Task.Delay(100); - orderAggregate.Delete(); + orderAggregate.Delete(deletedBy); await Task.Delay(100); @@ -122,6 +123,7 @@ public void Aggregate_AddEventWhenDomainEventIsNull_Success() var id = Guid.NewGuid(); var createBy = Guid.NewGuid(); var tenant = Guid.NewGuid(); + var deletedBy = Guid.NewGuid(); var orderAggregate = OrderAggregate.Create(id, "Test", "Test Description", 10, tenant, createBy); @@ -129,7 +131,7 @@ public void Aggregate_AddEventWhenDomainEventIsNull_Success() domainEventsField!.SetValue(orderAggregate, null); // Act - orderAggregate.Delete(); + orderAggregate.Delete(deletedBy); // Assert var events = orderAggregate.GetAndClearEvents(); diff --git a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Abstractions/ItemTest.cs b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Abstractions/ItemTest.cs new file mode 100644 index 00000000..fef14d2b --- /dev/null +++ b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Abstractions/ItemTest.cs @@ -0,0 +1,50 @@ +namespace CodeDesignPlus.Net.Core.Test.Abstractions; + +public class ItemTest +{ + [Fact] + public void Constructor_ShouldSetProperties() + { + // Arrange + var id = Guid.NewGuid(); + var value = "TestValue"; + + // Act + var item = new Item(id, value); + + // Assert + Assert.Equal(id, item.Id); + Assert.Equal(value, item.Value); + } + + [Fact] + public void Records_WithSameValues_ShouldBeEqual() + { + // Arrange + var id = Guid.NewGuid(); + var value = 42; + + // Act + var item1 = new Item(id, value); + var item2 = new Item(id, value); + + // Assert + Assert.Equal(item1, item2); + Assert.True(item1 == item2); + } + + [Fact] + public void Records_WithDifferentValues_ShouldNotBeEqual() + { + // Arrange + var id = Guid.NewGuid(); + + // Act + var item1 = new Item(id, 1); + var item2 = new Item(id, 2); + + // Assert + Assert.NotEqual(item1, item2); + Assert.False(item1 == item2); + } +} diff --git a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/ConfigurationUtil.cs b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/ConfigurationUtil.cs index 351eb5ef..41eb9e0c 100644 --- a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/ConfigurationUtil.cs +++ b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/ConfigurationUtil.cs @@ -8,6 +8,7 @@ public static class ConfigurationUtil { Business = nameof(Core.Abstractions.Options.CoreOptions.Business), AppName = "ms-test", + TypeEntryPoint = "rest", Version = "v1", Description = nameof(Core.Abstractions.Options.CoreOptions.Description), Contact = new Contact() diff --git a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/Context/FakeEntity.cs b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/Context/FakeEntity.cs index 94199d57..fbfe6229 100644 --- a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/Context/FakeEntity.cs +++ b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/Context/FakeEntity.cs @@ -10,5 +10,9 @@ public class FakeEntity : IEntity public Instant? UpdatedAt { get; set; } public Guid? UpdatedBy { get; set; } public bool IsActive { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } + } } diff --git a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/Domain/OrderAggregate.cs b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/Domain/OrderAggregate.cs index 807c4b05..2bc78bf0 100644 --- a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/Domain/OrderAggregate.cs +++ b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Helpers/Domain/OrderAggregate.cs @@ -20,18 +20,17 @@ public OrderAggregate(Guid id, string name, string description, decimal price) : public decimal Price { get; private set; } - - public static OrderAggregate Create(Guid id, string name, string description, decimal price, Guid tenant, Guid createBy) { var aggregate = new OrderAggregate(id, name, description, price) { - CreatedAt = SystemClock.Instance.GetCurrentInstant(), - CreatedBy = createBy, IsActive = true, Tenant = tenant }; + aggregate.CreatedAt = SystemClock.Instance.GetCurrentInstant(); + aggregate.CreatedBy = createBy; + aggregate.AddEvent(new OrderCreatedDomainEvent(id, name, description, price, SystemClock.Instance.GetCurrentInstant(), createBy, null, metadata: new Dictionary { { "MetaKey1", "Value1" } @@ -51,10 +50,12 @@ public void Update(string name, string description, decimal price, Guid updatedB AddEvent(new OrderUpdatedDomainEvent(Id, name, description, price, UpdatedAt, updatedBy)); } - public void Delete() + public void Delete(Guid deletedBy) { - UpdatedAt = SystemClock.Instance.GetCurrentInstant(); + DeletedAt = SystemClock.Instance.GetCurrentInstant(); + DeletedBy = deletedBy; + IsDeleted = true; - AddEvent(new OrderDeletedDomainEvent(Id, UpdatedAt)); + AddEvent(new OrderDeletedDomainEvent(Id, DeletedAt)); } } diff --git a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Options/CoreOptionsTest.cs b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Options/CoreOptionsTest.cs index b64b0ad5..f0f552f4 100644 --- a/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Options/CoreOptionsTest.cs +++ b/packages/CodeDesignPlus.Net.Core/tests/CodeDesignPlus.Net.Core.Test/Options/CoreOptionsTest.cs @@ -11,6 +11,7 @@ public void CoreOptions_DefaultValues_Valid() Id = Guid.NewGuid(), Business = Guid.NewGuid().ToString(), AppName = "ms-test", + TypeEntryPoint = "rest", Version = "v1", Description = Guid.NewGuid().ToString(), Contact = new Contact() @@ -87,6 +88,7 @@ public void CoreOptions_EmailInvalid_FailedValidation() Id = Guid.NewGuid(), Business = Guid.NewGuid().ToString(), AppName = "ms-test", + TypeEntryPoint = "rest", Version = "v1", Description = Guid.NewGuid().ToString(), Contact = new Contact() diff --git a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/AppPermision.cs b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/AppPermision.cs index 3b35d472..3fc073b1 100644 --- a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/AppPermision.cs +++ b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/AppPermision.cs @@ -17,5 +17,8 @@ public class AppPermision : IEntity public Instant? UpdatedAt { get; set; } public Guid? UpdatedBy { get; set; } public Instant CreatedAt { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } } diff --git a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/Application.cs b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/Application.cs index 3bfa247f..63f0016f 100644 --- a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/Application.cs +++ b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/Application.cs @@ -19,5 +19,8 @@ public class Application : IEntity public List AppPermisions { get; set; } = []; public List RolePermisions { get; set; } = []; + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } } diff --git a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/FakeEntity.cs b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/FakeEntity.cs index 77a71697..7fb212ce 100644 --- a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/FakeEntity.cs +++ b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/FakeEntity.cs @@ -14,5 +14,8 @@ public class FakeEntity : IEntity public Instant? UpdatedAt { get; set; } public Guid? UpdatedBy { get; set; } public Guid Tenant { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } } diff --git a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/Permission.cs b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/Permission.cs index f209c7b3..a6c27446 100644 --- a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/Permission.cs +++ b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/Permission.cs @@ -17,6 +17,9 @@ public class Permission : IEntity public Guid CreatedBy { get; set; } public Instant? UpdatedAt { get; set; } public Guid? UpdatedBy { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } public List AppPermisions { get; set; } = []; public List RolePermisions { get; set; } = []; diff --git a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/RolePermission.cs b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/RolePermission.cs index 5ff0da52..375aa433 100644 --- a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/RolePermission.cs +++ b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Entities/RolePermission.cs @@ -16,6 +16,9 @@ public class RolePermission : IEntity public Guid CreatedBy { get; set; } public Instant? UpdatedAt { get; set; } public Guid? UpdatedBy { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } public Application Application { get; set; } public Permission Permission { get; set; } diff --git a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Net.EFCore.Test/Repository/RepositoryBaseTest.cs b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Net.EFCore.Test/Repository/RepositoryBaseTest.cs index 03c060aa..14e54d3f 100644 --- a/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Net.EFCore.Test/Repository/RepositoryBaseTest.cs +++ b/packages/CodeDesignPlus.Net.EFCore/tests/CodeDesignPlus.Net.EFCore.Test/Repository/RepositoryBaseTest.cs @@ -585,7 +585,7 @@ public async Task TransactionAsync_CommitedTransaction_ReturnResultDelegate() var builder = new DbContextOptionsBuilder(); - var connectionString = $"Server=localhost,{this.sqlServerContainer.Port};Database=temp1;User Id=sa;Password=Temporal1;Encrypt=True;TrustServerCertificate=True"; + var connectionString = $"Server=localhost,{this.sqlServerContainer.Port};Database=temp1;User Id=sa;Password={this.sqlServerContainer.Password};Encrypt=True;TrustServerCertificate=True"; var options = builder.UseSqlServer(connectionString, x => { @@ -633,7 +633,7 @@ public async Task TransactionAsync_RollbackTransaction_InvalidOperationException var builder = new DbContextOptionsBuilder(); - var connectionString = $"Server=localhost,{sqlServerContainer.Port};Database=temp2;User Id=sa;Password=Temporal1;Encrypt=True;TrustServerCertificate=True"; + var connectionString = $"Server=localhost,{sqlServerContainer.Port};Database=temp2;User Id=sa;Password={sqlServerContainer.Password};Encrypt=True;TrustServerCertificate=True"; var options = builder.UseSqlServer(connectionString, x => { diff --git a/packages/CodeDesignPlus.Net.EventStore.PubSub/tests/CodeDesignPlus.Net.EventStore.PubSub.Test/Services/EventStorePubSubServiceTest.cs b/packages/CodeDesignPlus.Net.EventStore.PubSub/tests/CodeDesignPlus.Net.EventStore.PubSub.Test/Services/EventStorePubSubServiceTest.cs index 1205323d..4ce5c44a 100644 --- a/packages/CodeDesignPlus.Net.EventStore.PubSub/tests/CodeDesignPlus.Net.EventStore.PubSub.Test/Services/EventStorePubSubServiceTest.cs +++ b/packages/CodeDesignPlus.Net.EventStore.PubSub/tests/CodeDesignPlus.Net.EventStore.PubSub.Test/Services/EventStorePubSubServiceTest.cs @@ -297,6 +297,7 @@ private void AddJsonStream(IConfigurationBuilder config, bool enableQueue) Id = Guid.NewGuid(), Business = "CodeDesignPlus", AppName = "ms-test", + TypeEntryPoint = "rest", Version = "v1", Description = "Description Test", Contact = new Contact diff --git a/packages/CodeDesignPlus.Net.EventStore/tests/CodeDesignPlus.Net.EventStore.Test/Helpers/OptionsUtil.cs b/packages/CodeDesignPlus.Net.EventStore/tests/CodeDesignPlus.Net.EventStore.Test/Helpers/OptionsUtil.cs index aefd8d89..550ebcde 100644 --- a/packages/CodeDesignPlus.Net.EventStore/tests/CodeDesignPlus.Net.EventStore.Test/Helpers/OptionsUtil.cs +++ b/packages/CodeDesignPlus.Net.EventStore/tests/CodeDesignPlus.Net.EventStore.Test/Helpers/OptionsUtil.cs @@ -55,6 +55,7 @@ public static CoreOptions GetCoreOptions() return new() { AppName = "AppTest", + TypeEntryPoint = "rest", Version = "1.0.0", Description = "Description Test", Business = "Business Test", diff --git a/packages/CodeDesignPlus.Net.EventStore/tests/CodeDesignPlus.Net.EventStore.Test/Services/EventStoreServiceTest.cs b/packages/CodeDesignPlus.Net.EventStore/tests/CodeDesignPlus.Net.EventStore.Test/Services/EventStoreServiceTest.cs index 24d418a7..f0cae94c 100644 --- a/packages/CodeDesignPlus.Net.EventStore/tests/CodeDesignPlus.Net.EventStore.Test/Services/EventStoreServiceTest.cs +++ b/packages/CodeDesignPlus.Net.EventStore/tests/CodeDesignPlus.Net.EventStore.Test/Services/EventStoreServiceTest.cs @@ -704,6 +704,7 @@ private IEventSourcing GetService() { Id = Guid.NewGuid(), AppName = "ms-test", + TypeEntryPoint = "rest", Version = "v1", Business = "CodeDesignPlus", Description = "Description Test", diff --git a/packages/CodeDesignPlus.Net.Kafka/tests/CodeDesignPlus.Net.Kafka.Test/Helpers/OptionUtils.cs b/packages/CodeDesignPlus.Net.Kafka/tests/CodeDesignPlus.Net.Kafka.Test/Helpers/OptionUtils.cs index f9ac638c..dbc7c081 100644 --- a/packages/CodeDesignPlus.Net.Kafka/tests/CodeDesignPlus.Net.Kafka.Test/Helpers/OptionUtils.cs +++ b/packages/CodeDesignPlus.Net.Kafka/tests/CodeDesignPlus.Net.Kafka.Test/Helpers/OptionUtils.cs @@ -7,6 +7,7 @@ public static class OptionUtils public static readonly CoreOptions CoreOptions = new() { AppName = "xunit-kafka", + TypeEntryPoint = "rest", Description = "The xunit test for the kafka library", Version = "v1", Business = "CodeDesignPlus", diff --git a/packages/CodeDesignPlus.Net.Kafka/tests/CodeDesignPlus.Net.Kafka.Test/Services/KafkaPubSubTest.cs b/packages/CodeDesignPlus.Net.Kafka/tests/CodeDesignPlus.Net.Kafka.Test/Services/KafkaPubSubTest.cs index 9e64d0ba..cb4f633c 100644 --- a/packages/CodeDesignPlus.Net.Kafka/tests/CodeDesignPlus.Net.Kafka.Test/Services/KafkaPubSubTest.cs +++ b/packages/CodeDesignPlus.Net.Kafka/tests/CodeDesignPlus.Net.Kafka.Test/Services/KafkaPubSubTest.cs @@ -177,6 +177,7 @@ private void AddJsonStream(IConfigurationBuilder config, bool enableQueue, strin { Id = Guid.NewGuid(), AppName = "ms-kafka-test", + TypeEntryPoint = "rest", Version = "v1", Business = "CodeDesignPlus", Description = "Microservice Test", diff --git a/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Client.cs b/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Client.cs index ad1fc921..d76a3d7b 100644 --- a/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Client.cs +++ b/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Client.cs @@ -21,5 +21,7 @@ public class Client : IEntity public Guid? UpdatedBy { get; set; } public Guid Tenant { get; set; } - + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } \ No newline at end of file diff --git a/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Order.cs b/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Order.cs index 6ffacaf6..60c4c5f6 100644 --- a/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Order.cs +++ b/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Order.cs @@ -16,4 +16,7 @@ public class Order : IEntity public Guid CreatedBy { get; set; } public Guid? UpdatedBy { get; set; } public Guid Tenant { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } diff --git a/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Product.cs b/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Product.cs index 6dbbf71a..61704a29 100644 --- a/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Product.cs +++ b/packages/CodeDesignPlus.Net.Mongo/tests/CodeDesignPlus.Net.Mongo.Test/Helpers/Models/Product.cs @@ -16,4 +16,7 @@ public class ProductEntity : IEntity public Guid CreatedBy { get; set; } public Instant? UpdatedAt { get; set; } public Guid? UpdatedBy { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } diff --git a/packages/CodeDesignPlus.Net.PubSub/tests/CodeDesignPlus.Net.PubSub.Test/Helpers/Models/UserEntity.cs b/packages/CodeDesignPlus.Net.PubSub/tests/CodeDesignPlus.Net.PubSub.Test/Helpers/Models/UserEntity.cs index 86389548..c44d69af 100644 --- a/packages/CodeDesignPlus.Net.PubSub/tests/CodeDesignPlus.Net.PubSub.Test/Helpers/Models/UserEntity.cs +++ b/packages/CodeDesignPlus.Net.PubSub/tests/CodeDesignPlus.Net.PubSub.Test/Helpers/Models/UserEntity.cs @@ -14,4 +14,7 @@ public class UserEntity : IEntity public Guid Id { get; set; } public string? Name { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } diff --git a/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/ConfigurationUtil.cs b/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/ConfigurationUtil.cs index 9ebf13c5..55ec5743 100644 --- a/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/ConfigurationUtil.cs +++ b/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/ConfigurationUtil.cs @@ -7,6 +7,7 @@ public static class ConfigurationUtil public static readonly CoreOptions CoreOptions = new() { AppName = "test-rabbitmq", + TypeEntryPoint = "rest", Business = "CodeDesignPlus", Description = "Test RabbitMQ", Version = "v1", diff --git a/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/NotificationEntity.cs b/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/NotificationEntity.cs index 047daa3b..1d5d5daa 100644 --- a/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/NotificationEntity.cs +++ b/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/NotificationEntity.cs @@ -14,4 +14,7 @@ public class NotificationEntity : IEntity public Guid Tenant { get; set; } public Guid Id { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } diff --git a/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/ProductEntity.cs b/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/ProductEntity.cs index 421595fe..99aaf038 100644 --- a/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/ProductEntity.cs +++ b/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/ProductEntity.cs @@ -14,4 +14,8 @@ public class ProductEntity : IEntity public string? Name { get; set; } public Guid Id { get; set; } + + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } diff --git a/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/UserEntity.cs b/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/UserEntity.cs index 0d26d7f4..bf11b488 100644 --- a/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/UserEntity.cs +++ b/packages/CodeDesignPlus.Net.RabbitMQ/tests/CodeDesignPlus.Net.RabbitMQ.Test/Helpers/Entities/UserEntity.cs @@ -14,4 +14,8 @@ public class UserEntity : IEntity public string? Name { get; set; } public Guid Id { get; set; } + + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } diff --git a/packages/CodeDesignPlus.Net.Redis.PubSub/tests/CodeDesignPlus.Net.Redis.PubSub.Test/Helpers/OptionsUtil.cs b/packages/CodeDesignPlus.Net.Redis.PubSub/tests/CodeDesignPlus.Net.Redis.PubSub.Test/Helpers/OptionsUtil.cs index 5076360c..e0858b32 100644 --- a/packages/CodeDesignPlus.Net.Redis.PubSub/tests/CodeDesignPlus.Net.Redis.PubSub.Test/Helpers/OptionsUtil.cs +++ b/packages/CodeDesignPlus.Net.Redis.PubSub/tests/CodeDesignPlus.Net.Redis.PubSub.Test/Helpers/OptionsUtil.cs @@ -9,6 +9,7 @@ public static class OptionsUtil public static readonly CoreOptions CoreOptions = new() { AppName = "ms-redis-test", + TypeEntryPoint = "rest", Business = "CodeDesignPlus", Description = "Test project for CodeDesignPlus.Net.Redis.PubSub", Version = "v1", diff --git a/packages/CodeDesignPlus.Net.gRpc.Clients/README.md b/packages/CodeDesignPlus.Net.gRpc.Clients/README.md index 96be1d94..f3e3a10e 100644 --- a/packages/CodeDesignPlus.Net.gRpc.Clients/README.md +++ b/packages/CodeDesignPlus.Net.gRpc.Clients/README.md @@ -8,7 +8,7 @@

CodeDesignPlus.Net.gRpc.Clients

- .NET Core archetype for efficient development, unit testing, and continuous integration of NuGet libraries. + .NET Core archetype for efficient development, unit testing, and continuous integration of NuGet libraries.
Explore the docs » diff --git a/packages/CodeDesignPlus.Net.gRpc.Clients/src/CodeDesignPlus.Net.gRpc.Clients/Extensions/ServiceCollectionExtensions.cs b/packages/CodeDesignPlus.Net.gRpc.Clients/src/CodeDesignPlus.Net.gRpc.Clients/Extensions/ServiceCollectionExtensions.cs index ad4ca9ca..a3983b13 100644 --- a/packages/CodeDesignPlus.Net.gRpc.Clients/src/CodeDesignPlus.Net.gRpc.Clients/Extensions/ServiceCollectionExtensions.cs +++ b/packages/CodeDesignPlus.Net.gRpc.Clients/src/CodeDesignPlus.Net.gRpc.Clients/Extensions/ServiceCollectionExtensions.cs @@ -36,7 +36,7 @@ public static IServiceCollection AddGrpcClients(this IServiceCollection services if (!string.IsNullOrEmpty(options!.Payment)) { - services.AddGrpcClient(o => + services.AddGrpcClient(o => { o.Address = new Uri(options.Payment); }); @@ -46,7 +46,7 @@ public static IServiceCollection AddGrpcClients(this IServiceCollection services if (!string.IsNullOrEmpty(options!.User)) { - services.AddGrpcClient(o => + services.AddGrpcClient(o => { o.Address = new Uri(options.User); }); @@ -56,7 +56,7 @@ public static IServiceCollection AddGrpcClients(this IServiceCollection services if (!string.IsNullOrEmpty(options!.Tenant)) { - services.AddGrpcClient(o => + services.AddGrpcClient(o => { o.Address = new Uri(options.Tenant); }); diff --git a/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/CodeDesignPlus.Net.gRpc.Clients.Test.csproj b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/CodeDesignPlus.Net.gRpc.Clients.Test.csproj index e097e3dd..190580e7 100644 --- a/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/CodeDesignPlus.Net.gRpc.Clients.Test.csproj +++ b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/CodeDesignPlus.Net.gRpc.Clients.Test.csproj @@ -31,13 +31,12 @@ + + - - - diff --git a/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Exceptions/GrpcClientsExceptionTest.cs b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Exceptions/GrpcClientsExceptionTest.cs new file mode 100644 index 00000000..2ebce49b --- /dev/null +++ b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Exceptions/GrpcClientsExceptionTest.cs @@ -0,0 +1,65 @@ + +namespace CodeDesignPlus.Net.gRpc.Clients.Test.Exceptions; + +public class GrpcClientsExceptionTest +{ + [Fact] + public void DefaultConstructor_SetsEmptyErrors() + { + var ex = new GrpcClientsException(); + Assert.NotNull(ex.Errors); + Assert.Empty(ex.Errors); + } + + [Fact] + public void Constructor_WithErrors_SetsErrors() + { + var errors = new List { "Error1", "Error2" }; + var ex = new GrpcClientsException(errors); + Assert.Equal(errors, ex.Errors); + } + + [Fact] + public void Constructor_WithMessage_SetsMessageAndEmptyErrors() + { + var message = "Test message"; + var ex = new GrpcClientsException(message); + Assert.Equal(message, ex.Message); + Assert.NotNull(ex.Errors); + Assert.Empty(ex.Errors); + } + + [Fact] + public void Constructor_WithMessageAndErrors_SetsProperties() + { + var message = "Test message"; + var errors = new List { "Error1" }; + var ex = new GrpcClientsException(message, errors); + Assert.Equal(message, ex.Message); + Assert.Equal(errors, ex.Errors); + } + + [Fact] + public void Constructor_WithMessageAndInnerException_SetsProperties() + { + var message = "Test message"; + var inner = new InvalidOperationException("Inner"); + var ex = new GrpcClientsException(message, inner); + Assert.Equal(message, ex.Message); + Assert.Same(inner, ex.InnerException); + Assert.NotNull(ex.Errors); + Assert.Empty(ex.Errors); + } + + [Fact] + public void Constructor_WithMessageErrorsAndInnerException_SetsAllProperties() + { + var message = "Test message"; + var errors = new List { "Error1", "Error2" }; + var inner = new Exception("Inner"); + var ex = new GrpcClientsException(message, errors, inner); + Assert.Equal(message, ex.Message); + Assert.Equal(errors, ex.Errors); + Assert.Same(inner, ex.InnerException); + } +} diff --git a/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Extensions/ServiceCollectionExtensionsTest.cs b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Extensions/ServiceCollectionExtensionsTest.cs new file mode 100644 index 00000000..92e55c15 --- /dev/null +++ b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Extensions/ServiceCollectionExtensionsTest.cs @@ -0,0 +1,139 @@ +using CodeDesignPlus.Net.gRpc.Clients.Abstractions.Options; +using CodeDesignPlus.Net.gRpc.Clients.Extensions; +using CodeDesignPlus.Net.gRpc.Clients.Services.Payment; +using CodeDesignPlus.Net.gRpc.Clients.Services.Tenants; +using CodeDesignPlus.Net.gRpc.Clients.Services.Users; +using Moq; + +namespace CodeDesignPlus.Net.gRpc.Clients.Test.Extensions; + +public class ServiceCollectionExtensionsTest +{ + [Fact] + public void AddGrpcClients_ThrowsArgumentNullException_WhenServicesIsNull() + { + // Arrange + IServiceCollection services = null!; + // Act & Assert + Assert.Throws(() => ServiceCollectionExtensions.AddGrpcClients(services, Mock.Of())); + } + + [Fact] + public void AddGrpcClients_ThrowsArgumentNullException_WhenConfigurationIsNull() + { + // Arrange + var services = new ServiceCollection(); + IConfiguration configuration = null!; + + // Act & Assert + Assert.Throws(() => ServiceCollectionExtensions.AddGrpcClients(services, configuration)); + } + + [Fact] + public void AddGrpcClients_RegistersPaymentClient_WhenPaymentOptionIsSet() + { + // Arrange + var services = new ServiceCollection(); + var config = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + [$"{GrpcClientsOptions.Section}:Payment"] = "http://localhost:5001" + }) + .Build(); + + // Act + services.AddGrpcClients(config); + + // Assert + var serviceProvider = services.BuildServiceProvider(); + + Assert.Contains(services, d => d.ServiceType.Name.Contains("PaymentClient")); + Assert.Contains(services, d => d.ServiceType == typeof(IPaymentGrpc) && d.ImplementationType == typeof(PaymentService)); + + var paymentService = serviceProvider.GetService(); + + Assert.NotNull(paymentService); + } + + [Fact] + public void AddGrpcClients_RegistersUserClient_WhenUserOptionIsSet() + { + // Arrange + var services = new ServiceCollection(); + var config = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + [$"{GrpcClientsOptions.Section}:User"] = "http://localhost:5002" + }) + .Build(); + + // Act + services.AddGrpcClients(config); + + // Assert + var serviceProvider = services.BuildServiceProvider(); + + Assert.Contains(services, d => d.ServiceType.Name.Contains("UsersClient")); + Assert.Contains(services, d => d.ServiceType == typeof(IUserGrpc) && d.ImplementationType == typeof(UserService)); + + var userService = serviceProvider.GetService(); + + Assert.NotNull(userService); + } + + [Fact] + public void AddGrpcClients_RegistersTenantClient_WhenTenantOptionIsSet() + { + // Arrange + var services = new ServiceCollection(); + var config = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + [$"{GrpcClientsOptions.Section}:Tenant"] = "http://localhost:5003" + }) + .Build(); + + // Act + services.AddGrpcClients(config); + + // Assert + var serviceProvider = services.BuildServiceProvider(); + + Assert.Contains(services, d => d.ServiceType.Name.Contains("TenantClient")); + Assert.Contains(services, d => d.ServiceType == typeof(ITenantGrpc) && d.ImplementationType == typeof(TenantService)); + + var tenantService = serviceProvider.GetService(); + Assert.NotNull(tenantService); + } + + [Fact] + public void AddGrpcClients_RegistersNothing_WhenNoOptionsAreSet() + { + // Arrange + var services = new ServiceCollection(); + + var settings = new + { + GrpcClients = new + { + Info = "No gRPC clients configured", + } + }; + + var json = JsonSerializer.Serialize(settings); + + var jsonStream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + + var config = new ConfigurationBuilder() + .AddJsonStream(jsonStream) + .Build(); + + // Act + services.AddGrpcClients(config); + + // Assert + Assert.DoesNotContain(services, d => d.ServiceType == typeof(IPaymentGrpc)); + Assert.DoesNotContain(services, d => d.ServiceType == typeof(IUserGrpc)); + Assert.DoesNotContain(services, d => d.ServiceType == typeof(ITenantGrpc)); + } +} diff --git a/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Payment/PaymentServiceTest.cs b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Payment/PaymentServiceTest.cs index 039c267f..553bdee9 100644 --- a/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Payment/PaymentServiceTest.cs +++ b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Payment/PaymentServiceTest.cs @@ -1,180 +1,131 @@ -// using System; -// using CodeDesignPlus.Net.gRpc.Clients.Abstractions.Options; -// using CodeDesignPlus.Net.gRpc.Clients.Extensions; -// using CodeDesignPlus.Net.gRpc.Clients.Services.Payment; +using System; +using CodeDesignPlus.Net.gRpc.Clients.Abstractions.Options; +using CodeDesignPlus.Net.gRpc.Clients.Extensions; +using CodeDesignPlus.Net.gRpc.Clients.Services.Payment; +using CodeDesignPlus.Net.Security.Abstractions; +using CodeDesignPlus.Net.xUnit.Extensions; +using Ductus.FluentDocker.Commands; +using Moq; -// namespace CodeDesignPlus.Net.gRpc.Clients.Test.Services.Payment; +namespace CodeDesignPlus.Net.gRpc.Clients.Test.Services.Payment; -// public class PaymentServiceTest -// { -// [Fact] -// public async Task PayAsync_Temp() -// { -// var configuration = new ConfigurationBuilder() -// .AddInMemoryCollection(new Dictionary -// { -// { $"{GrpcClientsOptions.Section}:PaymenPaymenttUrl", "http://localhost:5001" } -// }) -// .Build(); +public class PaymentServiceTest +{ + [Fact] + public async Task InitiatePaymentAsync_ShouldReturnResponse_WhenCalledWithValidRequest() + { + // Arrange + var userContextMock = new Mock(); + userContextMock.Setup(uc => uc.AccessToken).Returns("test-access-token"); + userContextMock.Setup(uc => uc.Tenant).Returns(Guid.NewGuid()); -// var services = new ServiceCollection(); + var mockCall = GrpcUtil.CreateAsyncUnaryCall(new InitiatePaymentResponse + { + Message = "Payment initiated successfully", + TransactionId = Guid.NewGuid().ToString(), + RedirectUrl = "https://example.com/redirect", + Status = PaymentStatus.Pending, + Success = true, + FinancialNetwork = new FinancialNetwork + { + PaymentNetworkResponseCode = "00", + PaymentNetworkResponseErrorMessage = "Success", + TrazabilityCode = "TRAZ1234567890", + AuthorizationCode = "AUTH123456", + ResponseCode = "00", + } + }); - -// services.AddGrpcClients(configuration); -// var serviceProvider = services.BuildServiceProvider(); + var mockClient = new Mock(); + mockClient + .Setup(m => m.InitiatePaymentAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None)) + .Returns(mockCall); -// var paymentService = serviceProvider.GetRequiredService(); + var paymentService = new PaymentService(mockClient.Object, userContextMock.Object); + var request = new InitiatePaymentRequest + { + Description = "Test Payment", + Id = Guid.NewGuid().ToString(), + Module = "TestModule", + Payer = new Payer + { + BillingAddress = new Address + { + City = "Test City", + Country = "Test Country", + Street = "123 Test St", + PostalCode = "12345", + State = "Test State", + Phone = "123-456-7890" + }, + }, + PaymentMethod = new PaymentMethod + { + Type = "creditCard", + CreditCard = new CreditCard + { + Number = "4111111111111111", + ExpirationDate = "2025/12", + SecurityCode = "123", + InstallmentsNumber = 1, + Name = "Test User", + } + }, + Provider = PaymentProvider.Payu, + SubTotal = new Amount() + { + Currency = "USD", + Value = 100, + }, + Total = new Amount() + { + Currency = "USD", + Value = 100, + }, + Tax = new Amount() + { + Currency = "USD", + Value = 0, + }, + }; -// var request = new PayRequest() -// { -// Id = Guid.NewGuid().ToString(), -// Transaction = new Transaction -// { -// Order = new Order -// { -// Description = "Custom Description", -// Buyer = new Buyer -// { -// FullName = "Wilzon Liscano", -// EmailAddress = "wliscano@codedesignplus.com", -// ContactPhone = "3107545341", -// DniNumber = "1022389704", -// ShippingAddress = new Address -// { -// Street = "Calle 3a 53c 13", -// Country = "CO", -// State = "Bogota D.C", -// City = "Bogota D.C", -// PostalCode = "111611", -// Phone = "3107545341" -// }, -// }, -// Amount = new Amount -// { -// Value = 150000, -// Currency = "COP" -// }, -// Tax = new Amount -// { -// Value = 0, -// Currency = "COP" -// }, -// TaxReturnBase = new Amount -// { -// Value = 0, -// Currency = "COP" -// } -// }, -// Payer = new Payer -// { -// FullName = "Wilzon Liscano Galindo", -// EmailAddress = "wliscano@codedesignplus.com", -// DniNumber = "1022389704", -// DniType = "CC", -// ContactPhone = "3107545341", -// BillingAddress = new Address -// { -// Street = "Calle 3a 53c 13", -// Country = "CO", -// State = "Bogota D.C", -// City = "Bogota D.C", -// PostalCode = "111611", -// Phone = "3107545341" -// } -// }, -// CreditCard = new CreditCard -// { -// Number = "4037997623271984", -// SecurityCode = "321", -// ExpirationDate = "2030/12", -// Name = "APPROVED" -// }, -// Pse = null!, -// DeviceSessionId = "vghs6tvkcle931686k1900o6e1", -// IpAddress = "127.0.0.1", -// Cookie = "pt1t38347bs6jc9ruv2ecpv7o2", -// UserAgent = "Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0" -// } -// }; + // Act + var response = await paymentService.InitiatePaymentAsync(request, CancellationToken.None); -// try -// { -// await paymentService.PayAsync(request, CancellationToken.None); - -// } -// catch (Exception ex) -// { -// Assert.Fail($"Payment failed: {ex.Message}"); -// } -// } -// } + // Assert + Assert.NotNull(response); + mockClient.Verify(c => c.InitiatePaymentAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } -// //Request -// /* -// { -// "id": "{{$guid}}", -// "transaction": { -// "order": { -// "description": "Custom Description", -// "buyer": { -// "fullName": "Wilzon Liscano", -// "emailAddress": "wliscano@codedesignplus.com", -// "contactPhone": "3107545341", -// "dniNumber": "1022389704", -// "shippingAddress": { -// "street": "Calle 3a 53c 13", -// "country": "CO", -// "state": "Bogota D.C", -// "city": "Bogota D.C", -// "postalCode": "111611", -// "phone": "3107545341" -// } -// }, -// "ammount": { -// "value": 150000, -// "currency": "COP" -// }, -// "tax": { -// "value": 0, -// "currency": "COP" -// }, -// "taxReturnBase": { -// "value": 0, -// "currency": "COP" -// } -// }, -// "payer": { -// "fullName": "Wilzon Liscano Galindo", -// "emailAddress": "wliscano@codedesignplus.com", -// "dniNumber": "1022389704", -// "dniType": "CC", -// "contactPhone": "3107545341", -// "billingAddress": { -// "street": "Calle 3a 53c 13", -// "country": "CO", -// "state": "Bogota D.C", -// "city": "Bogota D.C", -// "postalCode": "111611", -// "phone": "3107545341" -// } -// }, -// "paymentMethod": "VISA", -// "creditCard": { -// "number": "4037997623271984", -// "securityCode": "321", -// "expirationDate": "2030/12", -// "name": "APPROVED" -// }, -// "pse": { -// "pseCode": "Bancolombia", -// "pseResponseUrl": "https://mi-tienda.com/respuesta-pse", -// "typePerson": "N" -// }, -// "deviceSessionId": "vghs6tvkcle931686k1900o6e1", -// "ipAddress": "127.0.0.1", -// "cookie": "pt1t38347bs6jc9ruv2ecpv7o2", -// "userAgent": "Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0" -// } -// } -// */ \ No newline at end of file + + [Fact] + public async Task UpdateStatusAsync_ShouldReturnResponse_WhenCalledWithValidId() + { + // Arrange + var userContextMock = new Mock(); + userContextMock.Setup(uc => uc.AccessToken).Returns("test-access-token"); + userContextMock.Setup(uc => uc.Tenant).Returns(Guid.NewGuid()); + + var mockCall = GrpcUtil.CreateAsyncUnaryCall(new UpdateStatusResponse + { + Message = "Payment status updated successfully", + Success = true, + }); + + var mockClient = new Mock(); + mockClient + .Setup(m => m.UpdateStatusAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None)) + .Returns(mockCall); + + var paymentService = new PaymentService(mockClient.Object, userContextMock.Object); + var paymentId = Guid.NewGuid(); + + // Act + var response = await paymentService.UpdateStatusAsync(paymentId, CancellationToken.None); + + // Assert + Assert.NotNull(response); + mockClient.Verify(c => c.UpdateStatusAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } +} diff --git a/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Tenant/TenantServiceTest.cs b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Tenant/TenantServiceTest.cs new file mode 100644 index 00000000..0b9bf775 --- /dev/null +++ b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Tenant/TenantServiceTest.cs @@ -0,0 +1,160 @@ +using System; +using CodeDesignPlus.Net.gRpc.Clients.Services.Tenant; +using CodeDesignPlus.Net.gRpc.Clients.Services.Tenants; +using CodeDesignPlus.Net.Security.Abstractions; +using CodeDesignPlus.Net.xUnit.Extensions; +using Moq; + +namespace CodeDesignPlus.Net.gRpc.Clients.Test.Services.Tenant; + +public class TenantServiceTest +{ + [Fact] + public async Task CreateTenantAsync_ShouldCreateTenant_WhenCalledWithValidRequest() + { + // Arrange + var userContextMock = new Mock(); + userContextMock.Setup(uc => uc.AccessToken).Returns("test-access-token"); + userContextMock.Setup(uc => uc.Tenant).Returns(Guid.NewGuid()); + + var mockCall = GrpcUtil.CreateAsyncUnaryCall(new Google.Protobuf.WellKnownTypes.Empty()); + + var mockClient = new Mock(); + mockClient + .Setup(m => m.CreateTenantAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None)) + .Returns(mockCall); + + var tenantService = new TenantService(mockClient.Object, userContextMock.Object); + var request = new CreateTenantRequest + { + Name = "Test Tenant", + Domain = "testtenant.com", + Email = "testtenant@example.com", + IsActive = true, + License = new License + { + Id = Guid.NewGuid().ToString(), + EndDate = DateTime.UtcNow.AddYears(1).ToString(), + StartDate = DateTime.UtcNow.ToString(), + }, + Location = new Location + { + City = new City + { + Id = Guid.NewGuid().ToString(), + Name = "Test City", + Timezone = "-5", + }, + Country = new Country + { + Id = Guid.NewGuid().ToString(), + Name = "Test Country", + }, + Address = "123 Test St", + PostalCode = "12345", + State = new State + { + Id = Guid.NewGuid().ToString(), + Name = "Test State", + }, + Locality = new Locality + { + Id = Guid.NewGuid().ToString(), + Name = "Test Locality", + }, + Neighborhood = new Neighborhood + { + Id = Guid.NewGuid().ToString(), + Name = "Test Neighborhood", + }, + }, + Id = Guid.NewGuid().ToString(), + NumbreDocument = "123456789", + Phone = "123-456-7890", + TypeDocument = new TypeDocument + { + Name = "Test Document Type", + Code = "TD123", + }, + }; + + // Act + await tenantService.CreateTenantAsync(request, CancellationToken.None); + + // Assert + mockClient.Verify(m => m.CreateTenantAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None), Times.Once); + } + + [Fact] + public async Task GetTenantByIdAsync_ShouldReturnTenant_WhenCalledWithValidRequest() + { + // Arrange + var userContextMock = new Mock(); + userContextMock.Setup(uc => uc.AccessToken).Returns("test-access-token"); + userContextMock.Setup(uc => uc.Tenant).Returns(Guid.NewGuid()); + + var mockCall = GrpcUtil.CreateAsyncUnaryCall(new GetTenantResponse + { + Id = Guid.NewGuid().ToString(), + Name = "Test Tenant", + Domain = "testtenant.com", + Email = "testtenant@example.com", + IsActive = true, + License = new License + { + Id = Guid.NewGuid().ToString(), + EndDate = DateTime.UtcNow.AddYears(1).ToString(), + StartDate = DateTime.UtcNow.ToString(), + }, + Location = new Location + { + City = new City + { + Id = Guid.NewGuid().ToString(), + Name = "Test City", + Timezone = "-5", + }, + Country = new Country + { + Id = Guid.NewGuid().ToString(), + Name = "Test Country", + }, + Address = "123 Test St", + PostalCode = "12345", + State = new State + { + Id = Guid.NewGuid().ToString(), + Name = "Test State", + }, + Locality = new Locality + { + Id = Guid.NewGuid().ToString(), + Name = "Test Locality", + }, + Neighborhood = new Neighborhood + { + Id = Guid.NewGuid().ToString(), + Name = "Test Neighborhood", + }, + } + }); + + var mockClient = new Mock(); + mockClient + .Setup(m => m.GetTenantAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None)) + .Returns(mockCall); + + var tenantService = new TenantService(mockClient.Object, userContextMock.Object); + var request = new GetTenantRequest + { + Id = Guid.NewGuid().ToString(), + }; + // Act + var response = await tenantService.GetTenantByIdAsync(request, CancellationToken.None); + + // Assert + mockClient.Verify(m => m.GetTenantAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None), Times.Once); + + Assert.NotNull(response); + } +} diff --git a/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Users/UserServiceTest.cs b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Users/UserServiceTest.cs new file mode 100644 index 00000000..57dc2749 --- /dev/null +++ b/packages/CodeDesignPlus.Net.gRpc.Clients/tests/CodeDesignPlus.Net.gRpc.Clients.Test/Services/Users/UserServiceTest.cs @@ -0,0 +1,73 @@ +using System; +using CodeDesignPlus.Net.gRpc.Clients.Services.User; +using CodeDesignPlus.Net.gRpc.Clients.Services.Users; +using CodeDesignPlus.Net.Security.Abstractions; +using CodeDesignPlus.Net.xUnit.Extensions; +using Moq; + +namespace CodeDesignPlus.Net.gRpc.Clients.Test.Services.Users; + +public class UserServiceTest +{ + [Fact] + public async Task AddTenantToUser_ShouldAddTenant_WhenCalledWithValidRequest() + { + // Arrange + var userContextMock = new Mock(); + userContextMock.Setup(uc => uc.AccessToken).Returns("test-access-token"); + userContextMock.Setup(uc => uc.Tenant).Returns(Guid.NewGuid()); + + var mockCall = GrpcUtil.CreateAsyncUnaryCall(new Google.Protobuf.WellKnownTypes.Empty()); + + var mockClient = new Mock(); + mockClient + .Setup(m => m.AddTenantToUserAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None)) + .Returns(mockCall); + + var userService = new UserService(mockClient.Object, userContextMock.Object); + var request = new AddTenantRequest + { + Id = Guid.NewGuid().ToString(), + Tenant = new Clients.Services.User.Tenant() + { + Id = Guid.NewGuid().ToString(), + Name = "Test Tenant" + } + }; + + // Act + await userService.AddTenantToUser(request, CancellationToken.None); + + // Assert + mockClient.Verify(m => m.AddTenantToUserAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None), Times.Once); + } + + [Fact] + public async Task AddGroupToUser_ShouldAddGroup_WhenCalledWithValidRequest() + { + // Arrange + var userContextMock = new Mock(); + userContextMock.Setup(uc => uc.AccessToken).Returns("test-access-token"); + userContextMock.Setup(uc => uc.Tenant).Returns(Guid.NewGuid()); + + var mockCall = GrpcUtil.CreateAsyncUnaryCall(new Google.Protobuf.WellKnownTypes.Empty()); + + var mockClient = new Mock(); + mockClient + .Setup(m => m.AddGroupToUserAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None)) + .Returns(mockCall); + + var userService = new UserService(mockClient.Object, userContextMock.Object); + var request = new AddGroupRequest + { + Id = Guid.NewGuid().ToString(), + Role = "administrator" + }; + + // Act + await userService.AddGroupToUser(request, CancellationToken.None); + + // Assert + mockClient.Verify(m => m.AddGroupToUserAsync(It.IsAny(), It.IsAny(), It.IsAny(), CancellationToken.None), Times.Once); + } +} diff --git a/packages/CodeDesignPlus.Net.xUnit.Microservice/tests/CodeDesignPlus.Net.Microservice.Domain/Entities/ClientEntity.cs b/packages/CodeDesignPlus.Net.xUnit.Microservice/tests/CodeDesignPlus.Net.Microservice.Domain/Entities/ClientEntity.cs index 40f4e804..44f7fe6a 100644 --- a/packages/CodeDesignPlus.Net.xUnit.Microservice/tests/CodeDesignPlus.Net.Microservice.Domain/Entities/ClientEntity.cs +++ b/packages/CodeDesignPlus.Net.xUnit.Microservice/tests/CodeDesignPlus.Net.Microservice.Domain/Entities/ClientEntity.cs @@ -13,4 +13,7 @@ public class ClientEntity : IEntity public Instant? UpdatedAt { get; set; } public Guid? UpdatedBy { get; set; } public Guid Tenant { get; set; } + public Instant? DeletedAt { get; set; } + public Guid? DeletedBy { get; set; } + public bool IsDeleted { get; set; } } diff --git a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Containers/SqlServer/SqlServerContainer.cs b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Containers/SqlServer/SqlServerContainer.cs index 2ec485af..1a814512 100644 --- a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Containers/SqlServer/SqlServerContainer.cs +++ b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Containers/SqlServer/SqlServerContainer.cs @@ -5,6 +5,7 @@ namespace CodeDesignPlus.Net.xUnit.Containers.SqlServer; ///

public class SqlServerContainer : DockerCompose { + public string Password { get; private set; } = GeneratePassword(); /// /// Builds the Docker Compose service configuration for the SQL Server container. /// @@ -17,14 +18,18 @@ protected override ICompositeService Build() // Configure the Docker Compose settings. var dockerCompose = new DockerComposeConfig { - ComposeFilePath = new[] { file }, + ComposeFilePath = [file], ForceRecreate = true, RemoveOrphans = true, StopOnDispose = true, AlternativeServiceName = "sql_" + Guid.NewGuid().ToString("N"), + EnvironmentNameValue = new Dictionary + { + { "SA_PASSWORD", this.Password }, + }, ComposeVersion = ComposeVersion.V2, }; - + // Enable port retrieval and set the internal port and container name. this.EnableGetPort = true; this.InternalPort = 1433; @@ -35,4 +40,16 @@ protected override ICompositeService Build() return compose; } + + public static string GeneratePassword() + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + var random = new Random(); + var password = new char[16]; + for (int i = 0; i < password.Length; i++) + { + password[i] = chars[random.Next(chars.Length)]; + } + return new string(password); + } } \ No newline at end of file diff --git a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Containers/SqlServer/docker-compose.yml b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Containers/SqlServer/docker-compose.yml index f80605db..023766b2 100644 --- a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Containers/SqlServer/docker-compose.yml +++ b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Containers/SqlServer/docker-compose.yml @@ -4,7 +4,7 @@ services: sqlserver: image: mcr.microsoft.com/mssql/server:2022-latest environment: - - MSSQL_SA_PASSWORD=Temporal1 + - MSSQL_SA_PASSWORD=${SA_PASSWORD} - ACCEPT_EULA=Y ports: - "0:1433" \ No newline at end of file diff --git a/packages/CodeDesignPlus.Net.xUnit/tests/CodeDesignPlus.Net.xUnit.Test/SqlServerContainerTest.cs b/packages/CodeDesignPlus.Net.xUnit/tests/CodeDesignPlus.Net.xUnit.Test/SqlServerContainerTest.cs index 689de9cd..da18336d 100644 --- a/packages/CodeDesignPlus.Net.xUnit/tests/CodeDesignPlus.Net.xUnit.Test/SqlServerContainerTest.cs +++ b/packages/CodeDesignPlus.Net.xUnit/tests/CodeDesignPlus.Net.xUnit.Test/SqlServerContainerTest.cs @@ -14,7 +14,7 @@ public class SqlServerContainerTest(SqlCollectionFixture sqlCollectionFixture) public void CheckConnectionService() { // Arrange - var sqlConnection = new SqlConnection($"Server=localhost,{this.container.Port};Database=master;User Id=sa;Password=Temporal1;Encrypt=True;TrustServerCertificate=True"); + var sqlConnection = new SqlConnection($"Server=localhost,{this.container.Port};Database=master;User Id=sa;Password={this.container.Password};Encrypt=True;TrustServerCertificate=True"); // Act sqlConnection.Open(); diff --git a/tools/scripts/run-sonarqube.js b/tools/scripts/run-sonarqube.js index b4a5eecf..64618bb5 100644 --- a/tools/scripts/run-sonarqube.js +++ b/tools/scripts/run-sonarqube.js @@ -1,6 +1,6 @@ -// tools/scripts/run-sonarqube.js - const { execSync } = require('child_process'); +const which = require('which'); +const dotnetPath = which.sync('dotnet'); const sonarHost = process.env.SONAR_HOST_URL; const sonarToken = process.env.SONAR_TOKEN; @@ -29,8 +29,8 @@ const exclusions = { 'CodeDesignPlus.Net.Exceptions': ",**Tests*.cs", 'CodeDesignPlus.Net.File.Storage': "**/CodeDesignPlus.Net.Core/**,**/CodeDesignPlus.Net.Redis/**,**/CodeDesignPlus.Net.Security/**,**/CodeDesignPlus.Net.Serializers/**,**Tests*.cs", 'CodeDesignPlus.Net.Generator': "**Tests*.cs", - 'CodeDesignPlus.Net.gRpc.Clients': "**Tests*.cs", - 'CodeDesignPlus.Net.Kafka': "**/CodeDesignPlus.Net.Core/**,**/CodeDesignPlus.Net.PubSub/**,**/CodeDesignPlus.Net.Redis/**,**/CodeDesignPlus.Net.Serializers/**,**Tests*.cs", + 'CodeDesignPlus.Net.gRpc.Clients': "**/CodeDesignPlus.Net.Core/**,**/CodeDesignPlus.Net.Redis/**,**/CodeDesignPlus.Net.Serializers/**,**/CodeDesignPlus.Net.Security/**,**Tests*.cs", + 'CodeDesignPlus.Net.Kafka': "**/CodeDesignPlus.Net.Core/**,**/CodeDesignPlus.Net.PubSub/**,**/CodeDesignPlus.Net.Redis/**,**/CodeDesignPlus.Net.Exceptions/**,**/CodeDesignPlus.Net.Serializers/**,**Tests*.cs", 'CodeDesignPlus.Net.Logger': "**/CodeDesignPlus.Net.Core/**,**/CodeDesignPlus.Net.Redis/**,**/CodeDesignPlus.Net.Serializers/**,**Tests*.cs", 'CodeDesignPlus.Net.Microservice.Commons': "**/CodeDesignPlus.Net.Core/**,**/CodeDesignPlus.Net.Exceptions/**,**/CodeDesignPlus.Net.Serializers/**,**Tests*.cs", 'CodeDesignPlus.Net.Mongo': "**/CodeDesignPlus.Net.Core/**,**/CodeDesignPlus.Net.Criteria/**,**/CodeDesignPlus.Net.Mongo.Diagnostics/**,**/CodeDesignPlus.Net.Redis/**,**/CodeDesignPlus.Net.Security/**,**/CodeDesignPlus.Net.Serializers/**,**Tests*.cs", @@ -61,15 +61,51 @@ console.log(`\n Exclusions for project ${projectKey}: ${exclusions[projectKey] | const joinedCommand = `dotnet test ${projectRoot}/${projectKey}.sln /p:CollectCoverage=true /p:CoverletOutputFormat=opencover && ` + - `dotnet sonarscanner begin /o:${org} /k:${projectKey} /d:sonar.host.url=${sonarHost} /d:sonar.cs.opencover.reportsPaths=${projectRoot}/tests/${projectKey}.Test/coverage.opencover.xml /d:sonar.javascript.enabled=false /d:sonar.architecture.enabled=false /d:sonar.coverage.exclusions=\"${exclusions[projectKey]}\" /d:sonar.login=${sonarToken} && ` + + `dotnet sonarscanner begin /o:${org} /k:${projectKey} /d:sonar.host.url=${sonarHost} /d:sonar.cs.opencover.reportsPaths=${projectRoot}/tests/${projectKey}.Test/coverage.opencover.xml /d:sonar.javascript.enabled=false /d:sonar.architecture.enabled=false /d:sonar.coverage.exclusions=${exclusions[projectKey]},**/*.js /d:sonar.login=${sonarToken} && ` + `dotnet build ${projectRoot}/${projectKey}.sln && ` + `dotnet sonarscanner end /d:sonar.token=${sonarToken}`; try { + // Ejecutar los comandos por separado para evitar inyección de comandos + const path = require('path'); + const { execFileSync } = require('child_process'); + + // 1. dotnet test + execFileSync(dotnetPath, [ + 'test', + path.join(projectRoot, `${projectKey}.sln`), + '/p:CollectCoverage=true', + '/p:CoverletOutputFormat=opencover' + ], { stdio: 'inherit' }); + + // 2. dotnet sonarscanner begin + execFileSync(dotnetPath, [ + 'sonarscanner', + 'begin', + `/o:${org}`, + `/k:${projectKey}`, + `/d:sonar.host.url=${sonarHost}`, + `/d:sonar.cs.opencover.reportsPaths=${path.join(projectRoot, 'tests', projectKey + '.Test', 'coverage.opencover.xml')}`, + '/d:sonar.javascript.enabled=false', + '/d:sonar.architecture.enabled=false', + `/d:sonar.coverage.exclusions=${exclusions[projectKey]},**/*.js`, + `/d:sonar.login=${sonarToken}` + ], { stdio: 'inherit' }); + + // 3. dotnet build + execFileSync(dotnetPath, [ + 'build', + path.join(projectRoot, `${projectKey}.sln`) + ], { stdio: 'inherit' }); + + // 4. dotnet sonarscanner end + execFileSync(dotnetPath, [ + 'sonarscanner', + 'end', + `/d:sonar.token=${sonarToken}` + ], { stdio: 'inherit' }); - execSync(joinedCommand, { stdio: 'inherit' }); console.log('\n✅ SonarQube analysis completed successfully.'); - } catch (error) { console.error('\n❌ ERROR: A command failed during SonarQube analysis.'); if (error instanceof Error) {