Skip to content

Commit 13f3eec

Browse files
committed
include more integration tests
1 parent 5ae14fd commit 13f3eec

File tree

5 files changed

+232
-45
lines changed

5 files changed

+232
-45
lines changed

src/Cassandra.IntegrationTests/OpenTelemetry/OpenTelemetryTests.cs

Lines changed: 184 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
using System.Linq;
2121
using System.Threading;
2222
using System.Threading.Tasks;
23+
using Cassandra.Data.Linq;
24+
using Cassandra.IntegrationTests.Policies.Util;
25+
using Cassandra.IntegrationTests.SimulacronAPI;
2326
using Cassandra.IntegrationTests.TestBase;
27+
using Cassandra.IntegrationTests.TestClusterManagement.Simulacron;
2428
using Cassandra.Mapping;
2529
using Cassandra.OpenTelemetry;
2630
using Cassandra.Tests;
@@ -42,10 +46,13 @@ public class OpenTelemetryTests : SharedClusterTest
4246

4347
private readonly List<Activity> _exportedActivities = new List<Activity>();
4448

49+
private readonly ActivitySource InternalActivitySource = new ActivitySource("testeActivitySource");
50+
4551
public OpenTelemetryTests()
4652
{
4753
Sdk.CreateTracerProviderBuilder()
4854
.AddSource(OpenTelemetrySourceName)
55+
.AddSource(InternalActivitySource.Name)
4956
.AddInMemoryExporter(_exportedActivities)
5057
.Build();
5158
}
@@ -191,16 +198,7 @@ public async Task AddOpenTelemetry_MapperAndMapperAsync_SessionRequestIsParentOf
191198

192199
session.ChangeKeyspace(keyspace);
193200

194-
string createTableQuery = @"
195-
CREATE TABLE IF NOT EXISTS song (
196-
Artist text,
197-
Title text,
198-
Id uuid,
199-
ReleaseDate timestamp,
200-
PRIMARY KEY (id)
201-
)";
202-
203-
session.Execute(createTableQuery);
201+
CreateSongTable(session);
204202

205203
var mapper = new Mapper(session);
206204

@@ -259,6 +257,174 @@ await mapper.InsertIfNotExistsAsync(songOne, testProfile, true, null)
259257
ValidateNodeActivityAttributes(syncNodeActivity);
260258
}
261259

260+
[Category(TestCategory.RealClusterLong)]
261+
[Test]
262+
[NUnit.Framework.Ignore("LINQ flow seems different than the flow in which OTEL is implemented!")]
263+
public void AddOpenTelemetry_Linq_SessionRequestIsParentOfNodeRequest()
264+
{
265+
var keyspace = TestUtils.GetUniqueKeyspaceName().ToLowerInvariant();
266+
267+
var cluster = GetNewTemporaryCluster(b => b
268+
.AddOpenTelemetryInstrumentation());
269+
270+
var session = cluster.Connect();
271+
272+
session.CreateKeyspaceIfNotExists(keyspace);
273+
274+
session.ChangeKeyspace(keyspace);
275+
276+
CreateSongTable(session);
277+
278+
var table = new Table<Song>(Session, new MappingConfiguration().Define(new Map<Song>().TableName("song")));
279+
280+
var song = new Song
281+
{
282+
Id = Guid.NewGuid(),
283+
Artist = "Led Zeppelin",
284+
Title = "Mothership",
285+
ReleaseDate = DateTimeOffset.UtcNow
286+
};
287+
288+
// Clear activities to get the Linq one
289+
_exportedActivities.Clear();
290+
291+
table.Insert(song);
292+
293+
var syncActivities = GetActivities();
294+
}
295+
296+
[Test]
297+
public void AddOpenTelemetry_WhenMethodIsInvokedAfterQuery_TraceIdIsTheSameThroughRequest()
298+
{
299+
var firstMethodName = "FirstMethod";
300+
var secondMethodName = "SecondMethod";
301+
302+
using (var activity = InternalActivitySource.StartActivity(firstMethodName, ActivityKind.Internal))
303+
{
304+
var cluster = GetNewTemporaryCluster(b => b.AddOpenTelemetryInstrumentation());
305+
var session = cluster.Connect();
306+
307+
var statement = new SimpleStatement("SELECT key FROM system.local");
308+
session.Execute(statement);
309+
310+
SecondMethod(secondMethodName);
311+
}
312+
313+
var firstMethodActivity = GetActivities().First(x => x.DisplayName == firstMethodName);
314+
var secondMethodActivity = GetActivities().First(x => x.DisplayName == secondMethodName);
315+
var sessionActivity = GetActivities().First(x => x.DisplayName == SessionActivityName);
316+
317+
Assert.AreEqual(firstMethodActivity.TraceId, sessionActivity.TraceId);
318+
Assert.AreEqual(firstMethodActivity.SpanId, sessionActivity.ParentSpanId);
319+
320+
Assert.AreEqual(firstMethodActivity.TraceId, secondMethodActivity.TraceId);
321+
Assert.AreEqual(firstMethodActivity.SpanId, secondMethodActivity.ParentSpanId);
322+
}
323+
324+
[Test]
325+
public void AddOpenTelemetry_RetryOnNextHost_ShouldProduceOneErrorAndOneValidSpansForTheSameSessionSpan()
326+
{
327+
var expectedErrorDescription = "overloaded";
328+
329+
using (var simulacronCluster = SimulacronCluster.CreateNew(3))
330+
{
331+
var contactPoint = simulacronCluster.InitialContactPoint;
332+
var nodes = simulacronCluster.GetNodes().ToArray();
333+
var loadBalancingPolicy = new CustomLoadBalancingPolicy(
334+
nodes.Select(n => n.ContactPoint).ToArray());
335+
336+
var builder = ClusterBuilder()
337+
.AddContactPoint(contactPoint)
338+
.WithSocketOptions(new SocketOptions()
339+
.SetConnectTimeoutMillis(10000)
340+
.SetReadTimeoutMillis(5000))
341+
.WithLoadBalancingPolicy(loadBalancingPolicy)
342+
.WithRetryPolicy(TryNextHostRetryPolicy.Instance)
343+
.AddOpenTelemetryInstrumentation();
344+
345+
using (var cluster = builder.Build())
346+
{
347+
var session = (Session)cluster.Connect();
348+
const string cql = "select * from table2";
349+
350+
nodes[0].PrimeFluent(
351+
b => b.WhenQuery(cql).
352+
ThenOverloaded(expectedErrorDescription));
353+
354+
nodes[1].PrimeFluent(
355+
b => b.WhenQuery(cql).
356+
ThenRowsSuccess(new[] { ("text", DataType.Ascii) }, rows => rows.WithRow("test1").WithRow("test2")));
357+
358+
session.Execute(new SimpleStatement(cql).SetConsistencyLevel(ConsistencyLevel.One));
359+
360+
var activities = GetActivities();
361+
var sessionActivity = activities.First(x => x.DisplayName.StartsWith(SessionActivityName));
362+
var validNodeActivity = activities.First(x => x.DisplayName.StartsWith(NodeActivityName) && x.Status != ActivityStatusCode.Error);
363+
var errorNodeActivity = activities.First(x => x.DisplayName.StartsWith(NodeActivityName) && x.Status == ActivityStatusCode.Error);
364+
365+
Assert.AreEqual(sessionActivity.TraceId, validNodeActivity.TraceId);
366+
Assert.AreEqual(sessionActivity.TraceId, errorNodeActivity.TraceId);
367+
Assert.AreEqual(sessionActivity.SpanId, validNodeActivity.ParentSpanId);
368+
Assert.AreEqual(sessionActivity.SpanId, errorNodeActivity.ParentSpanId);
369+
Assert.AreEqual(expectedErrorDescription, errorNodeActivity.StatusDescription);
370+
Assert.True(validNodeActivity.StartTimeUtc > errorNodeActivity.StartTimeUtc);
371+
}
372+
}
373+
}
374+
375+
[Test]
376+
public void AddOpenTelemetry_WithPaginationOnQuery_ShouldMultipleSpansForTheSameTraceId()
377+
{
378+
var expectedNumberOfSessionActivities = 2;
379+
380+
using (var activity = InternalActivitySource.StartActivity("Paging", ActivityKind.Internal))
381+
{
382+
var session = GetNewTemporaryCluster(b => b.AddOpenTelemetryInstrumentation()).Connect();
383+
384+
session.CreateKeyspaceIfNotExists(KeyspaceName, null, false);
385+
386+
session.ChangeKeyspace(KeyspaceName);
387+
388+
CreateSongTable(session);
389+
390+
for (int i = 0; i < expectedNumberOfSessionActivities; i++)
391+
{
392+
session.Execute(string.Format("INSERT INTO {0}.song (Artist, Title, Id, ReleaseDate) VALUES('Pink Floyd', 'The Dark Side Of The Moon', {1}, {2})", KeyspaceName, Guid.NewGuid(), ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeSeconds()));
393+
}
394+
395+
_exportedActivities.Clear();
396+
397+
var rs = session.Execute(new SimpleStatement(string.Format("SELECT * FROM {0}.song", KeyspaceName)).SetPageSize(1));
398+
399+
rs.FetchMoreResults();
400+
401+
var sessionActivities = GetActivities().Where(x => x.DisplayName == SessionActivityName);
402+
403+
Assert.AreEqual(expectedNumberOfSessionActivities, sessionActivities.Count());
404+
Assert.AreEqual(expectedNumberOfSessionActivities, rs.InnerQueueCount);
405+
406+
var firstActivity = sessionActivities.First();
407+
var lastActivity = sessionActivities.Last();
408+
409+
Assert.AreEqual(firstActivity.TraceId, lastActivity.TraceId);
410+
Assert.AreNotEqual(firstActivity.SpanId, lastActivity.SpanId);
411+
}
412+
}
413+
414+
private static void CreateSongTable(ISession session)
415+
{
416+
string createTableQuery = @"
417+
CREATE TABLE IF NOT EXISTS song (
418+
Artist text,
419+
Title text,
420+
Id uuid,
421+
ReleaseDate timestamp,
422+
PRIMARY KEY (id)
423+
)";
424+
425+
session.Execute(createTableQuery);
426+
}
427+
262428
private List<Activity> GetActivities()
263429
{
264430
var count = 0;
@@ -317,5 +483,13 @@ private static void ValidateNodeActivityAttributes(Activity activity)
317483
Assert.AreEqual(tags.FirstOrDefault(x => x.Key == pair.Key).Value, expectedTags[pair.Key]);
318484
}
319485
}
486+
487+
private void SecondMethod(string activityName)
488+
{
489+
using (var activity = InternalActivitySource.StartActivity(activityName, ActivityKind.Internal))
490+
{
491+
activity.AddTag("db.test", "t");
492+
}
493+
}
320494
}
321495
}

src/Cassandra.IntegrationTests/Policies/Tests/RetryPolicyShortTests.cs

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using System.Linq;
2020
using System.Threading;
2121
using System.Threading.Tasks;
22+
using Cassandra.IntegrationTests.Policies.Util;
2223
using Cassandra.IntegrationTests.SimulacronAPI;
2324
using Cassandra.IntegrationTests.SimulacronAPI.PrimeBuilder.Then;
2425
using Cassandra.IntegrationTests.TestBase;
@@ -263,37 +264,5 @@ public RetryDecision OnRequestError(IStatement statement, Configuration config,
263264
return RetryDecision.Retry(null, true);
264265
}
265266
}
266-
267-
private class CustomLoadBalancingPolicy : ILoadBalancingPolicy
268-
{
269-
private ICluster _cluster;
270-
private readonly string[] _hosts;
271-
272-
public CustomLoadBalancingPolicy(string[] hosts)
273-
{
274-
_hosts = hosts;
275-
}
276-
277-
public void Initialize(ICluster cluster)
278-
{
279-
_cluster = cluster;
280-
}
281-
282-
public HostDistance Distance(Host host)
283-
{
284-
return HostDistance.Local;
285-
}
286-
287-
public IEnumerable<Host> NewQueryPlan(string keyspace, IStatement query)
288-
{
289-
var queryPlan = new List<Host>();
290-
var allHosts = _cluster.AllHosts();
291-
foreach (var host in _hosts)
292-
{
293-
queryPlan.Add(allHosts.Single(h => h.Address.ToString() == host));
294-
}
295-
return queryPlan;
296-
}
297-
}
298267
}
299268
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
namespace Cassandra.IntegrationTests.Policies.Util
5+
{
6+
public class CustomLoadBalancingPolicy : ILoadBalancingPolicy
7+
{
8+
private ICluster _cluster;
9+
private readonly string[] _hosts;
10+
11+
public CustomLoadBalancingPolicy(string[] hosts)
12+
{
13+
_hosts = hosts;
14+
}
15+
16+
public void Initialize(ICluster cluster)
17+
{
18+
_cluster = cluster;
19+
}
20+
21+
public HostDistance Distance(Host host)
22+
{
23+
return HostDistance.Local;
24+
}
25+
26+
public IEnumerable<Host> NewQueryPlan(string keyspace, IStatement query)
27+
{
28+
var queryPlan = new List<Host>();
29+
var allHosts = _cluster.AllHosts();
30+
foreach (var host in _hosts)
31+
{
32+
queryPlan.Add(allHosts.Single(h => h.Address.ToString() == host));
33+
}
34+
return queryPlan;
35+
}
36+
}
37+
}

src/Cassandra/Requests/RequestHandler.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
using Cassandra.Collections;
2626
using Cassandra.Connections;
2727
using Cassandra.ExecutionProfiles;
28-
using Cassandra.Observers;
2928
using Cassandra.Observers.Abstractions;
3029
using Cassandra.Serialization;
3130
using Cassandra.SessionManagement;

src/Extensions/Cassandra.OpenTelemetry/OpenTelemetryRequestTracker.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,17 @@ public virtual Task OnErrorAsync(RequestTrackingInfo request, Exception ex)
134134
/// <returns>Completed task./returns>
135135
public virtual Task OnNodeSuccessAsync(RequestTrackingInfo request, HostTrackingInfo hostInfo)
136136
{
137-
request.Items.TryGetValue($"{otelActivityKey}.{hostInfo.Host.HostId}", out object context);
137+
var activityKey = $"{otelActivityKey}.{hostInfo.Host.HostId}";
138+
139+
request.Items.TryGetValue(activityKey, out object context);
138140

139141
if (context is Activity activity)
140142
{
141143
activity?.Dispose();
142144
}
143145

146+
request.Items.TryRemove(activityKey, out _);
147+
144148
return Task.CompletedTask;
145149
}
146150

@@ -154,7 +158,9 @@ public virtual Task OnNodeSuccessAsync(RequestTrackingInfo request, HostTracking
154158
/// <returns>Completed task./returns>
155159
public virtual Task OnNodeErrorAsync(RequestTrackingInfo request, HostTrackingInfo hostInfo, Exception ex)
156160
{
157-
request.Items.TryGetValue($"{otelActivityKey}.{hostInfo.Host.HostId}", out object context);
161+
var activityKey = $"{otelActivityKey}.{hostInfo.Host.HostId}";
162+
163+
request.Items.TryGetValue(activityKey, out object context);
158164

159165
if (!(context is Activity activity))
160166
{
@@ -166,6 +172,8 @@ public virtual Task OnNodeErrorAsync(RequestTrackingInfo request, HostTrackingIn
166172

167173
activity?.Dispose();
168174

175+
request.Items.TryRemove(activityKey, out _);
176+
169177
return Task.CompletedTask;
170178
}
171179

0 commit comments

Comments
 (0)