Skip to content

Commit

Permalink
added server selection rtt tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
craiggwilson committed Mar 5, 2015
1 parent dfa3631 commit 9da54d4
Show file tree
Hide file tree
Showing 70 changed files with 3,394 additions and 5 deletions.
68 changes: 68 additions & 0 deletions src/MongoDB.Driver.Core.Tests/MongoDB.Driver.Core.Tests.csproj
Expand Up @@ -143,6 +143,7 @@
<Compile Include="Core\Clusters\SingleServerClusterTests.cs" />
<Compile Include="SetUpFixture.cs" />
<Compile Include="Specifications\server-discovery-and-monitoring\TestRunner.cs" />
<Compile Include="Specifications\server-selection\RttTestRunner.cs" />
<Compile Include="TagSetTests.cs" />
<Compile Include="TagTests.cs" />
<Compile Include="Core\Configuration\ConnectionStringTests.cs" />
Expand Down Expand Up @@ -300,6 +301,73 @@
<None Include="Specifications\server-discovery-and-monitoring\tests\single\standalone_removed.yml" />
<EmbeddedResource Include="Specifications\server-discovery-and-monitoring\tests\single\unavailable_seed.json" />
<None Include="Specifications\server-discovery-and-monitoring\tests\single\unavailable_seed.yml" />
<None Include="Specifications\server-selection\tests\README.rst" />
<EmbeddedResource Include="Specifications\server-selection\tests\rtt\first_value.json" />
<None Include="Specifications\server-selection\tests\rtt\first_value.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\rtt\first_value_zero.json" />
<None Include="Specifications\server-selection\tests\rtt\first_value_zero.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\rtt\value_test_1.json" />
<None Include="Specifications\server-selection\tests\rtt\value_test_1.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\rtt\value_test_2.json" />
<None Include="Specifications\server-selection\tests\rtt\value_test_2.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\rtt\value_test_3.json" />
<None Include="Specifications\server-selection\tests\rtt\value_test_3.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\rtt\value_test_4.json" />
<None Include="Specifications\server-selection\tests\rtt\value_test_4.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\rtt\value_test_5.json" />
<None Include="Specifications\server-selection\tests\rtt\value_test_5.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Nearest.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Nearest.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Nearest_non_matching.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Nearest_non_matching.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Primary.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Primary.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\PrimaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\PrimaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\PrimaryPreferred_non_matching.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\PrimaryPreferred_non_matching.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Secondary.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Secondary.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\SecondaryPreferred_non_matching.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\SecondaryPreferred_non_matching.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Secondary_non_matching.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\read\Secondary_non_matching.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\write\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetNoPrimary\write\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Nearest.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Nearest.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Nearest_non_matching.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Nearest_non_matching.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Primary.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Primary.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\PrimaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\PrimaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\PrimaryPreferred_non_matching.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\PrimaryPreferred_non_matching.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Secondary.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Secondary.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\SecondaryPreferred_non_matching.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\SecondaryPreferred_non_matching.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Secondary_non_matching.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\read\Secondary_non_matching.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\write\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\ReplicaSetWithPrimary\write\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\Sharded\read\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\Sharded\read\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\Sharded\write\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\Sharded\write\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\Single\read\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\Single\read\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\Single\write\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\Single\write\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\Unknown\read\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\Unknown\read\SecondaryPreferred.yml" />
<EmbeddedResource Include="Specifications\server-selection\tests\server_selection\Unknown\write\SecondaryPreferred.json" />
<None Include="Specifications\server-selection\tests\server_selection\Unknown\write\SecondaryPreferred.yml" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
Expand Down
@@ -0,0 +1,92 @@
/* Copyright 2013-2014 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Driver.Core.Configuration;
using MongoDB.Driver.Core.Connections;
using MongoDB.Driver.Core.Events;
using MongoDB.Driver.Core.Helpers;
using MongoDB.Driver.Core.Misc;
using MongoDB.Driver.Core.Servers;
using FluentAssertions;
using NSubstitute;
using NUnit.Framework;
using MongoDB.Driver.Core.Clusters;

namespace MongoDB.Driver.Specifications.server_selection
{
[TestFixture]
public class RttTestRunner
{
[TestCaseSource(typeof(TestCaseFactory), "GetTestCases")]
public void RunTestDefinition(BsonDocument definition)
{
var subject = new ExponentiallyWeightedMovingAverage(0.2);

var current = definition["avg_rtt_ms"];
if(current.ToString() != "NULL")
{
subject.AddSample(TimeSpan.FromMilliseconds(current.ToDouble())); // the first value
}

var nextValue = definition["new_rtt_ms"].ToDouble();
subject.AddSample(TimeSpan.FromMilliseconds(nextValue));
var expected = definition["new_avg_rtt"].ToDouble();

subject.Average.Should().BeCloseTo(TimeSpan.FromMilliseconds(expected), 1);
}

private static class TestCaseFactory
{
public static IEnumerable<ITestCaseData> GetTestCases()
{
const string prefix = "MongoDB.Driver.Specifications.server_selection.tests.rtt.";
return Assembly
.GetExecutingAssembly()
.GetManifestResourceNames()
.Where(path => path.StartsWith(prefix) && path.EndsWith(".json"))
.Select(path =>
{
var definition = ReadDefinition(path);
var fullName = path.Remove(0, prefix.Length);
var data = new TestCaseData(definition);
data.Categories.Add("Specifications");
data.Categories.Add("server-selection");
return data.SetName(fullName.Remove(fullName.Length - 5));
});
}

private static BsonDocument ReadDefinition(string path)
{
using (var definitionStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path))
using (var definitionStringReader = new StreamReader(definitionStream))
{
var definitionString = definitionStringReader.ReadToEnd();
return BsonDocument.Parse(definitionString);
}
}
}
}
}
@@ -0,0 +1,99 @@
======================
Server Selection Tests
======================

This directory contains platform-independent tests that drivers can use
to prove their conformance to the Server Selection spec. The tests
are provided in both YAML and JSON formats, and drivers may test against
whichever format is more convenient for them.

Converting to JSON
------------------

The Server Selection tests were originally written in YAML. YAML has
a standard comment format, which makes it more human-readable than JSON,
and it also has language features for expressing duplicated information
more concisely. A JSON-converted version of each YAML test is included
here, but if you change the YAML, you will need to re-convert to JSON.
One way of converting YAML to JSON is with
`jsonwidget-python <http://jsonwidget.org/wiki/Jsonwidget-python>`_::

pip install PyYAML urwid jsonwidget
make

Or instead of "make"::

for i in `find . -iname '*.yml'`; do
echo "${i%.*}"
jwc yaml2json $i > ${i%.*}.json
done

Version
-------

Specifications have no version scheme.
They are not tied to a MongoDB server version,
and it is our intention that each specification moves from "draft" to "final"
with no further versions; it is superseded by a future spec, not revised.

However, implementers must have stable sets of tests to target.
As test files evolve they will be occasionally tagged like
"server-selection-tests-2015-01-04", until the spec is final.

Test Format and Use
-------------------

There are two types of tests for the server selection spec, tests for
round trip time (RTT) calculation, and tests for server selection logic.

Drivers should be able to test their server selection logic
without any network I/O, by parsing topology descriptions and read preference
documents from the test files and passing them into driver code. Parts of the
server selection code may need to be mocked or subclassed to achieve this.

RTT Calculation Tests
>>>>>>>>>>>>>>>>>>>>>

These YAML files contain the following keys:

- ``avg_rtt_ms``: a server's previous average RTT, in milliseconds
- ``new_rtt_ms``: a new RTT value for this server, in milliseconds
- ``new_avg_rtt``: this server's newly-calculated average RTT, in milliseconds

For each file, create a server description object initialized with ``avg_rtt_ms``.
Parse ``new_rtt_ms``, and ensure that the new RTT value for the mocked server
description is equal to ``new_avg_rtt``.

If driver architecture doesn't easily allow construction of server description
objects in isolation, unit testing the EWMA algorithm using these inputs
and expected outputs is acceptable.

Server Selection Logic Tests
>>>>>>>>>>>>>>>>>>>>>>>>>>>>

These YAML files contain the following setup for each test:

- ``topology_description``: the state of a mocked cluster
- ``operation``: the kind of operation to perform, either read or write
- ``read_preference``: a read preference document

For each file, create a new TopologyDescription object initialized with the values
from ``topology_description``. Create a ReadPreference object initialized with the
values from ``read_preference``.

Together with "operation", pass the newly-created TopologyDescription and ReadPreference
to server selection, and ensure that it selects the correct subset of servers from
the TopologyDescription. Each YAML file contains a key for each substage of server selection:

- ``candidate_servers``: the set of servers in topology_description that are candidates,
as per the Server Selection spec, given operation and read_preference
- ``eligible_servers``: the set of servers in topology_description that are eligible, as
per the Server Selection spec, given operation and read_preference
- ``suitable_servers``: the set of servers in topology_description that are suitable, as
per the Server Selection spec, given operation and read_preference
- ``in_latency_window``: the set of suitable_servers that fall within the latency window

Drivers implementing server selection MUST test that their implementations
correctly return the set of servers in ``in_latency_window``. Drivers SHOULD test against
``suitable_servers`` if possible, and MAY test against ``eligible_servers`` and
``candidate_servers`` if testing at intermediate stages of server selection is desired.
@@ -0,0 +1,5 @@
{
"avg_rtt_ms": "NULL",
"new_avg_rtt": 10,
"new_rtt_ms": 10
}
@@ -0,0 +1,4 @@
---
avg_rtt_ms: 'NULL'
new_rtt_ms: 10
new_avg_rtt: 10
@@ -0,0 +1,5 @@
{
"avg_rtt_ms": "NULL",
"new_avg_rtt": 0,
"new_rtt_ms": 0
}
@@ -0,0 +1,4 @@
---
avg_rtt_ms: 'NULL'
new_rtt_ms: 0
new_avg_rtt: 0
@@ -0,0 +1,5 @@
{
"avg_rtt_ms": 0,
"new_avg_rtt": 1.0,
"new_rtt_ms": 5
}
@@ -0,0 +1,4 @@
---
avg_rtt_ms: 0
new_rtt_ms: 5
new_avg_rtt: 1.0
@@ -0,0 +1,5 @@
{
"avg_rtt_ms": 3.1,
"new_avg_rtt": 9.68,
"new_rtt_ms": 36
}
@@ -0,0 +1,4 @@
---
avg_rtt_ms: 3.1
new_rtt_ms: 36
new_avg_rtt: 9.68
@@ -0,0 +1,5 @@
{
"avg_rtt_ms": 9.12,
"new_avg_rtt": 9.12,
"new_rtt_ms": 9.12
}
@@ -0,0 +1,4 @@
---
avg_rtt_ms: 9.12
new_rtt_ms: 9.12
new_avg_rtt: 9.12
@@ -0,0 +1,5 @@
{
"avg_rtt_ms": 1,
"new_avg_rtt": 200.8,
"new_rtt_ms": 1000
}
@@ -0,0 +1,4 @@
---
avg_rtt_ms: 1
new_rtt_ms: 1000
new_avg_rtt: 200.8
@@ -0,0 +1,5 @@
{
"avg_rtt_ms": 0,
"new_avg_rtt": 0.05,
"new_rtt_ms": 0.25
}
@@ -0,0 +1,4 @@
---
avg_rtt_ms: 0
new_rtt_ms: 0.25
new_avg_rtt: 0.05

0 comments on commit 9da54d4

Please sign in to comment.