public async Task Update_competition_does_not_redirect_unchanged_route() { var competition = _databaseFixture.TestData.Competitions.First(); var auditable = new Competition { CompetitionId = competition.CompetitionId, CompetitionName = competition.CompetitionName, CompetitionRoute = competition.CompetitionRoute }; var routeGenerator = new Mock <IRouteGenerator>(); routeGenerator.Setup(x => x.GenerateUniqueRoute(auditable.CompetitionRoute, "/competitions", auditable.CompetitionName, NoiseWords.CompetitionRoute, It.IsAny <Func <string, Task <int> > >())).Returns(Task.FromResult(competition.CompetitionRoute)); var copier = new Mock <IStoolballEntityCopier>(); copier.Setup(x => x.CreateAuditableCopy(competition)).Returns(auditable); var redirects = new Mock <IRedirectsRepository>(); var repo = new SqlServerCompetitionRepository( _databaseFixture.ConnectionFactory, Mock.Of <IAuditRepository>(), Mock.Of <ILogger>(), Mock.Of <ISeasonRepository>(), routeGenerator.Object, redirects.Object, Mock.Of <IHtmlSanitizer>(), copier.Object, Mock.Of <IUrlFormatter>(), Mock.Of <ISocialMediaAccountFormatter>()); var updated = await repo.UpdateCompetition(competition, Guid.NewGuid(), "Person 1").ConfigureAwait(false); redirects.Verify(x => x.InsertRedirect(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <IDbTransaction>()), Times.Never); }
public async Task Update_competition_does_not_add_competition_version_if_name_is_unchanged() { var competition = _databaseFixture.TestData.Competitions.First(x => !x.UntilYear.HasValue); var auditable = new Competition { CompetitionId = competition.CompetitionId, CompetitionName = competition.CompetitionName, }; int?existingVersions = null; (Guid? competitionVersionId, string competitionName, string comparableName, DateTimeOffset? fromDate)currentVersion = (null, null, null, null); using (var connection = _databaseFixture.ConnectionFactory.CreateDatabaseConnection()) { existingVersions = await connection.ExecuteScalarAsync <int>($"SELECT COUNT(*) FROM {Tables.CompetitionVersion} WHERE CompetitionId = @CompetitionId", auditable).ConfigureAwait(false); currentVersion = await connection.QuerySingleAsync <(Guid competitionVersionId, string competitionName, string comparableName, DateTimeOffset?fromDate)>( $"SELECT CompetitionVersionId, CompetitionName, ComparableName, FromDate FROM {Tables.CompetitionVersion} WHERE CompetitionId = @CompetitionId AND UntilDate IS NULL", auditable).ConfigureAwait(false); } var routeGenerator = new Mock <IRouteGenerator>(); routeGenerator.Setup(x => x.GenerateUniqueRoute(competition.CompetitionRoute, "/competitions", auditable.CompetitionName, NoiseWords.CompetitionRoute, It.IsAny <Func <string, Task <int> > >())).Returns(Task.FromResult(competition.CompetitionRoute)); var copier = new Mock <IStoolballEntityCopier>(); copier.Setup(x => x.CreateAuditableCopy(competition)).Returns(auditable); var repo = new SqlServerCompetitionRepository( _databaseFixture.ConnectionFactory, Mock.Of <IAuditRepository>(), Mock.Of <ILogger>(), Mock.Of <ISeasonRepository>(), routeGenerator.Object, Mock.Of <IRedirectsRepository>(), Mock.Of <IHtmlSanitizer>(), copier.Object, Mock.Of <IUrlFormatter>(), Mock.Of <ISocialMediaAccountFormatter>()); var updated = await repo.UpdateCompetition(competition, Guid.NewGuid(), "Person 1").ConfigureAwait(false); using (var connection = _databaseFixture.ConnectionFactory.CreateDatabaseConnection()) { var totalVersions = await connection.ExecuteScalarAsync <int>($"SELECT COUNT(*) FROM {Tables.CompetitionVersion} WHERE CompetitionId = @CompetitionId", auditable).ConfigureAwait(false); Assert.Equal(existingVersions, totalVersions); var versionResult = await connection.QuerySingleAsync <(Guid competitionVersionId, string competitionName, string comparableName, DateTimeOffset?fromDate)>( $"SELECT CompetitionVersionId, CompetitionName, ComparableName, FromDate FROM {Tables.CompetitionVersion} WHERE CompetitionId = @CompetitionId AND UntilDate IS NULL", auditable).ConfigureAwait(false); Assert.Equal(currentVersion.competitionVersionId, versionResult.competitionVersionId); Assert.Equal(auditable.CompetitionName, versionResult.competitionName); Assert.Equal(auditable.ComparableName(), versionResult.comparableName); Assert.Equal(currentVersion.fromDate.Value, versionResult.fromDate.Value); } }
public async Task Update_competition_throws_ArgumentNullException_if_memberName_is_empty_string() { var repo = new SqlServerCompetitionRepository( _databaseFixture.ConnectionFactory, Mock.Of <IAuditRepository>(), Mock.Of <ILogger>(), Mock.Of <ISeasonRepository>(), Mock.Of <IRouteGenerator>(), Mock.Of <IRedirectsRepository>(), Mock.Of <IHtmlSanitizer>(), Mock.Of <IStoolballEntityCopier>(), Mock.Of <IUrlFormatter>(), Mock.Of <ISocialMediaAccountFormatter>()); await Assert.ThrowsAsync <ArgumentNullException>(async() => await repo.UpdateCompetition(new Competition(), Guid.NewGuid(), string.Empty).ConfigureAwait(false)).ConfigureAwait(false); }
public async Task Update_competition_audits_and_logs() { var location = _databaseFixture.TestData.Competitions.First(); var auditable = new Competition { CompetitionId = location.CompetitionId, CompetitionRoute = location.CompetitionRoute, CompetitionName = location.CompetitionName, }; var redacted = new Competition { CompetitionId = location.CompetitionId, CompetitionRoute = location.CompetitionRoute, CompetitionName = location.CompetitionName }; var routeGenerator = new Mock <IRouteGenerator>(); routeGenerator.Setup(x => x.GenerateUniqueRoute(location.CompetitionRoute, "/competitions", auditable.CompetitionName, NoiseWords.CompetitionRoute, It.IsAny <Func <string, Task <int> > >())).Returns(Task.FromResult(location.CompetitionRoute)); var copier = new Mock <IStoolballEntityCopier>(); copier.Setup(x => x.CreateAuditableCopy(location)).Returns(auditable); copier.Setup(x => x.CreateRedactedCopy(auditable)).Returns(redacted); var auditRepository = new Mock <IAuditRepository>(); var logger = new Mock <ILogger>(); var repo = new SqlServerCompetitionRepository( _databaseFixture.ConnectionFactory, auditRepository.Object, logger.Object, Mock.Of <ISeasonRepository>(), routeGenerator.Object, Mock.Of <IRedirectsRepository>(), Mock.Of <IHtmlSanitizer>(), copier.Object, Mock.Of <IUrlFormatter>(), Mock.Of <ISocialMediaAccountFormatter>()); var memberKey = Guid.NewGuid(); var memberName = "Person 1"; var updated = await repo.UpdateCompetition(location, memberKey, memberName).ConfigureAwait(false); copier.Verify(x => x.CreateRedactedCopy(auditable), Times.Once); auditRepository.Verify(x => x.CreateAudit(It.IsAny <AuditRecord>(), It.IsAny <IDbTransaction>()), Times.Once); logger.Verify(x => x.Info(typeof(SqlServerCompetitionRepository), LoggingTemplates.Updated, redacted, memberName, memberKey, typeof(SqlServerCompetitionRepository), nameof(SqlServerCompetitionRepository.UpdateCompetition))); }
public async Task Update_competition_updates_season_routes_and_inserts_redirects() { var competition = _databaseFixture.TestData.Competitions.First(x => x.Seasons.Count > 1); var auditable = new Competition { CompetitionId = competition.CompetitionId, CompetitionName = competition.CompetitionName, CompetitionRoute = competition.CompetitionRoute }; var updatedRoute = competition.CompetitionRoute + "-updated"; var routeGenerator = new Mock <IRouteGenerator>(); routeGenerator.Setup(x => x.GenerateUniqueRoute(competition.CompetitionRoute, "/competitions", auditable.CompetitionName, NoiseWords.CompetitionRoute, It.IsAny <Func <string, Task <int> > >())).Returns(Task.FromResult(updatedRoute)); var copier = new Mock <IStoolballEntityCopier>(); copier.Setup(x => x.CreateAuditableCopy(competition)).Returns(auditable); var redirects = new Mock <IRedirectsRepository>(); var repo = new SqlServerCompetitionRepository( _databaseFixture.ConnectionFactory, Mock.Of <IAuditRepository>(), Mock.Of <ILogger>(), Mock.Of <ISeasonRepository>(), routeGenerator.Object, redirects.Object, Mock.Of <IHtmlSanitizer>(), copier.Object, Mock.Of <IUrlFormatter>(), Mock.Of <ISocialMediaAccountFormatter>()); var updated = await repo.UpdateCompetition(competition, Guid.NewGuid(), "Person 1").ConfigureAwait(false); using (var connection = _databaseFixture.ConnectionFactory.CreateDatabaseConnection()) { var seasonRoutes = await connection.QueryAsync <string>($"SELECT SeasonRoute FROM {Tables.Season} WHERE CompetitionId = @CompetitionId", competition).ConfigureAwait(false); foreach (var route in seasonRoutes) { Assert.Matches("^" + updatedRoute.Replace("/", @"\/") + @"\/[0-9]{4}(-[0-9]{2,4})?$", route); redirects.Verify(x => x.InsertRedirect(competition.CompetitionRoute + route.Substring(route.LastIndexOf("/", StringComparison.OrdinalIgnoreCase)), route, null, It.IsAny <IDbTransaction>()), Times.Once); } } }
public async Task Update_competition_returns_a_copy() { var competition = new Competition { CompetitionName = "Example competition", CompetitionRoute = "/competitions/example-competition", MemberGroupKey = Guid.NewGuid(), MemberGroupName = "Test group" }; var copyCompetition = new Competition { CompetitionName = competition.CompetitionName, MemberGroupKey = competition.MemberGroupKey, MemberGroupName = competition.MemberGroupName }; var routeGenerator = new Mock <IRouteGenerator>(); routeGenerator.Setup(x => x.GenerateUniqueRoute(competition.CompetitionRoute, "/competitions", copyCompetition.CompetitionName, NoiseWords.CompetitionRoute, It.IsAny <Func <string, Task <int> > >())).Returns(Task.FromResult("/competitions/" + Guid.NewGuid())); var copier = new Mock <IStoolballEntityCopier>(); copier.Setup(x => x.CreateAuditableCopy(competition)).Returns(copyCompetition); var repo = new SqlServerCompetitionRepository( _databaseFixture.ConnectionFactory, Mock.Of <IAuditRepository>(), Mock.Of <ILogger>(), Mock.Of <ISeasonRepository>(), routeGenerator.Object, Mock.Of <IRedirectsRepository>(), Mock.Of <IHtmlSanitizer>(), copier.Object, Mock.Of <IUrlFormatter>(), Mock.Of <ISocialMediaAccountFormatter>()); var updated = await repo.UpdateCompetition(competition, Guid.NewGuid(), "Member name").ConfigureAwait(false); copier.Verify(x => x.CreateAuditableCopy(competition), Times.Once); Assert.Equal(copyCompetition, updated); }
public async Task Update_competition_succeeds() { var competition = _databaseFixture.TestData.Competitions.First(); var originalIntro = string.IsNullOrEmpty(competition.Introduction) ? "Unsanitised introduction" : competition.Introduction; var originalPrivateContact = string.IsNullOrEmpty(competition.PrivateContactDetails) ? "Unsanitised private details" : competition.PrivateContactDetails; var originalPublicContact = string.IsNullOrEmpty(competition.PublicContactDetails) ? "Unsanitised public details" : competition.PublicContactDetails; var sanitisedIntro = "<p>This is the sanitised intro</p>"; var sanitisedPrivateContact = "<p>Sanitised private details</p>"; var sanitisedPublicContact = "<p>Sanitised public details</p>"; var originalFacebook = "facebook.com/" + Guid.NewGuid().ToString(); var originalInstagram = Guid.NewGuid().ToString(); var originalYouTube = "youtube.com/example" + Guid.NewGuid().ToString(); var originalTwitter = Guid.NewGuid().ToString(); var originalWebsite = "example.org/" + Guid.NewGuid().ToString(); var auditable = new Competition { CompetitionId = competition.CompetitionId, Introduction = originalIntro, PlayerType = competition.PlayerType == PlayerType.JuniorGirls ? PlayerType.Ladies : PlayerType.JuniorGirls, CompetitionName = Guid.NewGuid().ToString(), FromYear = competition.FromYear.HasValue ? competition.FromYear + 1 : 1999, UntilYear = competition.UntilYear.HasValue ? competition.UntilYear + 1 : 2021, Facebook = originalFacebook, Instagram = originalInstagram, YouTube = originalYouTube, Twitter = originalTwitter, Website = originalWebsite, PrivateContactDetails = originalPrivateContact, PublicContactDetails = originalPublicContact, }; var updatedRoute = competition.CompetitionRoute + Guid.NewGuid(); var routeGenerator = new Mock <IRouteGenerator>(); routeGenerator.Setup(x => x.GenerateUniqueRoute(competition.CompetitionRoute, "/competitions", auditable.CompetitionName, NoiseWords.CompetitionRoute, It.IsAny <Func <string, Task <int> > >())).Returns(Task.FromResult(updatedRoute)); var copier = new Mock <IStoolballEntityCopier>(); copier.Setup(x => x.CreateAuditableCopy(competition)).Returns(auditable); var sanitizer = new Mock <IHtmlSanitizer>(); sanitizer.Setup(x => x.Sanitize(auditable.PrivateContactDetails)).Returns(sanitisedPrivateContact); sanitizer.Setup(x => x.Sanitize(auditable.PublicContactDetails)).Returns(sanitisedPublicContact); sanitizer.Setup(x => x.Sanitize(auditable.Introduction)).Returns(sanitisedIntro); var urlFormatter = new Mock <IUrlFormatter>(); urlFormatter.Setup(x => x.PrefixHttpsProtocol(auditable.Facebook)).Returns(new Uri("https://" + auditable.Facebook)); urlFormatter.Setup(x => x.PrefixHttpsProtocol(auditable.YouTube)).Returns(new Uri("https://" + auditable.YouTube)); urlFormatter.Setup(x => x.PrefixHttpsProtocol(auditable.Website)).Returns(new Uri("https://" + auditable.Website)); var socialMediaFormatter = new Mock <ISocialMediaAccountFormatter>(); socialMediaFormatter.Setup(x => x.PrefixAtSign(auditable.Instagram)).Returns("@" + auditable.Instagram); socialMediaFormatter.Setup(x => x.PrefixAtSign(auditable.Twitter)).Returns("@" + auditable.Twitter); var repo = new SqlServerCompetitionRepository( _databaseFixture.ConnectionFactory, Mock.Of <IAuditRepository>(), Mock.Of <ILogger>(), Mock.Of <ISeasonRepository>(), routeGenerator.Object, Mock.Of <IRedirectsRepository>(), sanitizer.Object, copier.Object, urlFormatter.Object, socialMediaFormatter.Object); var updated = await repo.UpdateCompetition(competition, Guid.NewGuid(), "Person 1").ConfigureAwait(false); using (var connection = _databaseFixture.ConnectionFactory.CreateDatabaseConnection()) { var competitionResult = await connection.QuerySingleOrDefaultAsync <Competition>( $@"SELECT PlayerType, Introduction, Facebook, Instagram, YouTube, Twitter, Website, PrivateContactDetails, PublicContactDetails, CompetitionRoute FROM {Tables.Competition} WHERE CompetitionId = @CompetitionId", new { updated.CompetitionId }).ConfigureAwait(false); Assert.NotNull(competitionResult); Assert.Equal(auditable.PlayerType, competitionResult.PlayerType); sanitizer.Verify(x => x.Sanitize(originalIntro)); Assert.Equal(sanitisedIntro, competitionResult.Introduction); urlFormatter.Verify(x => x.PrefixHttpsProtocol(originalFacebook), Times.Once); Assert.Equal(auditable.Facebook, competitionResult.Facebook); Assert.StartsWith("https://", auditable.Facebook); socialMediaFormatter.Verify(x => x.PrefixAtSign(originalInstagram), Times.Once); Assert.Equal(auditable.Instagram, competitionResult.Instagram); Assert.StartsWith("@", auditable.Instagram); urlFormatter.Verify(x => x.PrefixHttpsProtocol(originalYouTube), Times.Once); Assert.Equal(auditable.YouTube, competitionResult.YouTube); Assert.StartsWith("https://", auditable.YouTube); socialMediaFormatter.Verify(x => x.PrefixAtSign(originalTwitter), Times.Once); Assert.Equal(auditable.Twitter, competitionResult.Twitter); Assert.StartsWith("@", auditable.Twitter); urlFormatter.Verify(x => x.PrefixHttpsProtocol(originalWebsite), Times.Once); Assert.Equal(auditable.Website, competitionResult.Website); Assert.StartsWith("https://", auditable.Website); sanitizer.Verify(x => x.Sanitize(originalPrivateContact)); Assert.Equal(sanitisedPrivateContact, competitionResult.PrivateContactDetails); sanitizer.Verify(x => x.Sanitize(originalPublicContact)); Assert.Equal(sanitisedPublicContact, competitionResult.PublicContactDetails); Assert.Equal(updatedRoute, competitionResult.CompetitionRoute); var versionResult = await connection.QuerySingleOrDefaultAsync <(string competitionName, string comparableName)>( $"SELECT CompetitionName, ComparableName FROM {Tables.CompetitionVersion} WHERE CompetitionId = @CompetitionId", new { updated.CompetitionId }).ConfigureAwait(false); Assert.Equal(auditable.CompetitionName, versionResult.competitionName); Assert.Equal(auditable.ComparableName(), versionResult.comparableName); } }