Skip to content

Commit eca9bb0

Browse files
committed
Sql tests improved
- Chinook based tests for variety of RDBMSs - PgSQL SqlDomTests updated
1 parent 54903a6 commit eca9bb0

11 files changed

Lines changed: 5119 additions & 965 deletions

File tree

Orm/Xtensive.Orm.Tests.Sql/Sqlite/ChinookSchemaCreator.cs renamed to Orm/Xtensive.Orm.Tests.Sql/ChinookSchemaCreator.cs

Lines changed: 152 additions & 101 deletions
Large diffs are not rendered by default.
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// Copyright (C) 2011-2021 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
// Created by: Malisa Ncube
5+
// Created: 2011.03.17
6+
7+
using System;
8+
using System.Data;
9+
using System.Diagnostics;
10+
using System.Linq;
11+
using NUnit.Framework;
12+
using Xtensive.Core;
13+
using Xtensive.Sql;
14+
using Xtensive.Sql.Compiler;
15+
using Xtensive.Sql.Model;
16+
17+
namespace Xtensive.Orm.Tests.Sql
18+
{
19+
public abstract class ChinookTestBase
20+
{
21+
protected struct DbCommandExecutionResult
22+
{
23+
public int FieldCount;
24+
public string[] FieldNames;
25+
public int RowCount;
26+
27+
public override string ToString()
28+
{
29+
if (FieldNames == null)
30+
FieldNames = new string[0];
31+
return string.Format("Fields: '{0}'; Rows: {1}", string.Join("', '", FieldNames), RowCount);
32+
}
33+
}
34+
35+
protected SqlDriver sqlDriver;
36+
protected SqlConnection sqlConnection;
37+
38+
protected virtual bool InMemory => false;
39+
40+
protected virtual bool PerformanceCheck => false;
41+
42+
protected int RunsPerGroup = 50;
43+
44+
protected string Url => TestConnectionInfoProvider.GetConnectionUrl();
45+
46+
protected Catalog Catalog { get; private set; }
47+
48+
[OneTimeSetUp]
49+
public virtual void SetUp()
50+
{
51+
CheckRequirements();
52+
sqlDriver = TestSqlDriver.Create(Url);
53+
sqlConnection = sqlDriver.CreateConnection();
54+
if (InMemory) {
55+
var catalog = new Catalog("Dummy");
56+
var schema = catalog.CreateSchema("default");
57+
58+
var creator = new ChinookSchemaCreator(sqlDriver);
59+
creator.CreateSchemaContent(schema);
60+
Catalog = catalog;
61+
return;
62+
}
63+
64+
try {
65+
sqlConnection.Open();
66+
}
67+
catch (Exception exception) {
68+
Console.WriteLine(exception);
69+
throw;
70+
}
71+
try {
72+
sqlConnection.BeginTransaction();
73+
Catalog = sqlDriver.ExtractCatalog(sqlConnection);
74+
var schema = Catalog.DefaultSchema;
75+
76+
var creator = new ChinookSchemaCreator(sqlDriver);
77+
creator.DropSchemaContent(sqlConnection, schema);
78+
creator.CreateSchemaContent(sqlConnection, schema);
79+
80+
sqlConnection.Commit();
81+
}
82+
catch {
83+
sqlConnection.Rollback();
84+
throw;
85+
}
86+
}
87+
88+
[OneTimeTearDown]
89+
public void TearDown()
90+
{
91+
try {
92+
if (sqlConnection!=null && sqlConnection.State!=ConnectionState.Closed)
93+
sqlConnection.Close();
94+
}
95+
catch (Exception ex) {
96+
Console.WriteLine(ex.Message);
97+
}
98+
}
99+
100+
protected virtual void CheckRequirements()
101+
{
102+
}
103+
104+
protected static DbCommandExecutionResult GetExecuteDataReaderResult(IDbCommand cmd)
105+
{
106+
var result = new DbCommandExecutionResult();
107+
try {
108+
cmd.Transaction = cmd.Connection.BeginTransaction();
109+
var rowCount = 0;
110+
var fieldCount = 0;
111+
var fieldNames = new string[0];
112+
using (var reader = cmd.ExecuteReader()) {
113+
while (reader.Read()) {
114+
if (rowCount == 0) {
115+
fieldCount = reader.FieldCount;
116+
fieldNames = new string[fieldCount];
117+
for (var i = 0; i < fieldCount; i++)
118+
fieldNames[i] = reader.GetName(i);
119+
}
120+
rowCount++;
121+
}
122+
}
123+
124+
result.RowCount = rowCount;
125+
result.FieldCount = fieldCount;
126+
result.FieldNames = fieldNames;
127+
}
128+
finally {
129+
cmd.Transaction.Rollback();
130+
}
131+
return result;
132+
}
133+
134+
protected static DbCommandExecutionResult GetExecuteNonQueryResult(IDbCommand cmd)
135+
{
136+
var result = new DbCommandExecutionResult();
137+
try {
138+
cmd.Transaction = cmd.Connection.BeginTransaction();
139+
result.RowCount = cmd.ExecuteNonQuery();
140+
}
141+
finally {
142+
cmd.Transaction.Rollback();
143+
}
144+
return result;
145+
}
146+
147+
protected string Compile(ISqlCompileUnit statement)
148+
{
149+
return PerformanceCheck
150+
? CompileWithPerformanceCheck(statement)
151+
: CompileRegular(statement);
152+
}
153+
154+
protected string CompileWithPerformanceCheck(ISqlCompileUnit statement)
155+
{
156+
var runs = new TimeSpan[RunsPerGroup * 5];
157+
var stopwatch = new Stopwatch();
158+
var compiledCommandText = sqlDriver.Compile(statement).GetCommandText();
159+
for (var i = 0; i < RunsPerGroup * 5; i++) {
160+
stopwatch.Start();
161+
_ = sqlDriver.Compile(statement).GetCommandText();
162+
stopwatch.Stop();
163+
164+
runs[i] = stopwatch.Elapsed;
165+
stopwatch.Reset();
166+
}
167+
168+
WriteDetailedStats(runs);
169+
return compiledCommandText;
170+
}
171+
172+
protected string CompileRegular(ISqlCompileUnit statement)
173+
{
174+
var stopwatch = new Stopwatch();
175+
stopwatch.Start();
176+
var compiledStatement = sqlDriver.Compile(statement);
177+
stopwatch.Stop();
178+
WriteDuration(stopwatch);
179+
return compiledStatement.GetCommandText();
180+
}
181+
182+
private void WriteDuration(Stopwatch stopwatch) =>
183+
Console.WriteLine($"Compilation elapsed ticks: {stopwatch.Elapsed} ({stopwatch.ElapsedTicks} ticks)");
184+
185+
private void WriteDetailedStats(TimeSpan[] values)
186+
{
187+
var runs = RunsPerGroup;
188+
var part1 = new ArraySegment<TimeSpan>(values, runs * 0, runs);
189+
var part2 = new ArraySegment<TimeSpan>(values, runs * 1, runs);
190+
var part3 = new ArraySegment<TimeSpan>(values, runs * 2, runs);
191+
var part4 = new ArraySegment<TimeSpan>(values, runs * 3, runs);
192+
var part5 = new ArraySegment<TimeSpan>(values, runs * 4, runs);
193+
194+
var orderedTicks = values.Select(ts => ts.Ticks).OrderBy(t => t).ToArray(values.Length);
195+
var min = orderedTicks[0];
196+
var max = orderedTicks[^1];
197+
var avg = orderedTicks.Average();
198+
199+
var p95barier = (int) (0.95 * values.Length);
200+
var p95Values = new ArraySegment<long>(orderedTicks, 0, p95barier);
201+
var p95Max = p95Values[^1];
202+
var p95Avg = p95Values.Average();
203+
var deltas = values.Select(d => Math.Abs(avg - d.Ticks));
204+
205+
Console.WriteLine("-------------------------------------");
206+
Console.WriteLine($"Min: {min} ticks({new TimeSpan(min)})");
207+
Console.WriteLine($"Max: {max} ticks({new TimeSpan(max)})");
208+
Console.WriteLine($"P95Max {p95Max} ticks({new TimeSpan(p95Max)})");
209+
Console.WriteLine($"Avg: {avg} ticks");
210+
Console.WriteLine($"P95Avg: {p95Avg} ticks");
211+
212+
Console.WriteLine("-------------------------------------");
213+
214+
Console.WriteLine("--------------Raw values-------------");
215+
for (var i = 0; i < part1.Count; i++) {
216+
Console.WriteLine($"{part1[i].Ticks} {part2[i].Ticks} {part3[i].Ticks} {part4[i].Ticks} {part5[i].Ticks}");
217+
}
218+
Console.WriteLine("-------------------------------------");
219+
}
220+
}
221+
}

0 commit comments

Comments
 (0)