From e17a9e4fac9f5dfa4f9faf328a668150b23f4bc7 Mon Sep 17 00:00:00 2001 From: agunn26 Date: Mon, 26 Oct 2026 09:40:34 -0500 Subject: [PATCH] Raise RedirectsUpdated when a redirect is deleted by id DefaultRedirectsService.DeleteById removed the row but, unlike every other write on the service, never raised RedirectsEvents.RedirectsUpdated. The admin redirects list's Delete button calls it, so CustomRedirectHandler kept serving the deleted redirect until the application restarted or another redirect was saved, and OptimizelySyncEvents never relayed the change to other instances. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 ++ .../Core/Redirects/DefaultRedirectsService.cs | 2 + .../DefaultRedirectsServiceTests.cs | 76 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 tests/Geta.NotFoundHandler.Tests/DefaultRedirectsServiceTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index e460b88..427c63d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [Unreleased] + +### Fixed + +- Deleting a redirect from the admin redirects list (`IRedirectsService.DeleteById`) now raises `RedirectsEvents.RedirectsUpdated`, like every other write on `DefaultRedirectsService`. Before, the deleted redirect kept applying until the application restarted or another redirect was saved, and `OptimizelySyncEvents` never told the other instances. + ## [6.1.0] ### Added diff --git a/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs b/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs index aa24e13..62c7536 100644 --- a/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs +++ b/src/Geta.NotFoundHandler/Core/Redirects/DefaultRedirectsService.cs @@ -159,6 +159,8 @@ public void DeleteById(Guid id) { _repository.Delete(match); } + + _redirectsEvents.RedirectsUpdated(); } public CustomRedirect Get(Guid id) diff --git a/tests/Geta.NotFoundHandler.Tests/DefaultRedirectsServiceTests.cs b/tests/Geta.NotFoundHandler.Tests/DefaultRedirectsServiceTests.cs new file mode 100644 index 0000000..573b670 --- /dev/null +++ b/tests/Geta.NotFoundHandler.Tests/DefaultRedirectsServiceTests.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FakeItEasy; +using Geta.NotFoundHandler.Core; +using Geta.NotFoundHandler.Core.Redirects; +using Geta.NotFoundHandler.Data; +using Geta.NotFoundHandler.Tests.Base; +using Xunit; + +namespace Geta.NotFoundHandler.Tests +{ + public class DefaultRedirectsServiceTests + { + private static readonly Uri DefaultOldUri = new Uri("http://example.com/old"); + + private readonly List _storedRedirects; + private readonly RedirectsEvents _redirectsEvents; + private readonly CustomRedirectHandler _redirectHandler; + private readonly RedirectsInitializer _redirectsInitializer; + private readonly DefaultRedirectsService _sut; + + public DefaultRedirectsServiceTests() + { + _storedRedirects = new List(); + var repository = A.Fake>(); + A.CallTo(() => repository.Delete(A._)) + .Invokes((CustomRedirect redirect) => _storedRedirects.Remove(redirect)); + var redirectLoader = A.Fake(); + A.CallTo(() => redirectLoader.GetAll()).ReturnsLazily(() => _storedRedirects.ToList()); + A.CallTo(() => redirectLoader.Get(A._)) + .ReturnsLazily((Guid id) => _storedRedirects.FirstOrDefault(x => x.Id == id)); + + _redirectsEvents = new RedirectsEvents(); + _sut = new DefaultRedirectsService(repository, redirectLoader, _redirectsEvents); + + _redirectHandler = new CustomRedirectHandler(); + _redirectsInitializer = new RedirectsInitializer( + _redirectsEvents, + _redirectHandler, + () => _sut, + Enumerable.Empty()); + } + + [Fact] + public void DeleteById_raises_redirects_updated() + { + var redirect = GivenStoredRedirect(DefaultOldUri.PathAndQuery); + var raised = false; + _redirectsEvents.OnRedirectsUpdated += _ => raised = true; + + _sut.DeleteById(redirect.Id.Value); + + Assert.True(raised); + } + + [Fact] + public void DeleteById_removes_redirect_from_redirect_handler() + { + var redirect = GivenStoredRedirect(DefaultOldUri.PathAndQuery); + _redirectsInitializer.Initialize(); + Assert.NotNull(_redirectHandler.Find(DefaultOldUri.PathAndQuery.ToUri())); + + _sut.DeleteById(redirect.Id.Value); + + Assert.Null(_redirectHandler.Find(DefaultOldUri.PathAndQuery.ToUri())); + } + + private CustomRedirect GivenStoredRedirect(string oldUrl) + { + var redirect = new CustomRedirect(oldUrl, "/new") { Id = Guid.NewGuid() }; + _storedRedirects.Add(redirect); + return redirect; + } + } +}