From 24ec586b3d90a1fa1527d04c1acfe759fdd0dfbe Mon Sep 17 00:00:00 2001 From: Adrian Hall Date: Mon, 20 Jan 2025 13:14:33 -0800 Subject: [PATCH 1/3] (#206) PgSQL Controller tests. --- .../Base => Helpers}/LiveControllerTests.cs | 54 +++++++++++++------ ..._Tests.cs => AzureSQL_Controller_Tests.cs} | 6 +-- .../Live/PgSQL_Controller_Tests.cs | 51 ++++++++++++++++++ 3 files changed, 92 insertions(+), 19 deletions(-) rename tests/CommunityToolkit.Datasync.Server.Test/{Live/Base => Helpers}/LiveControllerTests.cs (98%) rename tests/CommunityToolkit.Datasync.Server.Test/Live/{AzureSQL/Controller_Query_Tests.cs => AzureSQL_Controller_Tests.cs} (88%) create mode 100644 tests/CommunityToolkit.Datasync.Server.Test/Live/PgSQL_Controller_Tests.cs diff --git a/tests/CommunityToolkit.Datasync.Server.Test/Live/Base/LiveControllerTests.cs b/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs similarity index 98% rename from tests/CommunityToolkit.Datasync.Server.Test/Live/Base/LiveControllerTests.cs rename to tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs index ae5adf0..c814538 100644 --- a/tests/CommunityToolkit.Datasync.Server.Test/Live/Base/LiveControllerTests.cs +++ b/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs @@ -2,11 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.Net; -namespace CommunityToolkit.Datasync.Server.Test.Live; +namespace CommunityToolkit.Datasync.Server.Test.Helpers; /// /// The base set of tests for the controller tests going against a live server. @@ -82,6 +81,21 @@ protected virtual async Task CreateControllerAsync(HttpMethod method = null, str this.tableController.ControllerContext.HttpContext = CreateHttpContext(method ?? HttpMethod.Get, uri); } + private async Task> GetListOfEntitiesAsync(IEnumerable ids) + { + List entities = []; + foreach (string id in ids) + { + TEntity entity = await GetEntityAsync(id); + if (entity != null) + { + entities.Add(entity); + } + } + + return entities; + } + /// /// This is the base test for the individual query tests. /// @@ -104,7 +118,14 @@ private async Task MovieQueryTest(string pathAndQuery, int itemCount, string nex List items = result.Items.Cast().ToList(); items.Should().HaveCount(itemCount); result.Count.Should().Be(totalCount); - items.Select(m => m.Id).Take(firstItems.Length).Should().BeEquivalentTo(firstItems); + List actualItems = items.Select(m => m.Id).Take(firstItems.Length).ToList(); + + // Get the list of items in firstItems and actualItems + List expA1 = await GetListOfEntitiesAsync(firstItems); + List expA2 = await GetListOfEntitiesAsync(actualItems); + expA2.Count.Should().Be(actualItems.Count); + + actualItems.Should().BeEquivalentTo(firstItems); if (nextLinkQuery is not null) { @@ -113,7 +134,7 @@ private async Task MovieQueryTest(string pathAndQuery, int itemCount, string nex } else { - result.NextLink.Should().BeNull(); + result.NextLink.Should().BeNull(); } } @@ -3359,19 +3380,20 @@ await MovieQueryTest( ); } - [SkippableFact] - public async Task Query_Test_235() - { - Skip.IfNot(CanRunLiveTests()); + // PROBLEM - THIS TEST RESULTS IN DIFFERENT ORDERING ON PGSQL vs. AZURESQL + //[SkippableFact] + //public async Task Query_Test_235() + //{ + // Skip.IfNot(CanRunLiveTests()); - await MovieQueryTest( - $"{MovieEndpoint}?$orderby=title asc&$skip=5", - DefaultPageSize, - "$orderby=title asc&$skip=105", - null, - ["id-214", "id-102", "id-215", "id-039", "id-057"] - ); - } + // await MovieQueryTest( + // $"{MovieEndpoint}?$orderby=title asc&$skip=5", + // DefaultPageSize, + // "$orderby=title asc&$skip=105", + // null, + // ["id-214", "id-102", "id-215", "id-039", "id-057"] + // ); + //} [SkippableFact] public async Task Query_Test_236() diff --git a/tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL/Controller_Query_Tests.cs b/tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL_Controller_Tests.cs similarity index 88% rename from tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL/Controller_Query_Tests.cs rename to tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL_Controller_Tests.cs index aa71603..ae4825b 100644 --- a/tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL/Controller_Query_Tests.cs +++ b/tests/CommunityToolkit.Datasync.Server.Test/Live/AzureSQL_Controller_Tests.cs @@ -8,11 +8,11 @@ using Microsoft.EntityFrameworkCore; using Xunit.Abstractions; -namespace CommunityToolkit.Datasync.Server.Test.Live.AzureSQL; +namespace CommunityToolkit.Datasync.Server.Test.Live; [ExcludeFromCodeCoverage] [Collection("LiveTestsCollection")] -public class AzureSql_Controller_Query_Tests : LiveControllerTests +public class AzureSQL_Controller_Tests : LiveControllerTests { #region Setup private readonly DatabaseFixture _fixture; @@ -21,7 +21,7 @@ public class AzureSql_Controller_Query_Tests : LiveControllerTests movies; private readonly Lazy _context; - public AzureSql_Controller_Query_Tests(DatabaseFixture fixture, ITestOutputHelper output) : base() + public AzureSQL_Controller_Tests(DatabaseFixture fixture, ITestOutputHelper output) : base() { this._fixture = fixture; this.connectionString = Environment.GetEnvironmentVariable("DATASYNC_AZSQL_CONNECTIONSTRING"); diff --git a/tests/CommunityToolkit.Datasync.Server.Test/Live/PgSQL_Controller_Tests.cs b/tests/CommunityToolkit.Datasync.Server.Test/Live/PgSQL_Controller_Tests.cs new file mode 100644 index 0000000..6a5a39d --- /dev/null +++ b/tests/CommunityToolkit.Datasync.Server.Test/Live/PgSQL_Controller_Tests.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using CommunityToolkit.Datasync.Server.EntityFrameworkCore; +using CommunityToolkit.Datasync.Server.Test.Helpers; +using CommunityToolkit.Datasync.TestCommon.Databases; +using Microsoft.EntityFrameworkCore; +using Xunit.Abstractions; + +namespace CommunityToolkit.Datasync.Server.Test.Live; + +[ExcludeFromCodeCoverage] +[Collection("LiveTestsCollection")] +public class PgSQL_Controller_Tests : LiveControllerTests +{ + #region Setup + private readonly DatabaseFixture _fixture; + private readonly Random random = new(); + private readonly string connectionString; + private readonly List movies; + private readonly Lazy _context; + + public PgSQL_Controller_Tests(DatabaseFixture fixture, ITestOutputHelper output) : base() + { + this._fixture = fixture; + this.connectionString = Environment.GetEnvironmentVariable("DATASYNC_PGSQL_CONNECTIONSTRING"); + if (!string.IsNullOrEmpty(this.connectionString)) + { + this._context = new Lazy(() => PgDbContext.CreateContext(this.connectionString, output)); + this.movies = Context.Movies.AsNoTracking().ToList(); + } + } + + private PgDbContext Context { get => this._context.Value; } + + protected override bool CanRunLiveTests() => !string.IsNullOrEmpty(this.connectionString); + + protected override Task GetEntityAsync(string id) + => Task.FromResult(Context.Movies.AsNoTracking().SingleOrDefault(m => m.Id == id)); + + protected override Task GetEntityCountAsync() + => Task.FromResult(Context.Movies.Count()); + + protected override Task> GetPopulatedRepositoryAsync() + => Task.FromResult>(new EntityTableRepository(Context)); + + protected override Task GetRandomEntityIdAsync(bool exists) + => Task.FromResult(exists ? this.movies[this.random.Next(this.movies.Count)].Id : Guid.NewGuid().ToString()); + #endregion +} From 95f2926df1eed85881f38b69ffda5e9b85c1c027 Mon Sep 17 00:00:00 2001 From: Adrian Hall Date: Mon, 20 Jan 2025 13:39:00 -0800 Subject: [PATCH 2/3] (#206) Ensures stable ordering across database types. --- .../Helpers/LiveControllerTests.cs | 32 ++++++++----------- .../Databases/Postgresql/PgDbContext.cs | 9 ++++-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs b/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs index c814538..5eedeba 100644 --- a/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs +++ b/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs @@ -119,12 +119,6 @@ private async Task MovieQueryTest(string pathAndQuery, int itemCount, string nex items.Should().HaveCount(itemCount); result.Count.Should().Be(totalCount); List actualItems = items.Select(m => m.Id).Take(firstItems.Length).ToList(); - - // Get the list of items in firstItems and actualItems - List expA1 = await GetListOfEntitiesAsync(firstItems); - List expA2 = await GetListOfEntitiesAsync(actualItems); - expA2.Count.Should().Be(actualItems.Count); - actualItems.Should().BeEquivalentTo(firstItems); if (nextLinkQuery is not null) @@ -3381,19 +3375,19 @@ await MovieQueryTest( } // PROBLEM - THIS TEST RESULTS IN DIFFERENT ORDERING ON PGSQL vs. AZURESQL - //[SkippableFact] - //public async Task Query_Test_235() - //{ - // Skip.IfNot(CanRunLiveTests()); - - // await MovieQueryTest( - // $"{MovieEndpoint}?$orderby=title asc&$skip=5", - // DefaultPageSize, - // "$orderby=title asc&$skip=105", - // null, - // ["id-214", "id-102", "id-215", "id-039", "id-057"] - // ); - //} + [SkippableFact] + public async Task Query_Test_235() + { + Skip.IfNot(CanRunLiveTests()); + + await MovieQueryTest( + $"{MovieEndpoint}?$orderby=title asc&$skip=5", + DefaultPageSize, + "$orderby=title asc&$skip=105", + null, + ["id-214", "id-102", "id-215", "id-039", "id-057"] + ); + } [SkippableFact] public async Task Query_Test_236() diff --git a/tests/CommunityToolkit.Datasync.TestCommon/Databases/Postgresql/PgDbContext.cs b/tests/CommunityToolkit.Datasync.TestCommon/Databases/Postgresql/PgDbContext.cs index deb774d..9d56cd4 100644 --- a/tests/CommunityToolkit.Datasync.TestCommon/Databases/Postgresql/PgDbContext.cs +++ b/tests/CommunityToolkit.Datasync.TestCommon/Databases/Postgresql/PgDbContext.cs @@ -53,8 +53,13 @@ FOR EACH ROW EXECUTE PROCEDURE protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.Entity() - .Property(m => m.UpdatedAt).HasDefaultValueSql("NOW() AT TIME ZONE 'UTC'"); + modelBuilder.Entity().Property(m => m.UpdatedAt) + .HasDefaultValueSql("NOW() AT TIME ZONE 'UTC'"); + + // Ensures stable ordering across all database types. + modelBuilder.Entity().Property(m => m.Title) + .UseCollation("POSIX"); + base.OnModelCreating(modelBuilder); } } From 28cb2d90c00e3579bba3a3898de91aa05f9a4abd Mon Sep 17 00:00:00 2001 From: Adrian Hall Date: Mon, 20 Jan 2025 13:39:26 -0800 Subject: [PATCH 3/3] (#206) Removed unnecessary warning comment. --- .../Helpers/LiveControllerTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs b/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs index 5eedeba..7521534 100644 --- a/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs +++ b/tests/CommunityToolkit.Datasync.Server.Test/Helpers/LiveControllerTests.cs @@ -3374,7 +3374,6 @@ await MovieQueryTest( ); } - // PROBLEM - THIS TEST RESULTS IN DIFFERENT ORDERING ON PGSQL vs. AZURESQL [SkippableFact] public async Task Query_Test_235() {