Skip to content

Commit

Permalink
sup
Browse files Browse the repository at this point in the history
  • Loading branch information
oskogstad committed Mar 6, 2025
1 parent caa0678 commit 4b2fe2d
Show file tree
Hide file tree
Showing 12 changed files with 430 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common;

internal static class ValidationErrorStrings
{
internal const string PropertyNameMustBeLessThanOrEqualToComparisonProperty =
"'{PropertyName}' must be less than or equal to '{ComparisonProperty}'.";
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Digdir.Domain.Dialogporten.Domain.Common;
using Digdir.Domain.Dialogporten.Domain.Localizations;
using FluentValidation;
using static Digdir.Domain.Dialogporten.Application.Features.V1.Common.ValidationErrorStrings;

namespace Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search;

Expand Down Expand Up @@ -52,5 +53,20 @@ public SearchDialogQueryValidator()

RuleForEach(x => x.Status).IsInEnum();
RuleForEach(x => x.SystemLabel).IsInEnum();

RuleFor(x => x.CreatedAfter)
.LessThanOrEqualTo(x => x.CreatedBefore)
.When(x => x.CreatedAfter is not null && x.CreatedBefore is not null)
.WithMessage(PropertyNameMustBeLessThanOrEqualToComparisonProperty);

RuleFor(x => x.DueAfter)
.LessThanOrEqualTo(x => x.DueBefore)
.When(x => x.DueAfter is not null && x.DueBefore is not null)
.WithMessage(PropertyNameMustBeLessThanOrEqualToComparisonProperty);

RuleFor(x => x.UpdatedAfter)
.LessThanOrEqualTo(x => x.UpdatedBefore)
.When(x => x.UpdatedAfter is not null && x.UpdatedBefore is not null)
.WithMessage(PropertyNameMustBeLessThanOrEqualToComparisonProperty);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Digdir.Domain.Dialogporten.Domain.Parties;
using Digdir.Domain.Dialogporten.Domain.Parties.Abstractions;
using FluentValidation;
using static Digdir.Domain.Dialogporten.Application.Features.V1.Common.ValidationErrorStrings;

namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Search;

Expand Down Expand Up @@ -62,21 +63,21 @@ public SearchDialogQueryValidator()
RuleFor(x => x.CreatedAfter)
.LessThanOrEqualTo(x => x.CreatedBefore)
.When(x => x.CreatedAfter is not null && x.CreatedBefore is not null)
.WithMessage("'{PropertyName}' must be less than or equal to '{ComparisonProperty}'.");
.WithMessage(PropertyNameMustBeLessThanOrEqualToComparisonProperty);

RuleFor(x => x.DueAfter)
.LessThanOrEqualTo(x => x.DueBefore)
.When(x => x.DueAfter is not null && x.DueBefore is not null)
.WithMessage("'{PropertyName}' must be less than or equal to '{ComparisonProperty}'.");
.WithMessage(PropertyNameMustBeLessThanOrEqualToComparisonProperty);

RuleFor(x => x.UpdatedAfter)
.LessThanOrEqualTo(x => x.UpdatedBefore)
.When(x => x.UpdatedAfter is not null && x.UpdatedBefore is not null)
.WithMessage("'{PropertyName}' must be less than or equal to '{ComparisonProperty}'.");
.WithMessage(PropertyNameMustBeLessThanOrEqualToComparisonProperty);

RuleFor(x => x.VisibleAfter)
.LessThanOrEqualTo(x => x.VisibleBefore)
.When(x => x.VisibleAfter is not null && x.VisibleBefore is not null)
.WithMessage("'{PropertyName}' must be less than or equal to '{ComparisonProperty}'.");
.WithMessage(PropertyNameMustBeLessThanOrEqualToComparisonProperty);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Digdir.Domain.Dialogporten.Domain.Parties;
using Digdir.Tool.Dialogporten.GenerateFakeData;
using static Digdir.Domain.Dialogporten.Application.Integration.Tests.Common.Common;

namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Common;

public sealed class DateFilterTestData
{
public int? AfterYear { get; init; }
public int? BeforeYear { get; init; }
public int ExpectedCount { get; init; }
public required int[] ExpectedYears { get; init; }
}

internal static class Common
{
internal static DateTimeOffset CreateDateFromYear(int year) => new(year, 1, 1, 0, 0, 0, TimeSpan.Zero);

internal const string UpdatedAt = "UpdatedAt";
internal const string VisibleFrom = "VisibleFrom";
internal const string DueAt = "DueAt";
internal const string CreatedAt = "CreatedAt";

// Any party will do, required for EndUser search validation
internal static string Party => NorwegianPersonIdentifier.PrefixWithSeparator + "03886595947";
}

internal static class ApplicationExtensions
{
internal static async Task<Guid> CreateDialogWithDateInYear(this DialogApplication application, int year, string dateType)
{
var date = CreateDateFromYear(year);
var createDialogCommand = dateType switch
{
UpdatedAt => DialogGenerator.GenerateFakeCreateDialogCommand(
// Requires CreatedAt to be earlier than UpdatedAt
createdAt: CreateDateFromYear(year - 1), updatedAt: date),

VisibleFrom => DialogGenerator.GenerateFakeCreateDialogCommand(
// Requires DueAt to be later than VisibleFrom
dueAt: CreateDateFromYear(year + 1), visibleFrom: date),

DueAt => DialogGenerator.GenerateFakeCreateDialogCommand(dueAt: date),
CreatedAt => DialogGenerator.GenerateFakeCreateDialogCommand(createdAt: date),
_ => throw new ArgumentException("Invalid date type", nameof(dateType))
};

createDialogCommand.Dto.Party = Party;

var createCommandResponse = await application.Send(createDialogCommand);
return createCommandResponse.AsT0.DialogId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search;
using Digdir.Domain.Dialogporten.Application.Integration.Tests.Common;
using FluentAssertions;
using static Digdir.Domain.Dialogporten.Application.Integration.Tests.Common.Common;

namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.EndUser.Dialogs.Queries.Search;

[Collection(nameof(DialogCqrsCollectionFixture))]
public class CreatedAtFilterTests : ApplicationCollectionFixture
{
public CreatedAtFilterTests(DialogApplication application) : base(application) { }

[Theory]
[InlineData(2022, null, 2, new[] { 2022, 2023 })]
[InlineData(null, 2021, 2, new[] { 2020, 2021 })]
[InlineData(2021, 2022, 2, new[] { 2021, 2022 })]
public async Task Should_Filter_On_Created_Date(int? createdAfterYear, int? createdBeforeYear, int expectedCount, int[] expectedYears)
{
// Arrange
var dialogIn2020 = await Application.CreateDialogWithDateInYear(2020, CreatedAt);
var dialogIn2021 = await Application.CreateDialogWithDateInYear(2021, CreatedAt);
var dialogIn2022 = await Application.CreateDialogWithDateInYear(2022, CreatedAt);
var dialogIn2023 = await Application.CreateDialogWithDateInYear(2023, CreatedAt);

// Act
var response = await Application.Send(new SearchDialogQuery
{
Party = [Party],
CreatedAfter = createdAfterYear.HasValue ? CreateDateFromYear(createdAfterYear.Value) : null,
CreatedBefore = createdBeforeYear.HasValue ? CreateDateFromYear(createdBeforeYear.Value) : null
});

// Assert
response.TryPickT0(out var result, out _).Should().BeTrue();
result.Should().NotBeNull();

result.Items.Should().HaveCount(expectedCount);
foreach (var year in expectedYears)
{
var dialogId = year switch
{
2020 => dialogIn2020,
2021 => dialogIn2021,
2022 => dialogIn2022,
2023 => dialogIn2023,
_ => throw new ArgumentOutOfRangeException()
};

result.Items.Should().ContainSingle(x => x.Id == dialogId);
}
}

[Fact]
public async Task Cannot_Filter_On_Created_After_With_Value_Greater_Than_Created_Before()
{
// Act
var response = await Application.Send(new SearchDialogQuery
{
Party = [Party],
CreatedAfter = CreateDateFromYear(2022),
CreatedBefore = CreateDateFromYear(2021)
});

// Assert
response.TryPickT1(out var result, out _).Should().BeTrue();
result.Should().NotBeNull();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search;
using Digdir.Domain.Dialogporten.Application.Integration.Tests.Common;
using FluentAssertions;
using static Digdir.Domain.Dialogporten.Application.Integration.Tests.Common.Common;

namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.EndUser.Dialogs.Queries.Search;

[Collection(nameof(DialogCqrsCollectionFixture))]
public class DueAtFilterTests : ApplicationCollectionFixture
{
public DueAtFilterTests(DialogApplication application) : base(application) { }

[Theory, MemberData(nameof(DueAtTestData))]
public async Task Should_Filter_On_Due_Date(DateFilterTestData testData)
{
// Arrange
var currentYear = DateTimeOffset.UtcNow.Year;

var oneYearInTheFuture = currentYear + 1;
var twoYearsInTheFuture = currentYear + 2;
var threeYearsInTheFuture = currentYear + 3;
var fourYearsInTheFuture = currentYear + 4;

var dialogOneYearInTheFuture = await Application.CreateDialogWithDateInYear(oneYearInTheFuture, DueAt);
var dialogTwoYearsInTheFuture = await Application.CreateDialogWithDateInYear(twoYearsInTheFuture, DueAt);
var dialogThreeYearsInTheFuture = await Application.CreateDialogWithDateInYear(threeYearsInTheFuture, DueAt);
var dialogFourYearsInTheFuture = await Application.CreateDialogWithDateInYear(fourYearsInTheFuture, DueAt);

// Act
var response = await Application.Send(new SearchDialogQuery
{
Party = [Party],
DueAfter = testData.AfterYear.HasValue ? CreateDateFromYear(testData.AfterYear.Value) : null,
DueBefore = testData.BeforeYear.HasValue ? CreateDateFromYear(testData.BeforeYear.Value) : null
});

// Assert
response.TryPickT0(out var result, out _).Should().BeTrue();
result.Should().NotBeNull();

result.Items.Should().HaveCount(testData.ExpectedCount);
foreach (var year in testData.ExpectedYears)
{
var dialogId = year switch
{
_ when year == oneYearInTheFuture => dialogOneYearInTheFuture,
_ when year == twoYearsInTheFuture => dialogTwoYearsInTheFuture,
_ when year == threeYearsInTheFuture => dialogThreeYearsInTheFuture,
_ when year == fourYearsInTheFuture => dialogFourYearsInTheFuture,
_ => throw new ArgumentOutOfRangeException()
};

result.Items.Should().ContainSingle(x => x.Id == dialogId);
}
}

[Fact]
public async Task Cannot_Filter_On_DueAfter_With_Value_Greater_Than_DueBefore()
{
// Act
var response = await Application.Send(new SearchDialogQuery
{
Party = [Party],
DueAfter = CreateDateFromYear(2022),
DueBefore = CreateDateFromYear(2021)
});

// Assert
response.TryPickT1(out var result, out _).Should().BeTrue();
result.Should().NotBeNull();
}

public static IEnumerable<object[]> DueAtTestData()
{
var currentYear = DateTimeOffset.UtcNow.Year;
return new List<object[]>
{
new object[]
{
new DateFilterTestData
{
AfterYear = currentYear + 3,
BeforeYear = null,
ExpectedCount = 2,
ExpectedYears = [currentYear + 3, currentYear + 4]
}
},
new object[]
{
new DateFilterTestData
{
AfterYear = null,
BeforeYear = currentYear + 2,
ExpectedCount = 2,
ExpectedYears = [currentYear + 1, currentYear + 2]
}
},
new object[]
{
new DateFilterTestData
{
AfterYear = currentYear + 1,
BeforeYear = currentYear + 2,
ExpectedCount = 2,
ExpectedYears = [currentYear + 1, currentYear + 2]
}
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Queries.Search;
using Digdir.Domain.Dialogporten.Application.Integration.Tests.Common;
using FluentAssertions;
using static Digdir.Domain.Dialogporten.Application.Integration.Tests.Common.Common;

namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.EndUser.Dialogs.Queries.Search;

[Collection(nameof(DialogCqrsCollectionFixture))]
public class UpdatedAtFilterTests : ApplicationCollectionFixture
{
public UpdatedAtFilterTests(DialogApplication application) : base(application) { }

[Theory]
[InlineData(2022, null, 2, new[] { 2022, 2023 })]
[InlineData(null, 2021, 2, new[] { 2020, 2021 })]
[InlineData(2021, 2022, 2, new[] { 2021, 2022 })]
public async Task Should_Filter_On_Updated_Date(int? updatedAfterYear, int? updatedBeforeYear, int expectedCount, int[] expectedYears)
{
// Arrange
var dialogIn2020 = await Application.CreateDialogWithDateInYear(2020, UpdatedAt);
var dialogIn2021 = await Application.CreateDialogWithDateInYear(2021, UpdatedAt);
var dialogIn2022 = await Application.CreateDialogWithDateInYear(2022, UpdatedAt);
var dialogIn2023 = await Application.CreateDialogWithDateInYear(2023, UpdatedAt);

// Act
var response = await Application.Send(new SearchDialogQuery
{
Party = [Party],
UpdatedAfter = updatedAfterYear.HasValue ? CreateDateFromYear(updatedAfterYear.Value) : null,
UpdatedBefore = updatedBeforeYear.HasValue ? CreateDateFromYear(updatedBeforeYear.Value) : null
});

// Assert
response.TryPickT0(out var result, out _).Should().BeTrue();
result.Should().NotBeNull();

result.Items.Should().HaveCount(expectedCount);
foreach (var year in expectedYears)
{
var dialogId = year switch
{
2020 => dialogIn2020,
2021 => dialogIn2021,
2022 => dialogIn2022,
2023 => dialogIn2023,
_ => throw new ArgumentOutOfRangeException()
};

result.Items.Should().ContainSingle(x => x.Id == dialogId);
}
}

[Fact]
public async Task Cannot_Filter_On_UpdatedAfter_With_Value_Greater_Than_UpdatedBefore()
{
// Act
var response = await Application.Send(new SearchDialogQuery
{
Party = [Party],
UpdatedAfter = CreateDateFromYear(2022),
UpdatedBefore = CreateDateFromYear(2021)
});

// Assert
response.TryPickT1(out var result, out _).Should().BeTrue();
result.Should().NotBeNull();
}
}

This file was deleted.

Loading

0 comments on commit 4b2fe2d

Please sign in to comment.