Skip to content

Commit 091afa6

Browse files
CSHARP-3012: Remove a server from a multiServercluster in case if the server is not valid for the current cluster.
1 parent 257c8c8 commit 091afa6

File tree

6 files changed

+272
-14
lines changed

6 files changed

+272
-14
lines changed

src/MongoDB.Driver.Core/Core/Clusters/MultiServerCluster.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,8 @@ private void ProcessServerDescriptionChanged(ServerDescriptionChangedEventArgs a
318318
}
319319
else
320320
{
321-
newClusterDescription = newClusterDescription.WithoutServerDescription(newServerDescription.EndPoint);
321+
var reason = $"The server {newServerDescription.EndPoint} with type {newServerDescription.Type} is not valid for cluster type {newClusterDescription.Type}.";
322+
newClusterDescription = RemoveServer(newClusterDescription, newServerDescription.EndPoint, reason);
322323
}
323324
}
324325

tests/MongoDB.Driver.Core.Tests/Core/Clusters/MultiServerClusterTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,8 @@ public void Should_hide_a_seedlist_server_of_the_wrong_type(ClusterConnectionMod
736736
var description = subject.Description;
737737
description.Servers.Should().BeEquivalentToWithComparer(GetDescriptions(_firstEndPoint, _thirdEndPoint), _serverDescriptionComparer);
738738

739+
_capturedEvents.Next().Should().BeOfType<ClusterRemovingServerEvent>();
740+
_capturedEvents.Next().Should().BeOfType<ClusterRemovedServerEvent>();
739741
_capturedEvents.Next().Should().BeOfType<ClusterDescriptionChangedEvent>();
740742
_capturedEvents.Any().Should().BeFalse();
741743
}
@@ -762,6 +764,8 @@ public void Should_hide_a_discovered_server_of_the_wrong_type(ServerType wrongTy
762764
_capturedEvents.Next().Should().BeOfType<ClusterAddingServerEvent>();
763765
_capturedEvents.Next().Should().BeOfType<ClusterAddedServerEvent>();
764766
_capturedEvents.Next().Should().BeOfType<ClusterDescriptionChangedEvent>();
767+
_capturedEvents.Next().Should().BeOfType<ClusterRemovingServerEvent>();
768+
_capturedEvents.Next().Should().BeOfType<ClusterRemovedServerEvent>();
765769
_capturedEvents.Next().Should().BeOfType<ClusterDescriptionChangedEvent>();
766770
_capturedEvents.Any().Should().BeFalse();
767771
}

tests/MongoDB.Driver.Core.Tests/Core/Helpers/MockClusterableServerFactory.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,11 @@
1515

1616
using System;
1717
using System.Collections.Generic;
18-
using System.Linq;
1918
using System.Net;
20-
using System.Text;
21-
using System.Threading.Tasks;
2219
using MongoDB.Driver.Core.Clusters;
2320
using MongoDB.Driver.Core.Configuration;
2421
using MongoDB.Driver.Core.ConnectionPools;
2522
using MongoDB.Driver.Core.Events;
26-
using MongoDB.Driver.Core.Misc;
2723
using MongoDB.Driver.Core.Servers;
2824
using Moq;
2925

@@ -43,7 +39,7 @@ public MockClusterableServerFactory(IEventSubscriber eventSubscriber = null)
4339
public IClusterableServer CreateServer(ClusterId clusterId, IClusterClock clusterClock, EndPoint endPoint)
4440
{
4541
ServerTuple result;
46-
if (!_servers.TryGetValue(endPoint, out result))
42+
if (!_servers.TryGetValue(endPoint, out result) || result.HasBeenRemoved)
4743
{
4844
var description = new ServerDescription(new ServerId(clusterId, endPoint), endPoint);
4945

@@ -53,6 +49,13 @@ public IClusterableServer CreateServer(ClusterId clusterId, IClusterClock cluste
5349
mockServer.SetupGet(s => s.Description).Returns(description);
5450
mockServer.SetupGet(s => s.EndPoint).Returns(endPoint);
5551
mockServer.SetupGet(s => s.ServerId).Returns(new ServerId(clusterId, endPoint));
52+
mockServer
53+
.Setup(s => s.Dispose())
54+
.Callback(
55+
() =>
56+
{
57+
_servers[mockServer.Object.EndPoint].HasBeenRemoved = true;
58+
});
5659
result = new ServerTuple
5760
{
5861
Server = mockServer.Object
@@ -64,6 +67,13 @@ public IClusterableServer CreateServer(ClusterId clusterId, IClusterClock cluste
6467
var mockMonitor = new Mock<IServerMonitor>() { DefaultValue = DefaultValue.Mock };
6568
mockMonitorFactory.Setup(f => f.Create(It.IsAny<ServerId>(), It.IsAny<EndPoint>())).Returns(mockMonitor.Object);
6669
mockMonitor.SetupGet(m => m.Description).Returns(description);
70+
mockMonitor
71+
.Setup(s => s.Dispose())
72+
.Callback(
73+
() =>
74+
{
75+
_servers[mockMonitor.Object.Description.EndPoint].HasBeenRemoved = true;
76+
});
6777

6878
result = new ServerTuple
6979
{
@@ -118,7 +128,6 @@ public void PublishDescription(ServerDescription description)
118128
var mockServer = Mock.Get(result.Server);
119129
mockServer.SetupGet(s => s.Description).Returns(description);
120130
mockServer.Raise(s => s.DescriptionChanged += null, new ServerDescriptionChangedEventArgs(oldDescription, description));
121-
122131
}
123132
else
124133
{
@@ -130,6 +139,7 @@ public void PublishDescription(ServerDescription description)
130139

131140
private class ServerTuple
132141
{
142+
public bool HasBeenRemoved;
133143
public IClusterableServer Server;
134144
public IServerMonitor Monitor;
135145
}

tests/MongoDB.Driver.Core.Tests/Specifications/server-discovery-and-monitoring/TestRunner.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -273,18 +273,20 @@ private ICluster BuildCluster(BsonDocument definition)
273273

274274
private class TestCaseFactory : JsonDrivenTestCaseFactory
275275
{
276-
private readonly string __ignoredTestFolder = "MongoDB.Driver.Core.Tests.Specifications.server_discovery_and_monitoring.tests.monitoring.";
276+
// private constants
277+
private const string MonitoringPrefix = "MongoDB.Driver.Core.Tests.Specifications.server_discovery_and_monitoring.tests.monitoring.";
277278

278279
protected override string PathPrefix => "MongoDB.Driver.Core.Tests.Specifications.server_discovery_and_monitoring.tests.";
279280

280281
protected override IEnumerable<JsonDrivenTestCase> CreateTestCases(BsonDocument document)
281282
{
282-
var path = document["_path"].ToString();
283-
if (!path.StartsWith(__ignoredTestFolder))
284-
{
285-
var name = GetTestCaseName(document, document, 0);
286-
yield return new JsonDrivenTestCase(name, document, document);
287-
}
283+
var name = GetTestCaseName(document, document, 0);
284+
yield return new JsonDrivenTestCase(name, document, document);
285+
}
286+
287+
protected override bool ShouldReadJsonDocument(string path)
288+
{
289+
return base.ShouldReadJsonDocument(path) && !path.StartsWith(MonitoringPrefix);
288290
}
289291
}
290292
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
{
2+
"description": "Repeated ismaster response must be processed",
3+
"uri": "mongodb://a,b/?replicaSet=rs",
4+
"phases": [
5+
{
6+
"responses": [
7+
[
8+
"a:27017",
9+
{
10+
"ok": 1,
11+
"ismaster": false,
12+
"secondary": true,
13+
"hidden": true,
14+
"hosts": [
15+
"a:27017",
16+
"c:27017"
17+
],
18+
"setName": "rs",
19+
"minWireVersion": 0,
20+
"maxWireVersion": 6
21+
}
22+
]
23+
],
24+
"outcome": {
25+
"servers": {
26+
"a:27017": {
27+
"type": "RSOther",
28+
"setName": "rs"
29+
},
30+
"b:27017": {
31+
"type": "Unknown"
32+
},
33+
"c:27017": {
34+
"type": "Unknown"
35+
}
36+
},
37+
"topologyType": "ReplicaSetNoPrimary",
38+
"logicalSessionTimeoutMinutes": null,
39+
"setName": "rs"
40+
}
41+
},
42+
{
43+
"responses": [
44+
[
45+
"c:27017",
46+
{
47+
"ok": 1,
48+
"ismaster": true,
49+
"minWireVersion": 0,
50+
"maxWireVersion": 6
51+
}
52+
]
53+
],
54+
"outcome": {
55+
"servers": {
56+
"a:27017": {
57+
"type": "RSOther",
58+
"setName": "rs"
59+
},
60+
"b:27017": {
61+
"type": "Unknown"
62+
}
63+
},
64+
"topologyType": "ReplicaSetNoPrimary",
65+
"logicalSessionTimeoutMinutes": null,
66+
"setName": "rs"
67+
}
68+
},
69+
{
70+
"responses": [
71+
[
72+
"a:27017",
73+
{
74+
"ok": 1,
75+
"ismaster": false,
76+
"secondary": true,
77+
"hidden": true,
78+
"hosts": [
79+
"a:27017",
80+
"c:27017"
81+
],
82+
"setName": "rs",
83+
"minWireVersion": 0,
84+
"maxWireVersion": 6
85+
}
86+
]
87+
],
88+
"outcome": {
89+
"servers": {
90+
"a:27017": {
91+
"type": "RSOther",
92+
"setName": "rs"
93+
},
94+
"b:27017": {
95+
"type": "Unknown"
96+
},
97+
"c:27017": {
98+
"type": "Unknown"
99+
}
100+
},
101+
"topologyType": "ReplicaSetNoPrimary",
102+
"logicalSessionTimeoutMinutes": null,
103+
"setName": "rs"
104+
}
105+
},
106+
{
107+
"responses": [
108+
[
109+
"c:27017",
110+
{
111+
"ok": 1,
112+
"ismaster": true,
113+
"hosts": [
114+
"a:27017",
115+
"c:27017"
116+
],
117+
"setName": "rs",
118+
"minWireVersion": 0,
119+
"maxWireVersion": 6
120+
}
121+
]
122+
],
123+
"outcome": {
124+
"servers": {
125+
"a:27017": {
126+
"type": "RSOther",
127+
"setName": "rs"
128+
},
129+
"c:27017": {
130+
"type": "RSPrimary",
131+
"setName": "rs"
132+
}
133+
},
134+
"topologyType": "ReplicaSetWithPrimary",
135+
"logicalSessionTimeoutMinutes": null,
136+
"setName": "rs"
137+
}
138+
}
139+
]
140+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
description: Repeated ismaster response must be processed
2+
3+
uri: "mongodb://a,b/?replicaSet=rs"
4+
5+
phases:
6+
# Phase 1 - a says it's not primary and suggests c may be the primary
7+
- responses:
8+
-
9+
- "a:27017"
10+
- ok: 1
11+
ismaster: false
12+
secondary: true
13+
hidden: true
14+
hosts: ["a:27017", "c:27017"]
15+
setName: "rs"
16+
minWireVersion: 0
17+
maxWireVersion: 6
18+
outcome:
19+
servers:
20+
"a:27017":
21+
type: "RSOther"
22+
setName: "rs"
23+
24+
"b:27017":
25+
type: Unknown
26+
27+
"c:27017":
28+
type: Unknown
29+
topologyType: "ReplicaSetNoPrimary"
30+
logicalSessionTimeoutMinutes: ~
31+
setName: "rs"
32+
33+
# Phase 2 - c says it's a standalone, is removed
34+
- responses:
35+
-
36+
- "c:27017"
37+
- ok: 1
38+
ismaster: true
39+
minWireVersion: 0
40+
maxWireVersion: 6
41+
outcome:
42+
servers:
43+
"a:27017":
44+
type: "RSOther"
45+
setName: "rs"
46+
47+
"b:27017":
48+
type: Unknown
49+
topologyType: "ReplicaSetNoPrimary"
50+
logicalSessionTimeoutMinutes: ~
51+
setName: "rs"
52+
53+
# Phase 3 - response from a is repeated, and must be processed; c added again
54+
- responses:
55+
-
56+
- "a:27017"
57+
- ok: 1
58+
ismaster: false
59+
secondary: true
60+
hidden: true
61+
hosts: ["a:27017", "c:27017"]
62+
setName: "rs"
63+
minWireVersion: 0
64+
maxWireVersion: 6
65+
outcome:
66+
servers:
67+
"a:27017":
68+
type: "RSOther"
69+
setName: "rs"
70+
71+
"b:27017":
72+
type: Unknown
73+
74+
"c:27017":
75+
type: Unknown
76+
topologyType: "ReplicaSetNoPrimary"
77+
logicalSessionTimeoutMinutes: ~
78+
setName: "rs"
79+
80+
# Phase 4 - c is now a primary
81+
- responses:
82+
-
83+
- "c:27017"
84+
- ok: 1
85+
ismaster: true
86+
hosts: ["a:27017", "c:27017"]
87+
setName: "rs"
88+
minWireVersion: 0
89+
maxWireVersion: 6
90+
outcome:
91+
servers:
92+
"a:27017":
93+
type: "RSOther"
94+
setName: "rs"
95+
96+
"c:27017":
97+
type: RSPrimary
98+
setName: rs
99+
topologyType: "ReplicaSetWithPrimary"
100+
logicalSessionTimeoutMinutes: ~
101+
setName: "rs"

0 commit comments

Comments
 (0)