diff --git a/ECMJobRunner.Application/Behaviors/CheckQueryExecutionBehavior.cs b/ECMJobRunner.Application/Behaviors/CheckQueryExecutionBehavior.cs index 14a8083..cfd3970 100644 --- a/ECMJobRunner.Application/Behaviors/CheckQueryExecutionBehavior.cs +++ b/ECMJobRunner.Application/Behaviors/CheckQueryExecutionBehavior.cs @@ -1,9 +1,9 @@ using ECMJobRunner.Application.Common.Constants; using ECMJobRunner.Application.Common.Dtos; using ECMJobRunner.Application.Common.Exceptions; -using ECMJobRunner.Domain.Interfaces; +using ECMJobRunner.Application.Common.Interfaces; using ECMJobRunner.Application.Common.Options; -using ECMJobRunner.Application.DEXJob; +using ECMJobRunner.Application.DEXJob.Commands; using MediatR; using Microsoft.Extensions.Options; using System; diff --git a/ECMJobRunner.Application/Behaviors/MainQueryExecutionBehavior.cs b/ECMJobRunner.Application/Behaviors/MainQueryExecutionBehavior.cs index c6b12e6..6c7ca5f 100644 --- a/ECMJobRunner.Application/Behaviors/MainQueryExecutionBehavior.cs +++ b/ECMJobRunner.Application/Behaviors/MainQueryExecutionBehavior.cs @@ -1,9 +1,9 @@ using ECMJobRunner.Application.Common.Constants; using ECMJobRunner.Application.Common.Dtos; using ECMJobRunner.Application.Common.Exceptions; -using ECMJobRunner.Domain.Interfaces; +using ECMJobRunner.Application.Common.Interfaces; using ECMJobRunner.Application.Common.Options; -using ECMJobRunner.Application.DEXJob; +using ECMJobRunner.Application.DEXJob.Commands; using MediatR; using Microsoft.Extensions.Options; using System; diff --git a/ECMJobRunner.Application/Behaviors/ReCRequestExecutionBehavior.cs b/ECMJobRunner.Application/Behaviors/ReCRequestExecutionBehavior.cs index 26decd3..1b5455b 100644 --- a/ECMJobRunner.Application/Behaviors/ReCRequestExecutionBehavior.cs +++ b/ECMJobRunner.Application/Behaviors/ReCRequestExecutionBehavior.cs @@ -1,7 +1,7 @@ using ECMJobRunner.Application.Common.Constants; using ECMJobRunner.Application.Common.Exceptions; using ECMJobRunner.Application.Common.Options; -using ECMJobRunner.Application.DEXJob; +using ECMJobRunner.Application.DEXJob.Commands; using MediatR; using Microsoft.Extensions.Options; using ReC.Client; diff --git a/ECMJobRunner.Application/Common/Dtos/CfgProfileDto.cs b/ECMJobRunner.Application/Common/Dtos/CfgProfileDto.cs new file mode 100644 index 0000000..893b384 --- /dev/null +++ b/ECMJobRunner.Application/Common/Dtos/CfgProfileDto.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; + +namespace ECMJobRunner.Application.Common.Dtos +{ + /// + /// Data Transfer Object for CfgProfile entity + /// Used for querying and returning profile data + /// + public class CfgProfileDto + { + /// + /// Profile ID + /// + public long Id { get; set; } + + /// + /// Active / Inactive switch + /// + public bool Active { get; set; } + + /// + /// Profile name + /// + public string ProfileName { get; set; } = null!; + + /// + /// Profile type: 0 = ADSync; 1 = GraphQL; 2 = SQL-Job; 3 = SQL and REST-Job + /// + public byte TypeId { get; set; } + + /// + /// Schedule in Cron format + /// + public string Schedule { get; set; } = null!; + + /// + /// Optional description + /// + public string? Comment { get; set; } + + /// + /// Created by + /// + public string AddedWho { get; set; } = null!; + + /// + /// Created at + /// + public DateTime AddedWhen { get; set; } + + /// + /// Modified by + /// + public string? ChangedWho { get; set; } + + /// + /// Modified at + /// + public DateTime? ChangedWhen { get; set; } + + /// + /// SQL Jobs associated with this profile + /// + public List? SqlJobs { get; set; } + } + + /// + /// Data Transfer Object for ProfileSqlJob entity + /// + public class ProfileSqlJobDto + { + /// + /// SQL Job ID + /// + public long Id { get; set; } + + /// + /// Profile ID (foreign key) + /// + public long ProfileId { get; set; } + + /// + /// Active / Inactive switch + /// + public bool Active { get; set; } + + /// + /// Execution sequence order + /// + public short Sequence { get; set; } + + /// + /// Job name + /// + public string? Name { get; set; } + + /// + /// SQL query for pre-check validation + /// + public string? SqlCheckQuery { get; set; } + + /// + /// Main SQL query to execute + /// + public string? SqlMainQuery { get; set; } + + /// + /// API command to execute + /// + public string? ApiCommand { get; set; } + + /// + /// Optional description + /// + public string? Comment { get; set; } + } +} diff --git a/ECMJobRunner.Domain/Interfaces/ISQLExecutor.cs b/ECMJobRunner.Application/Common/Interfaces/ISQLExecutor.cs similarity index 90% rename from ECMJobRunner.Domain/Interfaces/ISQLExecutor.cs rename to ECMJobRunner.Application/Common/Interfaces/ISQLExecutor.cs index 9059f65..14bf71b 100644 --- a/ECMJobRunner.Domain/Interfaces/ISQLExecutor.cs +++ b/ECMJobRunner.Application/Common/Interfaces/ISQLExecutor.cs @@ -1,7 +1,7 @@ -using System.Threading; +using System.Threading; using System.Threading.Tasks; -namespace ECMJobRunner.Domain.Interfaces +namespace ECMJobRunner.Application.Common.Interfaces { /// /// Interface for executing SQL queries and mapping results to DTOs diff --git a/ECMJobRunner.Application/Common/Mapping/ProfileMappingProfile.cs b/ECMJobRunner.Application/Common/Mapping/ProfileMappingProfile.cs new file mode 100644 index 0000000..7c31f5b --- /dev/null +++ b/ECMJobRunner.Application/Common/Mapping/ProfileMappingProfile.cs @@ -0,0 +1,23 @@ +using AutoMapper; +using ECMJobRunner.Application.Common.Dtos; +using ECMJobRunner.Domain.Entities; + +namespace ECMJobRunner.Application.Common.Mapping +{ + /// + /// AutoMapper profile for CfgProfile and ProfileSqlJob mappings + /// Maps domain entities to DTOs + /// + public class ProfileMappingProfile : Profile + { + public ProfileMappingProfile() + { + // CfgProfile -> CfgProfileDto + CreateMap() + .ForMember(dest => dest.SqlJobs, opt => opt.MapFrom(src => src.SqlJobs)); + + // ProfileSqlJob -> ProfileSqlJobDto + CreateMap(); + } + } +} diff --git a/ECMJobRunner.Application/DEXJob/Queries/GetProfileQuery.cs b/ECMJobRunner.Application/DEXJob/Queries/GetProfileQuery.cs new file mode 100644 index 0000000..18566e1 --- /dev/null +++ b/ECMJobRunner.Application/DEXJob/Queries/GetProfileQuery.cs @@ -0,0 +1,124 @@ +using AutoMapper; +using ECMJobRunner.Application.Common.Dtos; +using ECMJobRunner.Domain.Interfaces; +using MediatR; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ECMJobRunner.Application.DEXJob.Queries +{ + /// + /// Query to retrieve profiles with flexible filtering options + /// All query options are nullable - when no filters are specified, returns all profiles + /// + public class GetProfileQuery : IRequest> + { + /// + /// Profile ID to retrieve (optional) + /// When specified, returns only the profile with this ID + /// + public long? Id { get; set; } + + /// + /// Filter by active status (optional) + /// When null, returns both active and inactive profiles + /// When true, returns only active profiles + /// When false, returns only inactive profiles + /// + public bool? Active { get; set; } + + /// + /// Filter by profile type (optional) + /// When specified, returns only profiles with this type + /// Type: 0 = ADSync; 1 = GraphQL; 2 = SQL-Job; 3 = SQL and REST-Job + /// + public byte? TypeId { get; set; } + + /// + /// Filter by profile name (optional) + /// When specified, returns profiles with matching name (case-insensitive contains) + /// + public string? ProfileName { get; set; } + + /// + /// Include associated SQL jobs in the result (optional) + /// Default: true + /// + public bool IncludeSqlJobs { get; set; } = true; + } + + /// + /// Handler for GetProfileQuery + /// Retrieves profiles with optional filtering and uses AutoMapper for DTO mapping + /// + public class GetProfileQueryHandler : IRequestHandler> + { + private readonly ICfgProfileRepository _profileRepository; + private readonly IMapper _mapper; + + public GetProfileQueryHandler(ICfgProfileRepository profileRepository, IMapper mapper) + { + _profileRepository = profileRepository; + _mapper = mapper; + } + + public async Task> Handle(GetProfileQuery request, CancellationToken cancellationToken) + { + IEnumerable profiles; + + // If ID is specified, get single profile by ID + if (request.Id.HasValue) + { + var profile = request.IncludeSqlJobs + ? await _profileRepository.GetByIdWithSqlJobsAsync(request.Id.Value, cancellationToken) + : await _profileRepository.GetByIdAsync(request.Id.Value, cancellationToken); + + profiles = profile != null ? new[] { profile } : []; + } + // Otherwise, get profiles with filters + else + { + // Get all profiles with SQL jobs if requested + if (request.IncludeSqlJobs) + { + // If Active filter is specified and true, use optimized method + if (request.Active.HasValue && request.Active.Value) + { + profiles = await _profileRepository.GetAllActiveWithSqlJobsAsync(cancellationToken); + } + else + { + // Generic query with filters + profiles = await _profileRepository.FindAsync(p => true, cancellationToken); + } + } + else + { + profiles = await _profileRepository.GetAllAsync(cancellationToken); + } + + // Apply filters + if (request.Active.HasValue) + { + profiles = profiles.Where(p => p.Active == request.Active.Value); + } + + if (request.TypeId.HasValue) + { + profiles = profiles.Where(p => p.TypeId == request.TypeId.Value); + } + + if (!string.IsNullOrWhiteSpace(request.ProfileName)) + { + var searchName = request.ProfileName.ToLowerInvariant(); + profiles = profiles.Where(p => p.ProfileName.ToLowerInvariant().Contains(searchName)); + } + } + + // Use AutoMapper to map entities to DTOs + return _mapper.Map>(profiles.ToList()); + } + } +} diff --git a/ECMJobRunner.Domain/Interfaces/ICfgProfileRepository.cs b/ECMJobRunner.Domain/Interfaces/ICfgProfileRepository.cs index 06adc20..81951f4 100644 --- a/ECMJobRunner.Domain/Interfaces/ICfgProfileRepository.cs +++ b/ECMJobRunner.Domain/Interfaces/ICfgProfileRepository.cs @@ -1,4 +1,7 @@ using ECMJobRunner.Domain.Entities; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; namespace ECMJobRunner.Domain.Interfaces { @@ -7,6 +10,19 @@ namespace ECMJobRunner.Domain.Interfaces /// public interface ICfgProfileRepository : IRepository { - // Add custom CfgProfile-specific methods here if needed + /// + /// Gets a profile by ID with associated SQL jobs eagerly loaded + /// + /// Profile ID + /// Cancellation token + /// Profile with SQL jobs or null if not found + Task GetByIdWithSqlJobsAsync(long id, CancellationToken cancellationToken = default); + + /// + /// Gets all active profiles with associated SQL jobs eagerly loaded + /// + /// Cancellation token + /// List of active profiles with SQL jobs + Task> GetAllActiveWithSqlJobsAsync(CancellationToken cancellationToken = default); } } diff --git a/ECMJobRunner.Infrastructure/DependencyExtension.cs b/ECMJobRunner.Infrastructure/DependencyExtension.cs index 5fdb885..832c5a4 100644 --- a/ECMJobRunner.Infrastructure/DependencyExtension.cs +++ b/ECMJobRunner.Infrastructure/DependencyExtension.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; #endif +using ECMJobRunner.Application.Common.Interfaces; using ECMJobRunner.Domain.Interfaces; using ECMJobRunner.Infrastructure.Data; using ECMJobRunner.Infrastructure.Repositories; diff --git a/ECMJobRunner.Infrastructure/ECMJobRunner.Infrastructure.csproj b/ECMJobRunner.Infrastructure/ECMJobRunner.Infrastructure.csproj index c75d7d5..a7272d7 100644 --- a/ECMJobRunner.Infrastructure/ECMJobRunner.Infrastructure.csproj +++ b/ECMJobRunner.Infrastructure/ECMJobRunner.Infrastructure.csproj @@ -17,6 +17,7 @@ + @@ -28,8 +29,8 @@ - - + + diff --git a/ECMJobRunner.Infrastructure/Repositories/CfgProfileRepository.cs b/ECMJobRunner.Infrastructure/Repositories/CfgProfileRepository.cs index 71e2375..af69dfd 100644 --- a/ECMJobRunner.Infrastructure/Repositories/CfgProfileRepository.cs +++ b/ECMJobRunner.Infrastructure/Repositories/CfgProfileRepository.cs @@ -2,6 +2,15 @@ using AutoMapper; using ECMJobRunner.Domain.Entities; using ECMJobRunner.Domain.Interfaces; using ECMJobRunner.Infrastructure.Data; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +#if NET48 +using System.Data.Entity; +#else +using Microsoft.EntityFrameworkCore; +#endif namespace ECMJobRunner.Infrastructure.Repositories { @@ -17,6 +26,25 @@ namespace ECMJobRunner.Infrastructure.Repositories { } - // Entity-specific methods can be added here in the future + /// + /// Gets a profile by ID with associated SQL jobs eagerly loaded + /// + public async Task GetByIdWithSqlJobsAsync(long id, CancellationToken cancellationToken = default) + { + return await _context.CfgProfiles + .Include(p => p.SqlJobs) + .FirstOrDefaultAsync(p => p.Id == id, cancellationToken); + } + + /// + /// Gets all active profiles with associated SQL jobs eagerly loaded + /// + public async Task> GetAllActiveWithSqlJobsAsync(CancellationToken cancellationToken = default) + { + return await _context.CfgProfiles + .Include(p => p.SqlJobs) + .Where(p => p.Active) + .ToListAsync(cancellationToken); + } } } diff --git a/ECMJobRunner.Infrastructure/Services/SQLExecutor.cs b/ECMJobRunner.Infrastructure/Services/SQLExecutor.cs index 0b4d942..b13170d 100644 --- a/ECMJobRunner.Infrastructure/Services/SQLExecutor.cs +++ b/ECMJobRunner.Infrastructure/Services/SQLExecutor.cs @@ -4,7 +4,7 @@ using System.Linq; #else using Microsoft.EntityFrameworkCore; #endif -using ECMJobRunner.Domain.Interfaces; +using ECMJobRunner.Application.Common.Interfaces; using ECMJobRunner.Infrastructure.Data; using System.Threading; using System.Threading.Tasks; diff --git a/ECMJobRunner.Tests/Application/CheckQueryExecutionBehaviorTests.cs b/ECMJobRunner.Tests/Application/CheckQueryExecutionBehaviorTests.cs index 3099baf..fcf0447 100644 --- a/ECMJobRunner.Tests/Application/CheckQueryExecutionBehaviorTests.cs +++ b/ECMJobRunner.Tests/Application/CheckQueryExecutionBehaviorTests.cs @@ -2,9 +2,9 @@ using ECMJobRunner.Application.Behaviors; using ECMJobRunner.Application.Common.Constants; using ECMJobRunner.Application.Common.Dtos; using ECMJobRunner.Application.Common.Exceptions; -using ECMJobRunner.Domain.Interfaces; +using ECMJobRunner.Application.Common.Interfaces; using ECMJobRunner.Application.Common.Options; -using ECMJobRunner.Application.DEXJob; +using ECMJobRunner.Application.DEXJob.Commands; using ECMJobRunner.Domain.Entities; using FluentAssertions; using MediatR; diff --git a/ECMJobRunner.Tests/Application/GetProfileQueryTests.cs b/ECMJobRunner.Tests/Application/GetProfileQueryTests.cs new file mode 100644 index 0000000..485aed6 --- /dev/null +++ b/ECMJobRunner.Tests/Application/GetProfileQueryTests.cs @@ -0,0 +1,302 @@ +using ECMJobRunner.Application.Common.Dtos; +using ECMJobRunner.Application.DEXJob.Queries; +using ECMJobRunner.Domain.Entities; +using ECMJobRunner.Domain.Interfaces; +using FluentAssertions; +using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace ECMJobRunner.Tests.Application +{ + public class GetProfileByIdQueryTests + { + private readonly Mock _mockProfileRepo; + private readonly GetProfileByIdQueryHandler _handler; + + public GetProfileByIdQueryTests() + { + _mockProfileRepo = new Mock(); + _handler = new GetProfileByIdQueryHandler(_mockProfileRepo.Object); + } + + [Fact] + public async Task Handle_WithValidProfileId_ReturnsProfile() + { + // Arrange + var profileId = 123L; + var profile = new CfgProfile + { + Id = profileId, + Active = true, + ProfileName = "Test Profile", + TypeId = 2, + Schedule = "0 30 4 ? * MON-SAT", + Comment = "Test comment", + AddedWho = "TestUser", + AddedWhen = DateTime.Now, + SqlJobs = new List + { + new ProfileSqlJob + { + Id = 1, + ProfileId = profileId, + Active = true, + Sequence = 1, + Name = "Job 1", + SqlMainQuery = "SELECT 1", + SqlCheckQuery = "SELECT COUNT(*) FROM Table1" + } + } + }; + + _mockProfileRepo + .Setup(r => r.GetByIdWithSqlJobsAsync(profileId, It.IsAny())) + .ReturnsAsync(profile); + + var query = new GetProfileByIdQuery { ProfileId = profileId, IncludeSqlJobs = true }; + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + result.Should().NotBeNull(); + result!.Id.Should().Be(profileId); + result.ProfileName.Should().Be("Test Profile"); + result.Active.Should().BeTrue(); + result.TypeId.Should().Be(2); + result.SqlJobs.Should().NotBeNull(); + result.SqlJobs!.Count.Should().Be(1); + result.SqlJobs[0].Name.Should().Be("Job 1"); + } + + [Fact] + public async Task Handle_WithNonExistentProfileId_ReturnsNull() + { + // Arrange + var profileId = 999L; + _mockProfileRepo + .Setup(r => r.GetByIdWithSqlJobsAsync(profileId, It.IsAny())) + .ReturnsAsync((CfgProfile?)null); + + var query = new GetProfileByIdQuery { ProfileId = profileId }; + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public async Task Handle_WithIncludeSqlJobsFalse_DoesNotLoadSqlJobs() + { + // Arrange + var profileId = 123L; + var profile = new CfgProfile + { + Id = profileId, + Active = true, + ProfileName = "Test Profile", + TypeId = 2, + Schedule = "0 30 4 ? * MON-SAT", + AddedWho = "TestUser", + AddedWhen = DateTime.Now + }; + + _mockProfileRepo + .Setup(r => r.GetByIdAsync(profileId, It.IsAny())) + .ReturnsAsync(profile); + + var query = new GetProfileByIdQuery { ProfileId = profileId, IncludeSqlJobs = false }; + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + result.Should().NotBeNull(); + result!.SqlJobs.Should().BeNull(); + _mockProfileRepo.Verify( + r => r.GetByIdAsync(profileId, It.IsAny()), + Times.Once); + _mockProfileRepo.Verify( + r => r.GetByIdWithSqlJobsAsync(It.IsAny(), It.IsAny()), + Times.Never); + } + + [Fact] + public async Task Handle_MapsAllProperties_Correctly() + { + // Arrange + var profileId = 123L; + var addedWhen = new DateTime(2026, 1, 1, 10, 0, 0); + var changedWhen = new DateTime(2026, 1, 2, 14, 30, 0); + + var profile = new CfgProfile + { + Id = profileId, + Active = false, + ProfileName = "Inactive Profile", + TypeId = 3, + Schedule = "0 0 12 * * ?", + Comment = "Detailed comment", + AddedWho = "Admin", + AddedWhen = addedWhen, + ChangedWho = "Editor", + ChangedWhen = changedWhen + }; + + _mockProfileRepo + .Setup(r => r.GetByIdAsync(profileId, It.IsAny())) + .ReturnsAsync(profile); + + var query = new GetProfileByIdQuery { ProfileId = profileId, IncludeSqlJobs = false }; + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + result.Should().NotBeNull(); + result!.Id.Should().Be(profileId); + result.Active.Should().BeFalse(); + result.ProfileName.Should().Be("Inactive Profile"); + result.TypeId.Should().Be(3); + result.Schedule.Should().Be("0 0 12 * * ?"); + result.Comment.Should().Be("Detailed comment"); + result.AddedWho.Should().Be("Admin"); + result.AddedWhen.Should().Be(addedWhen); + result.ChangedWho.Should().Be("Editor"); + result.ChangedWhen.Should().Be(changedWhen); + } + } + + public class GetAllActiveProfilesQueryTests + { + private readonly Mock _mockProfileRepo; + private readonly GetAllActiveProfilesQueryHandler _handler; + + public GetAllActiveProfilesQueryTests() + { + _mockProfileRepo = new Mock(); + _handler = new GetAllActiveProfilesQueryHandler(_mockProfileRepo.Object); + } + + [Fact] + public async Task Handle_ReturnsAllActiveProfiles() + { + // Arrange + var profiles = new List + { + new CfgProfile + { + Id = 1, + Active = true, + ProfileName = "Profile 1", + TypeId = 2, + Schedule = "0 30 4 ? * MON-SAT", + AddedWho = "User1", + AddedWhen = DateTime.Now, + SqlJobs = new List + { + new ProfileSqlJob { Id = 1, ProfileId = 1, Sequence = 1, Name = "Job 1" } + } + }, + new CfgProfile + { + Id = 2, + Active = true, + ProfileName = "Profile 2", + TypeId = 3, + Schedule = "0 0 12 * * ?", + AddedWho = "User2", + AddedWhen = DateTime.Now, + SqlJobs = new List + { + new ProfileSqlJob { Id = 2, ProfileId = 2, Sequence = 1, Name = "Job 2" } + } + } + }; + + _mockProfileRepo + .Setup(r => r.GetAllActiveWithSqlJobsAsync(It.IsAny())) + .ReturnsAsync(profiles); + + var query = new GetAllActiveProfilesQuery { IncludeSqlJobs = true }; + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + result.Should().NotBeNull(); + result.Count.Should().Be(2); + result[0].ProfileName.Should().Be("Profile 1"); + result[1].ProfileName.Should().Be("Profile 2"); + result[0].SqlJobs.Should().NotBeNull(); + result[0].SqlJobs!.Count.Should().Be(1); + result[1].SqlJobs.Should().NotBeNull(); + result[1].SqlJobs!.Count.Should().Be(1); + } + + [Fact] + public async Task Handle_WithNoActiveProfiles_ReturnsEmptyList() + { + // Arrange + _mockProfileRepo + .Setup(r => r.GetAllActiveWithSqlJobsAsync(It.IsAny())) + .ReturnsAsync(new List()); + + var query = new GetAllActiveProfilesQuery(); + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + result.Should().NotBeNull(); + result.Count.Should().Be(0); + } + + [Fact] + public async Task Handle_WithIncludeSqlJobsFalse_DoesNotLoadSqlJobs() + { + // Arrange + var profiles = new List + { + new CfgProfile + { + Id = 1, + Active = true, + ProfileName = "Profile 1", + TypeId = 2, + Schedule = "0 30 4 ? * MON-SAT", + AddedWho = "User1", + AddedWhen = DateTime.Now + } + }; + + _mockProfileRepo + .Setup(r => r.FindAsync(It.IsAny>>(), It.IsAny())) + .ReturnsAsync(profiles); + + var query = new GetAllActiveProfilesQuery { IncludeSqlJobs = false }; + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + result.Should().NotBeNull(); + result.Count.Should().Be(1); + result[0].SqlJobs.Should().BeNull(); + _mockProfileRepo.Verify( + r => r.FindAsync(It.IsAny>>(), It.IsAny()), + Times.Once); + _mockProfileRepo.Verify( + r => r.GetAllActiveWithSqlJobsAsync(It.IsAny()), + Times.Never); + } + } +} diff --git a/ECMJobRunner.Tests/Application/MainQueryExecutionBehaviorTests.cs b/ECMJobRunner.Tests/Application/MainQueryExecutionBehaviorTests.cs index 31b0232..98cf3aa 100644 --- a/ECMJobRunner.Tests/Application/MainQueryExecutionBehaviorTests.cs +++ b/ECMJobRunner.Tests/Application/MainQueryExecutionBehaviorTests.cs @@ -2,9 +2,9 @@ using ECMJobRunner.Application.Behaviors; using ECMJobRunner.Application.Common.Constants; using ECMJobRunner.Application.Common.Dtos; using ECMJobRunner.Application.Common.Exceptions; -using ECMJobRunner.Domain.Interfaces; +using ECMJobRunner.Application.Common.Interfaces; using ECMJobRunner.Application.Common.Options; -using ECMJobRunner.Application.DEXJob; +using ECMJobRunner.Application.DEXJob.Commands; using ECMJobRunner.Domain.Entities; using FluentAssertions; using MediatR;