diff --git a/src/Api/Data/IssueRepository.cs b/src/Api/Data/IssueRepository.cs index 747c699..0ee06aa 100644 --- a/src/Api/Data/IssueRepository.cs +++ b/src/Api/Data/IssueRepository.cs @@ -106,7 +106,7 @@ public async Task ArchiveAsync(string issueId, string archivedBy, Cancella update, cancellationToken: cancellationToken); - return result.ModifiedCount > 0; + return result.MatchedCount > 0; } /// diff --git a/tests/Integration/Handlers/DeleteIssueHandlerTests.cs b/tests/Integration/Handlers/DeleteIssueHandlerTests.cs new file mode 100644 index 0000000..e462553 --- /dev/null +++ b/tests/Integration/Handlers/DeleteIssueHandlerTests.cs @@ -0,0 +1,86 @@ +using Shared.Domain; + +namespace IssueManager.Tests.Integration.Handlers; + +/// +/// Integration tests for IssueRepository.ArchiveAsync (soft-delete). +/// Verifies correct behavior when archiving existing, already-archived, and non-existent issues. +/// +public class DeleteIssueHandlerTests : IAsyncLifetime +{ + private const string MONGODB_IMAGE = "mongo:8.0"; + private const string TEST_DATABASE = "IssueManagerTestDb"; + private readonly MongoDbContainer _mongoContainer; + + private IIssueRepository _repository = null!; + + public DeleteIssueHandlerTests() + { + _mongoContainer = new MongoDbBuilder() + .WithImage(MONGODB_IMAGE) + .Build(); + } + + /// + /// Initializes the test container and repository. + /// + public async Task InitializeAsync() + { + await _mongoContainer.StartAsync(); + var connectionString = _mongoContainer.GetConnectionString(); + _repository = new IssueRepository(connectionString, TEST_DATABASE); + } + + /// + /// Disposes the test container. + /// + public async Task DisposeAsync() + { + await _mongoContainer.StopAsync(); + await _mongoContainer.DisposeAsync(); + } + + [Fact] + public async Task ArchiveAsync_ExistingUnarchivedIssue_ReturnsTrue() + { + // Arrange + var issue = Issue.Create("Test Issue", "Test Description"); + await _repository.CreateAsync(issue); + + // Act + var result = await _repository.ArchiveAsync(issue.Id, "testuser"); + + // Assert + result.Should().BeTrue(); + + var retrieved = await _repository.GetByIdAsync(issue.Id); + retrieved!.IsArchived.Should().BeTrue(); + retrieved.ArchivedBy.Should().Be("testuser"); + retrieved.ArchivedAt.Should().NotBeNull(); + } + + [Fact] + public async Task ArchiveAsync_AlreadyArchivedIssue_ReturnsTrueIdempotent() + { + // Arrange + var issue = Issue.Create("Already Archived Issue", "Description"); + await _repository.CreateAsync(issue); + await _repository.ArchiveAsync(issue.Id, "firstuser"); + + // Act - archive again (already archived, ModifiedCount will be 0) + var result = await _repository.ArchiveAsync(issue.Id, "seconduser"); + + // Assert - should return true (issue was found), not false (issue not found) + result.Should().BeTrue(); + } + + [Fact] + public async Task ArchiveAsync_NonExistentIssue_ReturnsFalse() + { + // Act + var result = await _repository.ArchiveAsync("non-existent-id", "testuser"); + + // Assert + result.Should().BeFalse(); + } +}