Skip to content

Commit 750d021

Browse files
vincentkamMikalaiMazurenka
authored andcommitted
CSHARP-2515: Test Planned Maintenance Scenarios in Drivers
1 parent 7374ea0 commit 750d021

File tree

7 files changed

+456
-1
lines changed

7 files changed

+456
-1
lines changed

CSharpDriver.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SkippableTests", "tests\Ski
5454
EndProject
5555
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Driver.TestConsoleApplication", "tests\MongoDB.Driver.TestConsoleApplication\MongoDB.Driver.TestConsoleApplication.csproj", "{2E5780D2-29A5-483C-9CA2-844F45A66D0C}"
5656
EndProject
57+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AstrolabeWorkloadExecutor", "tests\AstrolabeWorkloadExecutor\AstrolabeWorkloadExecutor.csproj", "{B90F025F-89D3-436A-AD78-6AA304A6E240}"
58+
EndProject
5759
Global
5860
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5961
Debug|Any CPU = Debug|Any CPU
@@ -136,6 +138,10 @@ Global
136138
{2E5780D2-29A5-483C-9CA2-844F45A66D0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
137139
{2E5780D2-29A5-483C-9CA2-844F45A66D0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
138140
{2E5780D2-29A5-483C-9CA2-844F45A66D0C}.Release|Any CPU.Build.0 = Release|Any CPU
141+
{B90F025F-89D3-436A-AD78-6AA304A6E240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
142+
{B90F025F-89D3-436A-AD78-6AA304A6E240}.Debug|Any CPU.Build.0 = Debug|Any CPU
143+
{B90F025F-89D3-436A-AD78-6AA304A6E240}.Release|Any CPU.ActiveCfg = Release|Any CPU
144+
{B90F025F-89D3-436A-AD78-6AA304A6E240}.Release|Any CPU.Build.0 = Release|Any CPU
139145
EndGlobalSection
140146
GlobalSection(SolutionProperties) = preSolution
141147
HideSolutionNode = FALSE
@@ -160,6 +166,7 @@ Global
160166
{D197D685-5509-491E-A456-BA36C662CBB4} = {E472BDF5-61F1-461D-872B-9F53BB3ACA80}
161167
{D198833A-6AC3-4327-8B02-5095455192D0} = {E472BDF5-61F1-461D-872B-9F53BB3ACA80}
162168
{2E5780D2-29A5-483C-9CA2-844F45A66D0C} = {E472BDF5-61F1-461D-872B-9F53BB3ACA80}
169+
{B90F025F-89D3-436A-AD78-6AA304A6E240} = {E472BDF5-61F1-461D-872B-9F53BB3ACA80}
163170
EndGlobalSection
164171
GlobalSection(ExtensibilityGlobals) = postSolution
165172
SolutionGuid = {24BEC44B-92B0-43AA-9B15-163459D0C098}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/* Copyright 2020-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using System.Collections.Generic;
18+
using System.Linq;
19+
using System.Threading;
20+
using MongoDB.Bson;
21+
using MongoDB.Bson.TestHelpers;
22+
using MongoDB.Bson.TestHelpers.JsonDrivenTests;
23+
using MongoDB.Driver;
24+
using MongoDB.Driver.Core;
25+
using MongoDB.Driver.TestHelpers;
26+
using MongoDB.Driver.Tests.Specifications.Runner;
27+
28+
namespace WorkloadExecutor
29+
{
30+
public class AstrolabeTestRunner : MongoClientJsonDrivenTestRunnerBase
31+
{
32+
// private fields
33+
private readonly CancellationToken _cancellationToken;
34+
private readonly Action _incrementOperationSuccesses;
35+
private readonly Action _incrementOperationErrors;
36+
private readonly Action _incrementOperationFailures;
37+
38+
// protected properties
39+
protected override string[] ExpectedSharedColumns => new[] { "_path", "database", "collection", "testData", "tests" };
40+
protected override string[] ExpectedTestColumns => new[] { "operations", "async" };
41+
42+
public AstrolabeTestRunner(
43+
Action incrementOperationSuccesses,
44+
Action incrementOperationErrors,
45+
Action incrementOperationFailures,
46+
CancellationToken cancellationToken)
47+
{
48+
_incrementOperationSuccesses = incrementOperationSuccesses;
49+
_incrementOperationErrors = incrementOperationErrors;
50+
_incrementOperationFailures = incrementOperationFailures;
51+
_cancellationToken = cancellationToken;
52+
}
53+
54+
protected override string DatabaseNameKey => "database";
55+
protected override string CollectionNameKey => "collection";
56+
protected override string DataKey => "testData";
57+
58+
// public methods
59+
public void Run(JsonDrivenTestCase testCase)
60+
{
61+
SetupAndRunTest(testCase);
62+
}
63+
64+
// protected methods
65+
protected override void AssertOperation(JsonDrivenTest test)
66+
{
67+
var actualException = test._actualException();
68+
if (test._expectedException() == null)
69+
{
70+
if (actualException != null)
71+
{
72+
if (!(actualException is OperationCanceledException))
73+
{
74+
Console.WriteLine($"Operation error (unexpected exception type): {actualException.GetType()}");
75+
_incrementOperationErrors();
76+
}
77+
else
78+
{
79+
Console.WriteLine($"Operation cancelled: {actualException}");
80+
}
81+
82+
return;
83+
}
84+
if (test._expectedResult() == null)
85+
{
86+
_incrementOperationSuccesses();
87+
}
88+
else
89+
{
90+
try
91+
{
92+
test.AssertResult();
93+
_incrementOperationSuccesses();
94+
}
95+
catch (Exception ex)
96+
{
97+
Console.WriteLine($"Operation failure (unexpected exception type): {ex.GetType()}");
98+
_incrementOperationFailures();
99+
}
100+
}
101+
}
102+
else
103+
{
104+
if (actualException == null)
105+
{
106+
_incrementOperationErrors();
107+
108+
return;
109+
}
110+
try
111+
{
112+
test.AssertException();
113+
_incrementOperationSuccesses();
114+
}
115+
catch
116+
{
117+
_incrementOperationFailures();
118+
}
119+
}
120+
}
121+
122+
protected override void RunTest(BsonDocument shared, BsonDocument test, EventCapturer eventCapturer)
123+
{
124+
Console.WriteLine("dotnet astrolabetestrunner> creating disposable client...");
125+
using (var client = CreateDisposableMongoClient(eventCapturer))
126+
{
127+
Console.WriteLine("dotnet astrolabetestrunner> looping until cancellation is requested...");
128+
while (!_cancellationToken.IsCancellationRequested)
129+
{
130+
// Clone because inserts will auto assign an id to the test case document
131+
ExecuteOperations(
132+
client: client,
133+
objectMap: new Dictionary<string, object>(),
134+
test: test.DeepClone().AsBsonDocument);
135+
}
136+
}
137+
}
138+
139+
// private methods
140+
private DisposableMongoClient CreateDisposableMongoClient(EventCapturer eventCapturer)
141+
{
142+
var connectionString = Environment.GetEnvironmentVariable("MONGODB_URI");
143+
var settings = MongoClientSettings.FromConnectionString(connectionString);
144+
if (eventCapturer != null)
145+
{
146+
settings.ClusterConfigurator = c => c.Subscribe(eventCapturer);
147+
}
148+
149+
return new DisposableMongoClient(new MongoClient(settings));
150+
}
151+
152+
// nested types
153+
internal class TestCaseFactory : JsonDrivenTestCaseFactory
154+
{
155+
public JsonDrivenTestCase CreateTestCase(BsonDocument driverWorkload, bool async)
156+
{
157+
JsonDrivenHelper.EnsureAllFieldsAreValid(driverWorkload, new[] { "database", "collection", "testData", "operations" });
158+
159+
var adaptedDriverWorkload = new BsonDocument
160+
{
161+
{ "_path", "Astrolabe command line arguments" },
162+
{ "database", driverWorkload["database"] },
163+
{ "collection", driverWorkload["collection"] },
164+
{ "tests", new BsonArray(new [] { new BsonDocument("operations", driverWorkload["operations"]) }) }
165+
};
166+
if (driverWorkload.Contains("testData"))
167+
{
168+
adaptedDriverWorkload.Add("testData", driverWorkload["testData"]);
169+
}
170+
var testCase = CreateTestCases(adaptedDriverWorkload).Single();
171+
testCase.Test["async"] = async;
172+
173+
return testCase;
174+
}
175+
}
176+
}
177+
178+
internal static class JsonDrivenTestReflector
179+
{
180+
public static Exception _actualException(this JsonDrivenTest test)
181+
{
182+
return (Exception)Reflector.GetFieldValue(test, nameof(_actualException));
183+
}
184+
185+
public static BsonDocument _expectedException(this JsonDrivenTest test)
186+
{
187+
return (BsonDocument)Reflector.GetFieldValue(test, nameof(_expectedException));
188+
}
189+
190+
public static BsonValue _expectedResult(this JsonDrivenTest test)
191+
{
192+
return (BsonValue)Reflector.GetFieldValue(test, nameof(_expectedResult));
193+
}
194+
195+
public static void AssertException(this JsonDrivenTest test)
196+
{
197+
Reflector.Invoke(test, nameof(AssertException));
198+
}
199+
200+
public static void AssertResult(this JsonDrivenTest test)
201+
{
202+
Reflector.Invoke(test, nameof(AssertResult));
203+
}
204+
}
205+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFrameworks>netcoreapp2.1;netcoreapp1.1;net452</TargetFrameworks>
6+
<LangVersion>7.3</LangVersion>
7+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
8+
<WarningsAsErrors />
9+
<IsPackable>false</IsPackable>
10+
<AssemblyName>workload-executor</AssemblyName>
11+
<CodeAnalysisRuleSet>..\..\MongoDBTest.ruleset</CodeAnalysisRuleSet>
12+
</PropertyGroup>
13+
14+
<PropertyGroup>
15+
<AssemblyTitle>AstrolabeWorkloadExecutor</AssemblyTitle>
16+
<Product>AstrolabeWorkloadExecutor</Product>
17+
<Company>MongoDB Inc.</Company>
18+
<Copyright>Copyright © 2010-present MongoDB Inc.</Copyright>
19+
<Description>Astrolabe workload executor.</Description>
20+
</PropertyGroup>
21+
22+
<PropertyGroup Condition="'$(Version)'==''">
23+
<Version>0.0.0-local</Version>
24+
</PropertyGroup>
25+
26+
<PropertyGroup>
27+
<DefineConstants>TRACE</DefineConstants>
28+
</PropertyGroup>
29+
30+
<ItemGroup>
31+
<ProjectReference Include="../MongoDB.Driver.Tests/MongoDB.Driver.Tests.csproj" />
32+
</ItemGroup>
33+
</Project>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* Copyright 2020-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using System.IO;
18+
using System.Threading;
19+
using MongoDB.Bson;
20+
21+
namespace WorkloadExecutor
22+
{
23+
public static class Program
24+
{
25+
private static long __numberOfSuccessfulOperations;
26+
private static long __numberOfFailedOperations;
27+
private static long __numberOfOperationErrors;
28+
29+
public static void Main(string[] args)
30+
{
31+
var connectionString = args[0];
32+
var driverWorkload = BsonDocument.Parse(args[1]);
33+
34+
var cancellationTokenSource = new CancellationTokenSource();
35+
ConsoleCancelEventHandler cancelHandler = (o, e) => HandleCancel(e, cancellationTokenSource);
36+
37+
var resultsDir = Environment.GetEnvironmentVariable("RESULTS_DIR");
38+
var resultsPath = resultsDir == null ? "results.json" : Path.Combine(resultsDir, "results.json");
39+
Console.WriteLine($"dotnet main> Results will be written to {resultsPath}...");
40+
41+
try
42+
{
43+
Console.CancelKeyPress += cancelHandler;
44+
45+
Console.WriteLine("dotnet main> Starting workload executor...");
46+
47+
if (!bool.TryParse(Environment.GetEnvironmentVariable("ASYNC"), out bool async))
48+
{
49+
async = true;
50+
}
51+
52+
ExecuteWorkload(connectionString, driverWorkload, async, cancellationTokenSource.Token);
53+
}
54+
finally
55+
{
56+
Console.CancelKeyPress -= cancelHandler;
57+
Console.WriteLine("dotnet main finally> Writing final results file");
58+
var resultsJson = ConvertResultsToJson();
59+
Console.WriteLine(resultsJson);
60+
#if NETCOREAPP2_1
61+
File.WriteAllTextAsync(resultsPath, resultsJson).Wait();
62+
#else
63+
File.WriteAllText(resultsPath, resultsJson);
64+
#endif
65+
}
66+
}
67+
68+
private static string ConvertResultsToJson()
69+
{
70+
var resultsJson =
71+
@"{ " +
72+
$" \"numErrors\" : {__numberOfOperationErrors}, " +
73+
$" \"numFailures\" : {__numberOfFailedOperations}, " +
74+
$" \"numSuccesses\" : {__numberOfSuccessfulOperations} " +
75+
@"}";
76+
77+
return resultsJson;
78+
}
79+
80+
private static void ExecuteWorkload(string connectionString, BsonDocument driverWorkload, bool async, CancellationToken cancellationToken)
81+
{
82+
Environment.SetEnvironmentVariable("MONGODB_URI", connectionString);
83+
84+
var testRunner = new AstrolabeTestRunner(
85+
incrementOperationSuccesses: () => __numberOfSuccessfulOperations++,
86+
incrementOperationErrors: () => __numberOfOperationErrors++,
87+
incrementOperationFailures: () => __numberOfFailedOperations++,
88+
cancellationToken: cancellationToken);
89+
var factory = new AstrolabeTestRunner.TestCaseFactory();
90+
var testCase = factory.CreateTestCase(driverWorkload, async);
91+
testRunner.Run(testCase);
92+
Console.WriteLine("dotnet ExecuteWorkload> Returning...");
93+
}
94+
95+
private static void CancelWorkloadTask(CancellationTokenSource cancellationTokenSource)
96+
{
97+
Console.Write($"\ndotnet cancel workload> Canceling the workload task...");
98+
cancellationTokenSource.Cancel();
99+
Console.WriteLine($"Done.");
100+
}
101+
102+
private static void HandleCancel(
103+
ConsoleCancelEventArgs args,
104+
CancellationTokenSource cancellationTokenSource)
105+
{
106+
// We set the Cancel property to true to prevent the process from terminating
107+
args.Cancel = true;
108+
CancelWorkloadTask(cancellationTokenSource);
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)