using Knoks.Framework.DataAccess; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using Xunit; namespace Knoks.Test.Integrations.Framework { public class ProcExecutorTests : IDisposable { #region Static SQL Commantd private const string TableName = "Test_Table_Executor"; private const string GetProcName = "Test_Proc_Get_Executor"; private const string SetProcName = "Test_Proc_Set_Executor"; private static string[] SqlCommands = new[] { @"IF EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'Test_Proc_Get_Executor' AND TYPE = 'P') DROP PROCEDURE [Test_Proc_Get_Executor];", //------------------------------------------------------------------------------------- @"IF EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'Test_Proc_Set_Executor' AND TYPE = 'P') DROP PROCEDURE [Test_Proc_Set_Executor];", //------------------------------------------------------------------------------------- @"IF EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME='Test_Table_Executor' AND XTYPE = 'U') DROP TABLE [Test_Table_Executor];", //------------------------------------------------------------------------------------- @"CREATE TABLE [Test_Table_Executor] ( Id BIGINT NOT NULL IDENTITY(1,1), Col1 BIGINT NOT NULL, Col2 VARCHAR(50) NOT NULL, Col3 NVARCHAR(50) NOT NULL, Col4 DateTime2 NOT NULL );", //------------------------------------------------------------------------------------- @"CREATE PROCEDURE [Test_Proc_Get_Executor] @Id BIGINT = NULL AS SELECT * FROM [Test_Table_Executor] WHERE [Id] = ISNULL(@Id, [Id]); RETURN 0", //------------------------------------------------------------------------------------- @"CREATE PROCEDURE [Test_Proc_Set_Executor] @Col1 BIGINT, @Col2 VARCHAR(50), @Col3 NVARCHAR(50), @Col4 DateTime2, @Id BIGINT OUT AS INSERT INTO [Test_Table_Executor] VALUES (@Col1, @Col2, @Col3, @Col4); SET @Id = SCOPE_IDENTITY() RETURN 0" }; static ProcExecutorTests() { for (var i = 0; i < SqlCommands.Length; i++) { SqlCommands[i] = Regex.Replace(SqlCommands[i], "Test_Table_Executor", TableName); SqlCommands[i] = Regex.Replace(SqlCommands[i], "Test_Proc_Get_Executor", GetProcName); SqlCommands[i] = Regex.Replace(SqlCommands[i], "Test_Proc_Set_Executor", SetProcName); } } private static void SqlRunner(IEnumerable sqls) { using (var con = new SqlConnection(Config.DefaultDbConnection)) { con.Open(); foreach (var sql in sqls) { using (var cmd = new SqlCommand(string.Format(sql), con)) { cmd.ExecuteNonQuery(); } } } } private static void InitializeDatabaseEntities() { SqlRunner(SqlCommands); } private static void DestroyDatabaseEntities() { SqlRunner(SqlCommands.Take(3)); } #endregion private ProcExecutor _executor; public ProcExecutorTests() { SqlRunner(SqlCommands); _executor = new ProcExecutor(Config.DbConnections, new Logger(new LoggerFactory())); } public void Dispose() { SqlRunner(SqlCommands.Take(2)); } private class TestRecord { public long Col1 { get; set; } public string Col2 { get; set; } public string Col3 { get; set; } public DateTime Col4 { get; set; } [ProcParamIgnore] public string Col5 { get; set; } = "NotExistColumnInDb"; } class TestRecordComparer : IEqualityComparer { public static readonly TestRecordComparer Instance = new TestRecordComparer(); public bool Equals(TestRecord x, TestRecord y) { return x.Col1 == y.Col1 && x.Col2 == y.Col2 && x.Col3 == y.Col3 && x.Col4 == y.Col4; } public int GetHashCode(TestRecord obj) { return obj.GetHashCode(); } } [Fact(DisplayName = "GeneralPassingTest")] public async Task GeneralPassingTest() { var rowsExpected = new List { new TestRecord { Col1 = 1, Col2 = "Text 2-1", Col3 = "Text 3-1", Col4 = DateTime.UtcNow }, new TestRecord { Col1 = 2, Col2 = "Text 2-2", Col3 = "Text 3-2", Col4 = DateTime.UtcNow }, new TestRecord { Col1 = 3, Col2 = "Text 2-3", Col3 = "Text 3-3", Col4 = DateTime.UtcNow }, new TestRecord { Col1 = 4, Col2 = "Text 2-4", Col3 = "Text 3-4", Col4 = DateTime.UtcNow }, new TestRecord { Col1 = 5, Col2 = "Text 2-5", Col3 = "Text 3-5", Col4 = DateTime.UtcNow } }; var rowsActual = new List(); foreach (var rowExpected in rowsExpected) { var dr = await _executor.Go(SetProcName, rowExpected); rowsActual.Add((await _executor.Go(GetProcName, dr.OutputParams.First())).Тables[0][0].To()); }; Assert.Equal(rowsExpected, rowsActual, TestRecordComparer.Instance); } [Fact(DisplayName = "ParamPassingTest")] public async Task ParamsPassingTest() { var testRow = new TestRecord { Col1 = 1, Col2 = "Text 1", Col3 = "Text 1", Col4 = DateTime.UtcNow }; var rowsExpected = new List { testRow, testRow, testRow, testRow }; var d = new Dictionary { { "Col1", testRow.Col1 }, { "Col2", testRow.Col2 }, { "Col3", testRow.Col3 }, { "Col4", testRow.Col4 } }; var objects = new List { testRow, d, d.ToArray(), d.ToList() }; var rowsActual = new List(); foreach (var obj in objects) { var dr = await _executor.Go(SetProcName, obj); rowsActual.Add((await _executor.Go(GetProcName, dr.OutputParams.First())).Тables[0][0].To()); } Assert.Equal(rowsExpected, rowsActual, TestRecordComparer.Instance); } [Fact(DisplayName = "MultiParamsPassingTest")] public async Task MultiParamsPassingTest() { var rowsExpected = new TestRecord { Col1 = 1, Col2 = "Text 1", Col3 = "Text 1", Col4 = DateTime.UtcNow }; var dr = await _executor.Go(SetProcName, new { Col1 = rowsExpected.Col1, Col2 = rowsExpected.Col2 }, new { Col3 = rowsExpected.Col3, Col4 = rowsExpected.Col4 }); var rowsActual = (await _executor.Go(GetProcName, dr.OutputParams.First())).Тables[0][0].To(); Assert.Equal(rowsExpected, rowsActual, TestRecordComparer.Instance); } [ProcParamIgnore] private class IgnoreTestRecord { public long Col1 { get; set; } public string Col2 { get; set; } public string Col3 { get; set; } public DateTime Col4 { get; set; } } [Fact(DisplayName = "Ignore record class")] public async Task IgnoreRecordClass() { await Assert.ThrowsAsync(async () => { await _executor.Go(SetProcName, new IgnoreTestRecord()); }); } [Fact(DisplayName = "Ignore record KeyValuePair")] public async Task IgnoreRecordKeyValuePair() { await Assert.ThrowsAsync(async () => { await _executor.Go(SetProcName, new KeyValuePair("key", new IgnoreTestRecord())); }); } [Fact(DisplayName = "Ignore records in Dictionary")] public async Task IgnoreRecordDictionary() { await Assert.ThrowsAsync(async () => { await _executor.Go(SetProcName, new Dictionary { { "k1", new IgnoreTestRecord() }, { "k2", new IgnoreTestRecord() } }); }); } } }