Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
CAP
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
CAP
Commits
32e7452d
Commit
32e7452d
authored
Jun 28, 2017
by
yangxiaodong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add database connection unit test using ef
parent
0ae97693
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
81 additions
and
391 deletions
+81
-391
README.md
README.md
+3
-0
ConnectionUtil.cs
...DotNetCore.CAP.EntityFrameworkCore.Test/ConnectionUtil.cs
+45
-40
DatabaseTestHost.cs
...tNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs
+4
-3
DbUtil.cs
test/DotNetCore.CAP.EntityFrameworkCore.Test/DbUtil.cs
+0
-27
DefaultPocoTest.cs
...otNetCore.CAP.EntityFrameworkCore.Test/DefaultPocoTest.cs
+0
-53
DotNetCore.CAP.EntityFrameworkCore.Test.csproj
...kCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj
+2
-0
EnsuranceTest.cs
.../DotNetCore.CAP.EntityFrameworkCore.Test/EnsuranceTest.cs
+0
-12
MessageStoreTest.cs
...tNetCore.CAP.EntityFrameworkCore.Test/MessageStoreTest.cs
+26
-67
TestHost.cs
test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs
+1
-1
ScratchDatabaseFixture.cs
...ityFrameworkCore.Test/Utilities/ScratchDatabaseFixture.cs
+0
-22
SqlServerTestStore.cs
....EntityFrameworkCore.Test/Utilities/SqlServerTestStore.cs
+0
-139
TestEnvironment.cs
...CAP.EntityFrameworkCore.Test/Utilities/TestEnvironment.cs
+0
-20
config.json
test/DotNetCore.CAP.EntityFrameworkCore.Test/config.json
+0
-7
No files found.
README.md
View file @
32e7452d
[

](https://ci.appveyor.com/project/yuleyule66/cap)
[

](https://ci.appveyor.com/project/yuleyule66/cap/branch/master)
# cap
A .net core middleware of eventually consistent in distributed architectures, now developing...
...
...
test/DotNetCore.CAP.EntityFrameworkCore.Test/ConnectionUtil.cs
View file @
32e7452d
...
...
@@ -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
;
}
}
}
test/DotNetCore.CAP.EntityFrameworkCore.Test/DatabaseTestHost.cs
View file @
32e7452d
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
<
Cap
DbContext
>();
var
context
=
GetService
<
Test
DbContext
>();
context
.
Database
.
EnsureDeleted
();
context
.
Database
.
Migrate
();
_sqlObjectInstalled
=
true
;
_sqlObjectInstalled
=
true
;
}
}
}
...
...
@@ -38,7 +39,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Test
{
using
(
CreateScope
())
{
var
context
=
GetService
<
Cap
DbContext
>();
var
context
=
GetService
<
Test
DbContext
>();
var
commands
=
new
[]
{
...
...
test/DotNetCore.CAP.EntityFrameworkCore.Test/DbUtil.cs
deleted
100644 → 0
View file @
0ae97693
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
test/DotNetCore.CAP.EntityFrameworkCore.Test/DefaultPocoTest.cs
deleted
100644 → 0
View file @
0ae97693
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
test/DotNetCore.CAP.EntityFrameworkCore.Test/DotNetCore.CAP.EntityFrameworkCore.Test.csproj
View file @
32e7452d
...
...
@@ -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>
...
...
test/DotNetCore.CAP.EntityFrameworkCore.Test/EnsuranceTest.cs
deleted
100644 → 0
View file @
0ae97693
using
Xunit
;
namespace
DotNetCore.CAP.EntityFrameworkCore.Test
{
public
class
EnsuranceTest
:
DatabaseTestHost
{
[
Fact
]
public
void
Ensure
()
{
}
}
}
test/DotNetCore.CAP.EntityFrameworkCore.Test/MessageStoreTest.cs
View file @
32e7452d
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
Cap
DbContext
CreateContext
(
bool
delete
=
false
)
public
Test
DbContext
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
test/DotNetCore.CAP.EntityFrameworkCore.Test/TestHost.cs
View file @
32e7452d
...
...
@@ -29,7 +29,7 @@ namespace DotNetCore.CAP.EntityFrameworkCore.Test
var
connectionString
=
ConnectionUtil
.
GetConnectionString
();
//services.AddSingleton(new SqlServerOptions { ConnectionString = connectionString });
services
.
AddDbContext
<
Cap
DbContext
>(
options
=>
options
.
UseSqlServer
(
connectionString
));
services
.
AddDbContext
<
Test
DbContext
>(
options
=>
options
.
UseSqlServer
(
connectionString
));
_services
=
services
;
}
...
...
test/DotNetCore.CAP.EntityFrameworkCore.Test/Utilities/ScratchDatabaseFixture.cs
deleted
100644 → 0
View file @
0ae97693
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
test/DotNetCore.CAP.EntityFrameworkCore.Test/Utilities/SqlServerTestStore.cs
deleted
100644 → 0
View file @
0ae97693
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
test/DotNetCore.CAP.EntityFrameworkCore.Test/Utilities/TestEnvironment.cs
deleted
100644 → 0
View file @
0ae97693
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/DotNetCore.CAP.EntityFrameworkCore.Test/config.json
deleted
100644 → 0
View file @
0ae97693
{
"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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment