Skip to content

CSHARP-4394: Improve test coverage for retryable handshake errors #975

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,926 changes: 2,874 additions & 52 deletions specifications/retryable-reads/tests/unified/handshakeError.json

Large diffs are not rendered by default.

1,319 changes: 1,266 additions & 53 deletions specifications/retryable-reads/tests/unified/handshakeError.yml

Large diffs are not rendered by default.

1,648 changes: 1,583 additions & 65 deletions specifications/retryable-writes/tests/unified/handshakeError.json

Large diffs are not rendered by default.

764 changes: 706 additions & 58 deletions specifications/retryable-writes/tests/unified/handshakeError.yml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/

using System.Collections.Generic;
using System.Linq;
using MongoDB.Bson;
using MongoDB.Bson.TestHelpers.JsonDrivenTests;
using MongoDB.Driver.Core.TestHelpers.Logging;
Expand All @@ -27,6 +28,13 @@ namespace MongoDB.Driver.Tests.Specifications.retryable_reads
[Trait("Category", "Serverless")]
public sealed class RetryableReadsUnifiedTestRunner : LoggableTestClass
{
private readonly static string[] __operationsToSkip =
new[]
{
"findOne",
"listIndexNames"
};

// public constructors
public RetryableReadsUnifiedTestRunner(ITestOutputHelper testOutputHelper)
: base(testOutputHelper)
Expand Down Expand Up @@ -55,6 +63,11 @@ protected override IEnumerable<JsonDrivenTestCase> CreateTestCases(BsonDocument
{
foreach (var testCase in base.CreateTestCases(document))
{
if (__operationsToSkip.Any(testCase.Name.Contains))
{
continue;
}

foreach (var async in new[] { false, true })
{
var name = $"{testCase.Name}:async={async}";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver.Core.Misc;

namespace MongoDB.Driver.Tests.UnifiedTestOperations
{
public class UnifiedListCollectionNamesOperation : IUnifiedEntityTestOperation
{
private readonly IMongoDatabase _database;
private readonly ListCollectionNamesOptions _options;
private readonly IClientSessionHandle _session;

public UnifiedListCollectionNamesOperation(
IMongoDatabase database,
ListCollectionNamesOptions options,
IClientSessionHandle session)
{
_database = Ensure.IsNotNull(database, nameof(database));
_options = options; // can be null
_session = session;
}

public OperationResult Execute(CancellationToken cancellationToken)
{
try
{
using var cursor = _session == null
? _database.ListCollectionNames(_options, cancellationToken)
: _database.ListCollectionNames(_session, _options, cancellationToken);

var collections = cursor.ToList(cancellationToken);

return OperationResult.FromResult(new BsonArray(collections));
}
catch (Exception ex)
{
return OperationResult.FromException(ex);
}
}

public async Task<OperationResult> ExecuteAsync(CancellationToken cancellationToken)
{
try
{
using var cursor = _session == null
? await _database.ListCollectionNamesAsync(_options, cancellationToken)
: await _database.ListCollectionNamesAsync(_session, _options, cancellationToken);

var collections = await cursor.ToListAsync(cancellationToken);

return OperationResult.FromResult(new BsonArray(collections));
}
catch (Exception ex)
{
return OperationResult.FromException(ex);
}
}
}

public class UnifiedListCollectionNamesOperationBuilder
{
private readonly UnifiedEntityMap _entityMap;

public UnifiedListCollectionNamesOperationBuilder(UnifiedEntityMap entityMap)
{
_entityMap = entityMap;
}

public UnifiedListCollectionNamesOperation Build(string targetDatabaseId, BsonDocument arguments)
{
var database = _entityMap.GetDatabase(targetDatabaseId);

var listCollectionsOptions = new ListCollectionNamesOptions();
IClientSessionHandle session = null;

if (arguments != null)
{
foreach (var argument in arguments)
{
switch (argument.Name)
{
case "filter":
listCollectionsOptions.Filter = argument.Value.AsBsonDocument;
break;
case "session":
session = _entityMap.GetSession(argument.Value.AsString);
break;
default:
throw new FormatException($"Invalid {nameof(UnifiedListCollectionNamesOperation)} argument name: '{argument.Name}'.");
}
}
}

return new UnifiedListCollectionNamesOperation(database, listCollectionsOptions, session);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public UnifiedListCollectionsOperation Build(string targetDatabaseId, BsonDocume
session = _entityMap.GetSession(argument.Value.AsString);
break;
default:
throw new FormatException($"Invalid AssertIndexNotExistsOperation argument name: '{argument.Name}'.");
throw new FormatException($"Invalid {nameof(UnifiedListCollectionsOperation)} argument name: '{argument.Name}'.");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Bson;

namespace MongoDB.Driver.Tests.UnifiedTestOperations
{
public class UnifiedListDatabaseNamesOperation : IUnifiedEntityTestOperation
{
private readonly IMongoClient _client;
private readonly ListDatabaseNamesOptions _options = null;
private readonly IClientSessionHandle _session = null;

public UnifiedListDatabaseNamesOperation(
IMongoClient client,
ListDatabaseNamesOptions options,
IClientSessionHandle session)
{
_client = client;
_options = options;
_session = session;
}

public OperationResult Execute(CancellationToken cancellationToken)
{
try
{
using var cursor = _session == null
? _client.ListDatabaseNames(_options, cancellationToken)
: _client.ListDatabaseNames(_session, _options, cancellationToken);

var result = cursor.ToList(cancellationToken);

return OperationResult.FromResult(new BsonArray(result));
}
catch (Exception exception)
{
return OperationResult.FromException(exception);
}
}

public async Task<OperationResult> ExecuteAsync(CancellationToken cancellationToken)
{
try
{
using var cursor = _session == null
? await _client.ListDatabaseNamesAsync(_options, cancellationToken)
: await _client.ListDatabaseNamesAsync(_session, _options, cancellationToken);

var result = await cursor.ToListAsync(cancellationToken);

return OperationResult.FromResult(new BsonArray(result));
}
catch (Exception exception)
{
return OperationResult.FromException(exception);
}
}
}

public class UnifiedListDatabaseNamesOperationBuilder
{
private readonly UnifiedEntityMap _entityMap;

public UnifiedListDatabaseNamesOperationBuilder(UnifiedEntityMap entityMap)
{
_entityMap = entityMap;
}

public UnifiedListDatabaseNamesOperation Build(string targetClientId, BsonDocument arguments)
{
var client = _entityMap.GetClient(targetClientId);
ListDatabaseNamesOptions options = null;
IClientSessionHandle session = null;

if (arguments != null)
{
foreach (var argument in arguments)
{
switch (argument.Name)
{
case "filter":
options ??= new ListDatabaseNamesOptions();
options.Filter = new BsonDocumentFilterDefinition<BsonDocument>(argument.Value.AsBsonDocument);
break;
case "session":
session = _entityMap.GetSession(argument.Value.AsString);
break;
default:
throw new FormatException($"Invalid ListDatabasesOperation argument name: '{argument.Name}'.");
}
}
}

return new UnifiedListDatabaseNamesOperation(client, options, session);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public IUnifiedTestOperation CreateOperation(string operationName, string target
"close" => new UnifiedCloseClientOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
"createChangeStream" => new UnifiedCreateChangeStreamOnClientOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
"listDatabases" => new UnifiedListDatabasesOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
"listDatabaseNames" => new UnifiedListDatabaseNamesOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
_ => throw new FormatException($"Invalid method name: '{operationName}'."),
},
_ when _entityMap.HasCollection(targetEntityId) => operationName switch
Expand Down Expand Up @@ -107,6 +108,7 @@ public IUnifiedTestOperation CreateOperation(string operationName, string target
"createChangeStream" => new UnifiedCreateChangeStreamOnDatabaseOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
"dropCollection" => new UnifiedDropCollectionOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
"listCollections" => new UnifiedListCollectionsOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
"listCollectionNames" => new UnifiedListCollectionNamesOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
"runCommand" => new UnifiedRunCommandOperationBuilder(_entityMap).Build(targetEntityId, operationArguments),
_ => throw new FormatException($"Invalid method name: '{operationName}'."),
},
Expand Down