Commit 32e7452d authored by yangxiaodong's avatar yangxiaodong

Add database connection unit test using ef

parent 0ae97693
[![Build status](https://ci.appveyor.com/api/projects/status/4mpe0tbu7n126vyw?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap)
[![Build status](https://ci.appveyor.com/api/projects/status/4mpe0tbu7n126vyw/branch/master?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap/branch/master)
# cap
A .net core middleware of eventually consistent in distributed architectures, now developing...
......
......@@ -3,44 +3,49 @@ using System.Data.SqlClient;
namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
public static class ConnectionUtil
{
private const string DatabaseVariable = "Cap_SqlServer_DatabaseName";
private const string ConnectionStringTemplateVariable = "Cap_SqlServer_ConnectionStringTemplate";
private const string MasterDatabaseName = "master";
private const string DefaultDatabaseName = @"DotNetCore.CAP.EntityFrameworkCore.Test";
private const string DefaultConnectionStringTemplate = @"Server=.\sqlexpress;Database={0};Trusted_Connection=True;";
public static string GetDatabaseName()
{
return Environment.GetEnvironmentVariable(DatabaseVariable) ?? DefaultDatabaseName;
}
public static string GetMasterConnectionString()
{
return string.Format(GetConnectionStringTemplate(), MasterDatabaseName);
}
public static string GetConnectionString()
{
return string.Format(GetConnectionStringTemplate(), GetDatabaseName());
}
private static string GetConnectionStringTemplate()
{
return
Environment.GetEnvironmentVariable(ConnectionStringTemplateVariable) ??
DefaultConnectionStringTemplate;
}
public static SqlConnection CreateConnection(string connectionString = null)
{
connectionString = connectionString ?? GetConnectionString();
var connection = new SqlConnection(connectionString);
connection.Open();
return connection;
}
}
public static class ConnectionUtil
{
private const string DatabaseVariable = "Cap_SqlServer_DatabaseName";
private const string ConnectionStringTemplateVariable = "Cap_SqlServer_ConnectionStringTemplate";
private const string MasterDatabaseName = "master";
private const string DefaultDatabaseName = @"DotNetCore.CAP.EntityFrameworkCore.Test";
//private const string DefaultConnectionStringTemplate = @"Server=.\sqlexpress;Database={0};Trusted_Connection=True;";
private const string DefaultConnectionStringTemplate = @"Server=192.168.2.206;Initial Catalog={0};User Id=sa;Password=123123;MultipleActiveResultSets=True";
public static string GetDatabaseName()
{
return Environment.GetEnvironmentVariable(DatabaseVariable) ?? DefaultDatabaseName;
}
public static string GetMasterConnectionString()
{
return string.Format(GetConnectionStringTemplate(), MasterDatabaseName);
}
public static string GetConnectionString()
{
//if (Environment.GetEnvironmentVariable("ASPNETCore_Environment") == "Development")
//{
// return "Server=192.168.2.206;Initial Catalog=Test2;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True";
//}
return string.Format(GetConnectionStringTemplate(), GetDatabaseName());
}
private static string GetConnectionStringTemplate()
{
return
Environment.GetEnvironmentVariable(ConnectionStringTemplateVariable) ??
DefaultConnectionStringTemplate;
}
public static SqlConnection CreateConnection(string connectionString = null)
{
connectionString = connectionString ?? GetConnectionString();
var connection = new SqlConnection(connectionString);
connection.Open();
return connection;
}
}
}
using System.Data;
using System.Threading.Tasks;
using Dapper;
using Microsoft.EntityFrameworkCore;
......@@ -26,10 +27,10 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
using (CreateScope())
{
var context = GetService<CapDbContext>();
var context = GetService<TestDbContext>();
context.Database.EnsureDeleted();
context.Database.Migrate();
_sqlObjectInstalled = true;
_sqlObjectInstalled = true;
}
}
}
......@@ -38,7 +39,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
using (CreateScope())
{
var context = GetService<CapDbContext>();
var context = GetService<TestDbContext>();
var commands = new[]
{
......
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
public static class DbUtil
{
public static IServiceCollection ConfigureDbServices(string connectionString, IServiceCollection services = null) {
return ConfigureDbServices<CapDbContext>(connectionString, services);
}
public static IServiceCollection ConfigureDbServices<TContext>(string connectionString, IServiceCollection services = null) where TContext : DbContext {
if (services == null) {
services = new ServiceCollection();
}
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddDbContext<TContext>(options => options.UseSqlServer(connectionString));
return services;
}
public static TContext Create<TContext>(string connectionString) where TContext : DbContext {
var serviceProvider = ConfigureDbServices<TContext>(connectionString).BuildServiceProvider();
return serviceProvider.GetRequiredService<TContext>();
}
}
}
\ No newline at end of file
using System.Threading.Tasks;
using DotNetCore.CAP.Infrastructure;
using Microsoft.AspNetCore.Builder.Internal;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
public class DefaultPocoTest : IClassFixture<ScratchDatabaseFixture>
{
private readonly ApplicationBuilder _builder;
public DefaultPocoTest(ScratchDatabaseFixture fixture)
{
var services = new ServiceCollection();
services
.AddDbContext<CapDbContext>(o => o.UseSqlServer(fixture.ConnectionString))
.AddConsistency()
.AddEntityFrameworkStores<CapDbContext>();
services.AddLogging();
var provider = services.BuildServiceProvider();
_builder = new ApplicationBuilder(provider);
using (var scoped = provider.GetRequiredService<IServiceScopeFactory>().CreateScope())
using (var db = scoped.ServiceProvider.GetRequiredService<CapDbContext>())
{
db.Database.EnsureCreated();
}
}
[Fact]
public async Task EnsureStartupUsageWorks()
{
var messageStore = _builder.ApplicationServices.GetRequiredService<ICapMessageStore>();
var messageManager = _builder.ApplicationServices.GetRequiredService<ICapMessageStore>();
Assert.NotNull(messageStore);
Assert.NotNull(messageManager);
var message = new CapSentMessage();
var operateResult = await messageManager.StoreSentMessageAsync(message);
Assert.True(operateResult.Succeeded);
operateResult = await messageManager.RemoveSentMessageAsync(message);
Assert.True(operateResult.Succeeded);
}
}
}
\ No newline at end of file
......@@ -37,10 +37,12 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" />
<PackageReference Include="System.Data.SqlClient" Version="4.3.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.1" />
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
......
using Xunit;
namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
public class EnsuranceTest : DatabaseTestHost
{
[Fact]
public void Ensure()
{
}
}
}
using System;
using System.Linq;
using System.Threading.Tasks;
using DotNetCore.CAP.Infrastructure;
using DotNetCore.CAP.Test;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
public class MessageStoreTest : MessageManagerTestBase, IClassFixture<ScratchDatabaseFixture>
public class MessageStoreTest : DatabaseTestHost
{
private readonly ScratchDatabaseFixture _fixture;
public MessageStoreTest(ScratchDatabaseFixture fixture)
{
_fixture = fixture;
}
public class ApplicationDbContext : CapDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
}
[Fact]
public void CanCreateSentMessageUsingEF()
{
using (var db = CreateContext())
{
var guid = Guid.NewGuid().ToString();
db.CapSentMessages.Add(new CapSentMessage
var message = new CapSentMessage
{
Id = guid,
Content = "this is message body",
StateName = StateName.Enqueued
});
};
db.Attach(message).State = Microsoft.EntityFrameworkCore.EntityState.Added;
db.SaveChanges();
Assert.True(db.CapSentMessages.Any(u => u.Id == guid));
Assert.NotNull(db.CapSentMessages.FirstOrDefault(u => u.StateName == StateName.Enqueued));
}
}
[Fact]
public async Task CanCreateUsingManager()
{
var manager = CreateManager();
var guid = Guid.NewGuid().ToString();
var message = new CapSentMessage
{
Id = guid,
Content = "this is message body",
StateName = StateName.Enqueued,
};
//[Fact]
//public async Task CanCreateUsingManager()
//{
// var manager = CreateManager();
// var guid = Guid.NewGuid().ToString();
// var message = new CapSentMessage
// {
// Id = guid,
// Content = "this is message body",
// StateName = StateName.Enqueued,
// };
var result = await manager.StoreSentMessageAsync(message);
Assert.NotNull(result);
Assert.True(result.Succeeded);
// var result = await manager.StoreSentMessageAsync(message);
// Assert.NotNull(result);
// Assert.True(result.Succeeded);
result = await manager.RemoveSentMessageAsync(message);
Assert.NotNull(result);
Assert.True(result.Succeeded);
}
// result = await manager.RemoveSentMessageAsync(message);
// Assert.NotNull(result);
// Assert.True(result.Succeeded);
//}
public CapDbContext CreateContext(bool delete = false)
public TestDbContext CreateContext(bool delete = false)
{
var db = DbUtil.Create<CapDbContext>(_fixture.ConnectionString);
var db = Provider.GetRequiredService<TestDbContext>();
if (delete)
{
db.Database.EnsureDeleted();
......@@ -75,31 +60,5 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Test
db.Database.EnsureCreated();
return db;
}
protected override object CreateTestContext()
{
return CreateContext();
}
protected override void AddMessageStore(IServiceCollection services, object context = null)
{
services.AddSingleton<ICapMessageStore>(new CapMessageStore<CapDbContext>((CapDbContext)context));
}
protected override CapSentMessage CreateTestSentMessage(string content = "")
{
return new CapSentMessage
{
Content = content
};
}
protected override CapReceivedMessage CreateTestReceivedMessage(string content = "")
{
return new CapReceivedMessage()
{
Content = content
};
}
}
}
}
\ No newline at end of file
......@@ -29,7 +29,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Test
var connectionString = ConnectionUtil.GetConnectionString();
//services.AddSingleton(new SqlServerOptions { ConnectionString = connectionString });
services.AddDbContext<CapDbContext>(options => options.UseSqlServer(connectionString));
services.AddDbContext<TestDbContext>(options => options.UseSqlServer(connectionString));
_services = services;
}
......
using System;
using Microsoft.EntityFrameworkCore.Internal;
namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
public class ScratchDatabaseFixture : IDisposable
{
private LazyRef<SqlServerTestStore> _testStore;
public ScratchDatabaseFixture() {
_testStore = new LazyRef<SqlServerTestStore>(() => SqlServerTestStore.CreateScratch());
}
public string ConnectionString => _testStore.Value.Connection.ConnectionString;
public void Dispose() {
if (_testStore.HasValue) {
_testStore.Value?.Dispose();
}
}
}
}
\ No newline at end of file
using System;
using System.Data.Common;
using System.Data.SqlClient;
using System.IO;
using System.Threading;
namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
public class SqlServerTestStore : IDisposable
{
public const int CommandTimeout = 90;
public static string CreateConnectionString(string name) {
var connStrBuilder = new SqlConnectionStringBuilder(TestEnvironment.Config["Test:SqlServer:DefaultConnectionString"]) {
InitialCatalog = name
};
return connStrBuilder.ConnectionString;
}
public static SqlServerTestStore CreateScratch(bool createDatabase = true)
=> new SqlServerTestStore(GetScratchDbName()).CreateTransient(createDatabase);
private SqlConnection _connection;
private readonly string _name;
private bool _deleteDatabase;
private SqlServerTestStore(string name) {
_name = name;
}
private static string GetScratchDbName() {
string name;
do {
name = "Scratch_" + Guid.NewGuid();
} while (DatabaseExists(name)
|| DatabaseFilesExist(name));
return name;
}
private static void WaitForExists(SqlConnection connection) {
var retryCount = 0;
while (true) {
try {
connection.Open();
connection.Close();
return;
}
catch (SqlException e) {
if (++retryCount >= 30
|| (e.Number != 233 && e.Number != -2 && e.Number != 4060)) {
throw;
}
SqlConnection.ClearPool(connection);
Thread.Sleep(100);
}
}
}
private SqlServerTestStore CreateTransient(bool createDatabase) {
_connection = new SqlConnection(CreateConnectionString(_name));
if (createDatabase) {
using (var master = new SqlConnection(CreateConnectionString("master"))) {
master.Open();
using (var command = master.CreateCommand()) {
command.CommandTimeout = CommandTimeout;
command.CommandText = $"{Environment.NewLine}CREATE DATABASE [{_name}]";
command.ExecuteNonQuery();
WaitForExists(_connection);
}
}
_connection.Open();
}
_deleteDatabase = true;
return this;
}
private static bool DatabaseExists(string name) {
using (var master = new SqlConnection(CreateConnectionString("master"))) {
master.Open();
using (var command = master.CreateCommand()) {
command.CommandTimeout = CommandTimeout;
command.CommandText = $@"SELECT COUNT(*) FROM sys.databases WHERE name = N'{name}'";
return (int)command.ExecuteScalar() > 0;
}
}
}
private static bool DatabaseFilesExist(string name) {
var userFolder = Environment.GetEnvironmentVariable("USERPROFILE") ??
Environment.GetEnvironmentVariable("HOME");
return userFolder != null
&& (File.Exists(Path.Combine(userFolder, name + ".mdf"))
|| File.Exists(Path.Combine(userFolder, name + "_log.ldf")));
}
private void DeleteDatabase(string name) {
using (var master = new SqlConnection(CreateConnectionString("master"))) {
master.Open();
using (var command = master.CreateCommand()) {
command.CommandTimeout = CommandTimeout;
// Query will take a few seconds if (and only if) there are active connections
// SET SINGLE_USER will close any open connections that would prevent the drop
command.CommandText
= string.Format(@"IF EXISTS (SELECT * FROM sys.databases WHERE name = N'{0}')
BEGIN
ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [{0}];
END", name);
command.ExecuteNonQuery();
}
}
}
public DbConnection Connection => _connection;
public void Dispose() {
_connection.Dispose();
if (_deleteDatabase) {
DeleteDatabase(_name);
}
}
}
}
\ No newline at end of file
using System.IO;
using Microsoft.Extensions.Configuration;
namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
public class TestEnvironment
{
public static IConfiguration Config { get; }
static TestEnvironment() {
var configBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config.json", optional: true)
.AddJsonFile("config.test.json", optional: true)
.AddEnvironmentVariables();
Config = configBuilder.Build();
}
}
}
\ No newline at end of file
{
"Test": {
"SqlServer": {
"DefaultConnectionString": "Server=192.168.2.206;Initial Catalog=Test;User Id=cmswuliu;Password=h7xY81agBn*Veiu3;MultipleActiveResultSets=True"
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment