Skip to content

Commit 7aa0298

Browse files
committed
SqlTiming should no longer inherit from CustomTiming, just make it a lightweight wrapper (perhaps we can even remove SqlTiming); change SqlFormatter to take sql text and parameter list; better test helpers; test Protobuf serialization (we use this for all serialization to/from redis on Stack Overflow)
1 parent 1b15216 commit 7aa0298

File tree

85 files changed

+36986
-1873
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+36986
-1873
lines changed

StackExchange.Profiling.Tests/BaseTest.cs

+84-58
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
namespace StackExchange.Profiling.Tests
1+
using System.Collections;
2+
using System.Data.Common;
3+
4+
namespace StackExchange.Profiling.Tests
25
{
36
using System;
47
using System.Collections.Generic;
@@ -55,14 +58,16 @@ public static IDisposable GetRequest(string url = DefaultRequestUrl, bool startA
5558
}
5659

5760
/// <summary>
58-
/// Returns a profiler for <paramref name="url"/>. Only child steps will take any time, e.g. when <paramref name="childDepth"/> is 0, the
59-
/// resulting <see cref="MiniProfiler.DurationMilliseconds"/> will be zero.
61+
/// Returns a profiler for <paramref name="url"/>. Only child steps will take any time,
62+
/// e.g. when <paramref name="childDepth"/> is 0, the resulting <see cref="MiniProfiler.DurationMilliseconds"/> will be zero.
6063
/// </summary>
61-
/// <param name="url">the url</param>
6264
/// <param name="childDepth">number of levels of child steps underneath result's <see cref="MiniProfiler.Root"/></param>
6365
/// <param name="stepsEachTakeMilliseconds">Amount of time each step will "do work for" in each step</param>
6466
/// <returns>the mini profiler</returns>
65-
public static MiniProfiler GetProfiler(string url = DefaultRequestUrl, int childDepth = 0, int stepsEachTakeMilliseconds = StepTimeMilliseconds)
67+
public static MiniProfiler GetProfiler(
68+
string url = DefaultRequestUrl,
69+
int childDepth = 0,
70+
int stepsEachTakeMilliseconds = StepTimeMilliseconds)
6671
{
6772
MiniProfiler result = null;
6873
Action step = null;
@@ -104,10 +109,6 @@ public static void IncrementStopwatch(int milliseconds = StepTimeMilliseconds)
104109
/// <summary>
105110
/// Creates a <c>SqlCe</c> file database named after <typeparamref name="T"/>, returning the connection string to the database.
106111
/// </summary>
107-
/// <typeparam name="T">the database type</typeparam>
108-
/// <param name="deleteIfExists">delete if exists.</param>
109-
/// <param name="sqlToExecute">The SQL To execute.</param>
110-
/// <returns>a string containing the SQL database</returns>
111112
public static string CreateSqlCeDatabase<T>(bool deleteIfExists = false, IEnumerable<string> sqlToExecute = null)
112113
{
113114
var filename = GetSqlCeFileNameFor<T>();
@@ -159,91 +160,116 @@ public static SqlCeConnection GetOpenSqlCeConnection<T>()
159160
return result;
160161
}
161162

163+
/// <summary>
164+
/// Returns an open connection that will have its queries profiled.
165+
/// </summary>
166+
public static DbConnection GetSqliteConnection()
167+
{
168+
DbConnection cnn = new System.Data.SQLite.SQLiteConnection("Data Source=:memory:");
169+
170+
// to get profiling times, we have to wrap whatever connection we're using in a ProfiledDbConnection
171+
// when MiniProfiler.Current is null, this connection will not record any database timings
172+
if (MiniProfiler.Current != null)
173+
{
174+
cnn = new Data.ProfiledDbConnection(cnn, MiniProfiler.Current);
175+
}
176+
177+
cnn.Open();
178+
return cnn;
179+
}
180+
162181
/// <summary>
163182
/// The assert profilers are equal.
164183
/// </summary>
165-
/// <param name="mp1">the first profiler.</param>
166-
/// <param name="mp2">The second profiler.</param>
167184
public void AssertProfilersAreEqual(MiniProfiler mp1, MiniProfiler mp2)
168185
{
169186
Assert.AreEqual(mp1, mp2);
170187
AssertPublicPropertiesAreEqual(mp1, mp2);
188+
AssertTimingsAreEqualAndRecurse(mp1.Root, mp2.Root);
189+
}
171190

172-
var timings1 = mp1.GetTimingHierarchy().ToList();
173-
var timings2 = mp2.GetTimingHierarchy().ToList();
191+
protected void AssertTimingsAreEqualAndRecurse(Timing t1, Timing t2)
192+
{
193+
Console.WriteLine();
194+
Console.WriteLine();
174195

175-
Assert.That(timings1.Count == timings2.Count);
176-
for (int i = 0; i < timings1.Count; i++)
177-
{
178-
var t1 = timings1[i];
179-
var t2 = timings2[i];
180-
Assert.AreEqual(t1, t2);
196+
Assert.NotNull(t1);
197+
Assert.NotNull(t2);
181198

182-
Console.WriteLine();
183-
AssertPublicPropertiesAreEqual(t1, t2);
199+
AssertPublicPropertiesAreEqual(t1, t2);
184200

185-
//if (!t1.HasSqlTimings && !t2.HasSqlTimings) continue;
201+
if (t1.CustomTimings != null || t2.CustomTimings != null)
202+
{
203+
Assert.NotNull(t1.CustomTimings);
204+
Assert.NotNull(t2.CustomTimings);
186205

187-
//Assert.NotNull(t1.SqlTimings);
188-
//Assert.NotNull(t2.SqlTimings);
206+
Assert.AreEqual(t1.CustomTimings.Count, t2.CustomTimings.Count);
189207

190-
//for (int j = 0; j < t1.SqlTimings.Count; j++)
191-
//{
192-
// var s1 = t1.SqlTimings[j];
193-
// var s2 = t2.SqlTimings[j];
194-
// Assert.AreEqual(s1, s2);
208+
foreach (var pair1 in t1.CustomTimings)
209+
{
210+
Console.WriteLine();
195211

196-
// Console.WriteLine();
197-
// AssertPublicPropertiesAreEqual(s1, s2);
212+
var ct1 = pair1.Value;
213+
List<CustomTiming> ct2;
214+
Assert.True(t2.CustomTimings.TryGetValue(pair1.Key, out ct2));
198215

199-
// if (s1.Parameters == null && s2.Parameters == null) continue;
216+
for (int i = 0; i < ct1.Count; i++)
217+
{
218+
AssertPublicPropertiesAreEqual(ct1[i], ct2[i]);
219+
}
220+
}
221+
}
200222

201-
// Assert.NotNull(s1.Parameters);
202-
// Assert.NotNull(s2.Parameters);
223+
if (t1.Children != null || t2.Children != null)
224+
{
225+
Assert.NotNull(t1.Children);
226+
Assert.NotNull(t2.Children);
203227

204-
// for (int k = 0; k < s1.Parameters.Count; k++)
205-
// {
206-
// var p1 = s1.Parameters[k];
207-
// var p2 = s2.Parameters[k];
208-
// Assert.AreEqual(p1, p2);
228+
Assert.AreEqual(t1.Children.Count, t2.Children.Count);
209229

210-
// Console.WriteLine();
211-
// AssertPublicPropertiesAreEqual(p1, p2);
212-
// }
213-
//}
230+
for (int i = 0; i < t1.Children.Count; i++)
231+
{
232+
AssertTimingsAreEqualAndRecurse(t1.Children[i], t2.Children[i]);
233+
}
214234
}
215235
}
216236

217237
/// <summary>
218-
/// The assert public properties are equal.
238+
/// Doesn't handle collection properties!
219239
/// </summary>
220-
/// <param name="t1">first instance.</param>
221-
/// <param name="t2">second instance.</param>
222-
/// <typeparam name="T">the property type</typeparam>
223240
protected void AssertPublicPropertiesAreEqual<T>(T t1, T t2)
224241
{
225242
Assert.NotNull(t1);
226243
Assert.NotNull(t2);
227244

228-
// check public properties
245+
// we'll handle any collections elsewhere
229246
var props = from p in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
247+
where p.IsDefined(typeof(System.Runtime.Serialization.DataMemberAttribute), false)
248+
&& !p.PropertyType.GetInterfaces().Any(i => i.Equals(typeof(IDictionary)) || i.Equals(typeof(IList)))
230249
select p;
231250

232251
foreach (var p in props)
233252
{
234-
var val1 = p.GetValue(t1, null);
235-
var val2 = p.GetValue(t2, null);
253+
try
254+
{
255+
var val1 = p.GetValue(t1, null);
256+
var val2 = p.GetValue(t2, null);
236257

237-
// datetimes are sometimes serialized with different precisions - just look care about the 10th of a second
238-
if (p.PropertyType == typeof(DateTime))
258+
// datetimes are sometimes serialized with different precisions - just look care about the 10th of a second
259+
if (p.PropertyType == typeof(DateTime))
260+
{
261+
val1 = TrimToDecisecond((DateTime)val1);
262+
val2 = TrimToDecisecond((DateTime)val2);
263+
}
264+
265+
var name = typeof(T).Name + "." + p.Name;
266+
Assert.AreEqual(val1, val2, name + " have different values");
267+
Console.WriteLine("{0, 50}: {1} == {2}", name, val1 ?? "<null>", val2 ?? "<null>");
268+
}
269+
catch (Exception ex)
239270
{
240-
val1 = TrimToDecisecond((DateTime)val1);
241-
val2 = TrimToDecisecond((DateTime)val2);
271+
Assert.Fail("AssertPublicPropertiesAreEqual had an exception on " + p.Name + "; " + ex);
242272
}
243-
244-
var name = typeof(T).Name + "." + p.Name;
245-
Assert.AreEqual(val1, val2, name + " have different values");
246-
Console.WriteLine("{0, 50}: {1} == {2}", name, val1 ?? "<null>", val2 ?? "<null>");
247273
}
248274
}
249275

StackExchange.Profiling.Tests/MiniProfilerTest.cs

+4-13
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,33 @@
22

33
namespace StackExchange.Profiling.Tests
44
{
5-
/// <summary>
6-
/// The mini profiler test.
7-
/// </summary>
85
[TestFixture]
96
public class MiniProfilerTest : BaseTest
107
{
11-
/// <summary>
12-
/// simple test.
13-
/// </summary>
148
[Test]
159
public void Simple()
1610
{
17-
using (BaseTest.GetRequest("http://localhost/Test.aspx", startAndStopProfiler: false))
11+
using (GetRequest("http://localhost/Test.aspx", startAndStopProfiler: false))
1812
{
1913
MiniProfiler.Start();
20-
BaseTest.IncrementStopwatch(); // 1 ms
14+
IncrementStopwatch(); // 1 ms
2115
MiniProfiler.Stop();
2216

2317
var c = MiniProfiler.Current;
2418

2519
Assert.That(c, Is.Not.Null);
26-
Assert.That(c.DurationMilliseconds, Is.EqualTo(BaseTest.StepTimeMilliseconds));
20+
Assert.That(c.DurationMilliseconds, Is.EqualTo(StepTimeMilliseconds));
2721
Assert.That(c.Name, Is.EqualTo("/Test.aspx"));
2822

2923
Assert.That(c.Root, Is.Not.Null);
3024
Assert.That(c.Root.HasChildren, Is.False);
3125
}
3226
}
3327

34-
/// <summary>
35-
/// discard the results.
36-
/// </summary>
3728
[Test]
3829
public void DiscardResults()
3930
{
40-
using (BaseTest.GetRequest(startAndStopProfiler: false))
31+
using (GetRequest(startAndStopProfiler: false))
4132
{
4233
MiniProfiler.Start();
4334
MiniProfiler.Stop(discardResults: true);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using NUnit.Framework;
2+
using System.IO;
3+
using StackExchange.Profiling.Helpers.Dapper;
4+
using StackExchange.Profiling.SqlFormatters;
5+
6+
namespace StackExchange.Profiling.Tests
7+
{
8+
[TestFixture]
9+
public class ProtobufSerializationTest : BaseTest
10+
{
11+
[Test]
12+
public void Simple()
13+
{
14+
using (GetRequest("http://localhost/Test.aspx", startAndStopProfiler: false))
15+
{
16+
MiniProfiler.Start();
17+
IncrementStopwatch(); // 1 ms
18+
MiniProfiler.Stop();
19+
20+
var mp1 = MiniProfiler.Current;
21+
var ms = new MemoryStream();
22+
ProtoBuf.Serializer.Serialize(ms, mp1);
23+
24+
ms.Position = 0;
25+
var mp2 = ProtoBuf.Serializer.Deserialize<MiniProfiler>(ms);
26+
AssertProfilersAreEqual(mp1, mp2);
27+
}
28+
}
29+
30+
31+
[Test]
32+
public void CustomTimings()
33+
{
34+
using (GetRequest("http://localhost/Test.aspx", startAndStopProfiler: false))
35+
{
36+
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
37+
MiniProfiler.Start();
38+
var mp1 = MiniProfiler.Current;
39+
40+
IncrementStopwatch(); // 1 ms
41+
42+
using (mp1.Step("Child one"))
43+
{
44+
IncrementStopwatch();
45+
46+
using (mp1.CustomTiming("http", "GET http://google.com"))
47+
{
48+
IncrementStopwatch();
49+
}
50+
51+
using (var conn = GetSqliteConnection())
52+
{
53+
conn.Query<long>("select 1");
54+
conn.Query<long>("select @one", new { one = (byte)1 });
55+
}
56+
}
57+
58+
MiniProfiler.Stop();
59+
60+
var ms = new MemoryStream();
61+
ProtoBuf.Serializer.Serialize(ms, mp1);
62+
63+
ms.Position = 0;
64+
var mp2 = ProtoBuf.Serializer.Deserialize<MiniProfiler>(ms);
65+
AssertProfilersAreEqual(mp1, mp2);
66+
}
67+
}
68+
}
69+
}

StackExchange.Profiling.Tests/SqlTimingParameterTest.cs

-23
This file was deleted.

0 commit comments

Comments
 (0)