Skip to content

Commit 9fe937e

Browse files
committed
More tests showed some PostgreSQL problems - now fixed
1 parent 5d597ed commit 9fe937e

File tree

11 files changed

+360
-193
lines changed

11 files changed

+360
-193
lines changed

BenchmarkPostgreSql/BenchmarkPostgreSql.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
<ItemGroup>
1717
<ProjectReference Include="..\DataLayer\DataLayer.csproj" />
18-
<ProjectReference Include="..\TestSupport\TestSupport.csproj" />
18+
<ProjectReference Include="..\Test\Test.csproj" />
1919
</ItemGroup>
2020

2121
</Project>

BenchmarkPostgreSql/Program.cs

Lines changed: 19 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,83 +3,56 @@
33
using DataLayer.BookApp.EfCode;
44
using Microsoft.EntityFrameworkCore;
55
using Npgsql;
6+
using Respawn;
67
using Test.Helpers;
78
using TestSupport.EfHelpers;
89

910
public class Program
1011
{
11-
private NpgsqlConnection _conn;
12+
private const string _connectionString = "host=localhost;Database=TestSupportBenchmark-TestSupport;Username=postgres;Password=LetMeIn";
1213
private BookContext _context;
1314

1415
[GlobalSetup]
1516
public void Setup()
1617
{
1718
NpgsqlConnection.ClearAllPools();
1819

19-
var options = this.CreatePostgreSqlUniqueDatabaseOptions<BookContext>();
20-
_context = new BookContext(options);
20+
var builder = new DbContextOptionsBuilder<BookContext>();
21+
builder.UseNpgsql(_connectionString);
22+
_context = new BookContext(builder.Options);
2123
_context.Database.EnsureCreated();
22-
23-
_conn = new NpgsqlConnection(_context.Database.GetDbConnection().ConnectionString);
24-
_conn.Open();
2524
}
2625

27-
//[IterationSetup]
28-
//public void CreateTables()
29-
//{
30-
// _context.Database.EnsureCreated();
31-
//}
32-
33-
[Benchmark]
34-
public void DropPublicSchemaWithEnsureCreated()
26+
[IterationSetup]
27+
public void CreateTables()
3528
{
36-
var dropPublicSchemaBatch = new NpgsqlBatch(_conn)
37-
{
38-
BatchCommands =
39-
{
40-
new ("DROP SCHEMA public CASCADE"),
41-
new ("CREATE SCHEMA public"),
42-
new ("GRANT ALL ON SCHEMA public TO postgres"),
43-
new ("GRANT ALL ON SCHEMA public TO public")
44-
}
45-
};
46-
dropPublicSchemaBatch.ExecuteNonQuery();
4729
_context.Database.EnsureCreated();
4830
}
4931

5032
[Benchmark]
51-
public void DropAllSchemasWithEnsureCreated()
33+
public void EnsureCleanUsingDropSchema()
5234
{
53-
var dropPublicSchemaCommand = new NpgsqlCommand
54-
{
55-
Connection = _conn,
56-
CommandText = @"
57-
DO $$
58-
DECLARE
59-
r RECORD;
60-
BEGIN
61-
FOR r IN (SELECT nspname FROM pg_namespace WHERE nspname NOT IN ('pg_toast', 'pg_catalog', 'information_schema'))
62-
LOOP
63-
EXECUTE 'DROP SCHEMA ' || quote_ident(r.nspname) || ' CASCADE';
64-
END LOOP;
65-
EXECUTE 'CREATE SCHEMA public';
66-
END $$"
67-
};
68-
dropPublicSchemaCommand.ExecuteNonQuery();
69-
_context.Database.EnsureCreated();
35+
_context.Database.EnsureClean();
7036
}
7137

7238
[Benchmark]
73-
public void EnsureClean()
39+
public async Task WipedByRespawnNoCheckDbExists()
7440
{
75-
_context.Database.EnsureClean();
41+
await _context.EnsureCreatedAndEmptyPostgreSqlAsync(true);
7642
}
7743

7844
[Benchmark]
79-
public async Task EnsureCreatedAndWipedByRespawn()
45+
public async Task WipedByRespawnWithCheckForDbExists()
8046
{
8147
await _context.EnsureCreatedAndEmptyPostgreSqlAsync();
8248
}
8349

50+
[Benchmark]
51+
public void EnsureDeletedEnsureCreated()
52+
{
53+
_context.Database.EnsureDeleted();
54+
_context.Database.EnsureCreated();
55+
}
56+
8457
static void Main(string[] args) => BenchmarkRunner.Run<Program>();
8558
}
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
// Copyright (c) 2020 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
2+
// Licensed under MIT license. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using DataLayer.BookApp.EfCode;
8+
using DataLayer.Database1;
9+
using DataLayer.Database2;
10+
using Microsoft.EntityFrameworkCore;
11+
using Npgsql;
12+
using Test.Helpers;
13+
using TestSupport.EfHelpers;
14+
using TestSupport.Helpers;
15+
using Xunit;
16+
using Xunit.Abstractions;
17+
using Xunit.Extensions.AssertExtensions;
18+
19+
namespace Test.UnitTests.TestDataLayer
20+
{
21+
public class TestEnsureCleanPostgreSql
22+
{
23+
private readonly ITestOutputHelper _output;
24+
25+
public TestEnsureCleanPostgreSql(ITestOutputHelper output)
26+
{
27+
_output = output;
28+
}
29+
30+
[Fact]
31+
public void TestEnsureDeletedThenCreateDatabase1Ok()
32+
{
33+
//SETUP
34+
var logToOptions = new LogToOptions
35+
{
36+
ShowLog = false
37+
};
38+
var options = this.CreatePostgreSqlUniqueClassOptionsWithLogTo<DbContext1>(log => _output.WriteLine(log), logToOptions);
39+
using (var context = new DbContext1(options))
40+
{
41+
context.Database.EnsureDeleted();
42+
43+
//ATTEMPT
44+
logToOptions.ShowLog = true;
45+
using (new TimeThings(_output, "Time to create a new database"))
46+
context.Database.EnsureClean();
47+
logToOptions.ShowLog = false;
48+
49+
//VERIFY
50+
context.Add(new TopClass1());
51+
context.SaveChanges();
52+
}
53+
}
54+
55+
[Fact]
56+
public void TestEnsureCreatedThenCreateDatabase1Ok()
57+
{
58+
//SETUP
59+
var options = this.CreatePostgreSqlUniqueClassOptions<DbContext1>();
60+
using (var context = new DbContext1(options))
61+
{
62+
context.Database.EnsureCreated();
63+
64+
//ATTEMPT
65+
using (new TimeThings(_output, "Time to update schema of a database"))
66+
context.Database.EnsureClean();
67+
68+
//VERIFY
69+
context.Add(new TopClass1());
70+
context.SaveChanges();
71+
}
72+
}
73+
74+
[Fact]
75+
public void TestEnsureDeletedThenCreateDatabase2Ok()
76+
{
77+
//SETUP
78+
var logToOptions = new LogToOptions
79+
{
80+
ShowLog = false
81+
};
82+
var options = this.CreatePostgreSqlUniqueClassOptionsWithLogTo<DbContext2>(log => _output.WriteLine(log), logToOptions);
83+
using (var context = new DbContext2(options))
84+
{
85+
context.Database.EnsureDeleted();
86+
87+
//ATTEMPT
88+
logToOptions.ShowLog = true;
89+
context.Database.EnsureClean();
90+
logToOptions.ShowLog = false;
91+
92+
//VERIFY
93+
context.Add(new TopClass2());
94+
context.SaveChanges();
95+
}
96+
}
97+
98+
[Fact]
99+
public void TestWipeDataDatabase1Ok()
100+
{
101+
//SETUP
102+
var options = this.CreatePostgreSqlUniqueMethodOptions<DbContext1>();
103+
using (var context = new DbContext1(options))
104+
{
105+
context.Database.EnsureCreated();
106+
context.Add(new TopClass1 { Dependents = new List<Dependent1> { new Dependent1() } });
107+
context.SaveChanges();
108+
context.TopClasses.Count().ShouldEqual(1);
109+
context.Dependents.Count().ShouldEqual(1);
110+
111+
//ATTEMPT
112+
using (new TimeThings(_output, "Time to clean a PostgreSQL database"))
113+
context.Database.EnsureClean();
114+
115+
//VERIFY
116+
context.TopClasses.Count().ShouldEqual(0);
117+
context.Dependents.Count().ShouldEqual(0);
118+
}
119+
}
120+
121+
[Fact]
122+
public void TestWipeDataDatabase2Ok()
123+
{
124+
//SETUP
125+
var options = this.CreatePostgreSqlUniqueMethodOptions<DbContext2>();
126+
using (var context = new DbContext2(options))
127+
{
128+
context.Database.EnsureCreated();
129+
context.Add(new TopClass2 { Dependents = new List<Dependent2> { new Dependent2() } });
130+
context.SaveChanges();
131+
context.TopClasses.Count().ShouldEqual(1);
132+
context.Dependents.Count().ShouldEqual(1);
133+
134+
//ATTEMPT
135+
context.Database.EnsureClean();
136+
137+
//VERIFY
138+
context.TopClasses.Count().ShouldEqual(0);
139+
context.Dependents.Count().ShouldEqual(0);
140+
}
141+
}
142+
143+
[Fact]
144+
public void TestDatabase1SchemaChangeToDatabase2Ok()
145+
{
146+
//SETUP
147+
var connectionString = this.GetUniquePostgreSqlConnectionString();
148+
var builder1 = new DbContextOptionsBuilder<DbContext1>();
149+
using (var context = new DbContext1(builder1.UseNpgsql(connectionString).Options))
150+
using (new TimeThings(_output, "EnsureDeleted/EnsureCreated"))
151+
{
152+
context.Database.EnsureDeleted();
153+
context.Database.EnsureCreated();
154+
}
155+
var builder2 = new DbContextOptionsBuilder<DbContext2>();
156+
using (var context = new DbContext2(builder2.UseNpgsql(connectionString).Options))
157+
{
158+
//ATTEMPT
159+
using (new TimeThings(_output, "EnsureClean"))
160+
{
161+
context.Database.EnsureClean();
162+
}
163+
164+
//VERIFY
165+
context.Add(new TopClass2());
166+
context.SaveChanges();
167+
}
168+
}
169+
170+
[Fact]
171+
public void TestEnsureCleanNotSetSchema()
172+
{
173+
//SETUP
174+
var connectionString = this.GetUniquePostgreSqlConnectionString();
175+
var builder = new DbContextOptionsBuilder<DbContext1>();
176+
using (var context = new DbContext1(builder.UseNpgsql(connectionString).Options))
177+
{
178+
context.Database.EnsureCreated();
179+
CountTablesInDatabase(context).ShouldNotEqual(0);
180+
181+
//ATTEMPT-VERIFY1
182+
context.Database.EnsureClean(false);
183+
CountTablesInDatabase(context).ShouldEqual(-1);
184+
185+
//ATTEMPT-VERIFY2
186+
context.Database.EnsureCreated();
187+
CountTablesInDatabase(context).ShouldNotEqual(0);
188+
}
189+
}
190+
191+
//This proves that PostgreSQL EnsureClean does delete the default named migration history table
192+
[Fact]
193+
public void TestEnsureCleanApplyMigrationOk()
194+
{
195+
//SETUP
196+
var options = this.CreatePostgreSqlUniqueClassOptions<BookContext>();
197+
using var context = new BookContext(options);
198+
199+
//ATTEMPT
200+
context.Database.EnsureClean(false);
201+
context.Database.Migrate();
202+
203+
//VERIFY
204+
context.Books.Count().ShouldEqual(0);
205+
}
206+
207+
[Fact]
208+
public async Task TestRespawnOk()
209+
{
210+
//SETUP
211+
var options = this.CreatePostgreSqlUniqueMethodOptions<BookContext>();
212+
using var context = new BookContext(options);
213+
context.Database.EnsureCreated();
214+
215+
//ATTEMPT
216+
using(new TimeThings(_output))
217+
await context.EnsureCreatedAndEmptyPostgreSqlAsync();
218+
219+
//VERIFY
220+
context.Books.Count().ShouldEqual(0);
221+
}
222+
223+
224+
private int CountTablesInDatabase(DbContext context)
225+
{
226+
return context.Database.ExecuteSqlRaw(
227+
$"select count(*) from information_schema.tables;");
228+
}
229+
}
230+
}

Test/UnitTests/TestDataLayer/TestEnsureClean.cs renamed to Test/UnitTests/TestDataLayer/TestEnsureCleanSqlServer.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33

44
using System.Collections.Generic;
55
using System.Linq;
6+
using DataLayer.BookApp.EfCode;
67
using DataLayer.Database1;
78
using DataLayer.Database2;
89
using Microsoft.EntityFrameworkCore;
10+
using TestSupport.Attributes;
911
using TestSupport.EfHelpers;
1012
using TestSupport.Helpers;
1113
using Xunit;
@@ -14,11 +16,11 @@
1416

1517
namespace Test.UnitTests.TestDataLayer
1618
{
17-
public class TestEnsureClean
19+
public class TestEnsureCleanSqlServer
1820
{
1921
private readonly ITestOutputHelper _output;
2022

21-
public TestEnsureClean(ITestOutputHelper output)
23+
public TestEnsureCleanSqlServer(ITestOutputHelper output)
2224
{
2325
_output = output;
2426
}
@@ -165,6 +167,28 @@ public void TestEnsureCleanNotSetSchema()
165167
}
166168
}
167169

170+
//This proves that SQL Server EnsureClean doesn't delete the default named migration history table
171+
//but it does delete migration history tables
172+
//To check that it doesn't delete the default named migration history table remove the
173+
//MigrationsHistoryTable settings. If you run it twice it will NOT update the database schema because its already applied
174+
[RunnableInDebugOnly]
175+
public void TestEnsureCleanApplyMigrationOk()
176+
{
177+
//SETUP
178+
var connectionString = this.GetUniqueDatabaseConnectionString();
179+
var optionsBuilder = new DbContextOptionsBuilder<BookContext>();
180+
optionsBuilder.UseNpgsql(connectionString, dbOptions =>
181+
dbOptions.MigrationsHistoryTable("BookMigrationHistoryName"));
182+
using var context = new BookContext(optionsBuilder.Options);
183+
184+
//ATTEMPT
185+
context.Database.EnsureClean(false);
186+
context.Database.Migrate();
187+
188+
//VERIFY
189+
context.Books.Count().ShouldEqual(0);
190+
}
191+
168192
private int CountTablesInDatabase(DbContext context)
169193
{
170194
var databaseName = context.Database.GetDbConnection().Database;

0 commit comments

Comments
 (0)