Skip to content

Commit 7addf8d

Browse files
committed
JAVA-2611: Lookup SRV and TXT records in DNS when connection string protocol is mongodb+srv
Default ssl to true for this protocol, and restrict TXT record to only authSource and replicaSet options
1 parent 722b41c commit 7addf8d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2296
-1297
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
* Copyright 2017 MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.async.client;
18+
19+
import com.mongodb.ConnectionString;
20+
import com.mongodb.MongoClientException;
21+
import com.mongodb.ServerAddress;
22+
import com.mongodb.async.SingleResultCallback;
23+
import com.mongodb.connection.ClusterSettings;
24+
import com.mongodb.connection.ServerDescription;
25+
import com.mongodb.connection.SslSettings;
26+
import com.mongodb.event.ClusterClosedEvent;
27+
import com.mongodb.event.ClusterDescriptionChangedEvent;
28+
import com.mongodb.event.ClusterListener;
29+
import com.mongodb.event.ClusterOpeningEvent;
30+
import org.bson.BsonArray;
31+
import org.bson.BsonBoolean;
32+
import org.bson.BsonDocument;
33+
import org.bson.BsonValue;
34+
import org.bson.Document;
35+
import org.junit.Test;
36+
import org.junit.runner.RunWith;
37+
import org.junit.runners.Parameterized;
38+
import util.JsonPoweredTestHelper;
39+
40+
import java.io.File;
41+
import java.io.IOException;
42+
import java.net.URISyntaxException;
43+
import java.util.ArrayList;
44+
import java.util.Collection;
45+
import java.util.List;
46+
import java.util.Map;
47+
import java.util.concurrent.CountDownLatch;
48+
import java.util.concurrent.TimeUnit;
49+
50+
import static com.mongodb.ClusterFixture.getSslSettings;
51+
import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet;
52+
import static org.junit.Assert.assertEquals;
53+
import static org.junit.Assert.assertTrue;
54+
import static org.junit.Assert.fail;
55+
import static org.junit.Assume.assumeTrue;
56+
57+
// See https://github.com/mongodb/specifications/tree/master/source/initial-dns-seedlist-discovery/tests
58+
@RunWith(Parameterized.class)
59+
public class InitialDnsSeedlistDiscoveryTest {
60+
61+
private final String filename;
62+
private final String uri;
63+
private final List<String> seeds;
64+
private final List<ServerAddress> hosts;
65+
private final boolean isError;
66+
private final BsonDocument options;
67+
68+
public InitialDnsSeedlistDiscoveryTest(final String filename, final String uri, final List<String> seeds,
69+
final List<ServerAddress> hosts, final boolean isError, final BsonDocument options) {
70+
this.filename = filename;
71+
this.uri = uri;
72+
this.seeds = seeds;
73+
this.hosts = hosts;
74+
this.isError = isError;
75+
this.options = options;
76+
}
77+
78+
@Test
79+
public void shouldResolve() {
80+
81+
if (isError) {
82+
try {
83+
new ConnectionString(this.uri);
84+
fail();
85+
} catch (IllegalArgumentException e) {
86+
// all good
87+
} catch (MongoClientException e) {
88+
// all good
89+
}
90+
} else {
91+
ConnectionString connectionString = new ConnectionString(this.uri);
92+
93+
assertEquals(seeds.size(), connectionString.getHosts().size());
94+
assertTrue(connectionString.getHosts().containsAll(seeds));
95+
96+
for (Map.Entry<String, BsonValue> entry : options.entrySet()) {
97+
if (entry.getKey().equals("replicaSet")) {
98+
assertEquals(entry.getValue().asString().getValue(), connectionString.getRequiredReplicaSetName());
99+
} else if (entry.getKey().equals("ssl")) {
100+
assertEquals(entry.getValue().asBoolean().getValue(), connectionString.getSslEnabled());
101+
} else if (entry.getKey().equals("authSource")) {
102+
// ignoring authSource for now, because without at least a userName also in the connection string,
103+
// the authSource is ignored. If the test gets this far, at least we know that a TXT record
104+
// containing in authSource doesn't blow up. We just don't test that it's actually used.
105+
assertTrue(true);
106+
} else {
107+
throw new UnsupportedOperationException("No support configured yet for " + entry.getKey());
108+
}
109+
}
110+
}
111+
}
112+
113+
@Test
114+
public void shouldDiscover() throws InterruptedException {
115+
if (seeds.isEmpty()) {
116+
return;
117+
}
118+
final CountDownLatch latch = new CountDownLatch(1);
119+
120+
ConnectionString connectionString = new ConnectionString(uri);
121+
122+
SslSettings sslSettings = getSslSettings(connectionString);
123+
124+
assumeTrue(isDiscoverableReplicaSet() && getSslSettings().isEnabled() == sslSettings.isEnabled());
125+
126+
MongoClientSettings settings = MongoClientSettings
127+
.builder()
128+
.clusterSettings(ClusterSettings.builder()
129+
.applyConnectionString(connectionString)
130+
.addClusterListener(new ClusterListener() {
131+
@Override
132+
public void clusterOpening(final ClusterOpeningEvent event) {
133+
}
134+
135+
@Override
136+
public void clusterClosed(final ClusterClosedEvent event) {
137+
}
138+
139+
@Override
140+
public void clusterDescriptionChanged(final ClusterDescriptionChangedEvent event) {
141+
List<ServerAddress> curHostList = new ArrayList<ServerAddress>();
142+
for (ServerDescription cur : event.getNewDescription().getServerDescriptions()) {
143+
if (cur.isOk()) {
144+
curHostList.add(cur.getAddress());
145+
}
146+
}
147+
if (hosts.size() == curHostList.size() && curHostList.containsAll(hosts)) {
148+
latch.countDown();
149+
}
150+
151+
}
152+
}).build())
153+
.sslSettings(sslSettings)
154+
.build();
155+
156+
MongoClient client = MongoClients.create(settings);
157+
158+
try {
159+
assertTrue(latch.await(5, TimeUnit.SECONDS));
160+
161+
final CountDownLatch pingLatch = new CountDownLatch(1);
162+
client.getDatabase("admin").runCommand(new Document("ping", 1), new SingleResultCallback<Document>() {
163+
@Override
164+
public void onResult(final Document result, final Throwable t) {
165+
if (t == null) {
166+
pingLatch.countDown();
167+
}
168+
}
169+
});
170+
171+
assertTrue(pingLatch.await(5, TimeUnit.SECONDS));
172+
} finally {
173+
client.close();
174+
}
175+
}
176+
177+
@Parameterized.Parameters(name = "{0}")
178+
public static Collection<Object[]> data() throws URISyntaxException, IOException {
179+
List<Object[]> data = new ArrayList<Object[]>();
180+
for (File file : JsonPoweredTestHelper.getTestFiles("/initial-dns-seedlist-discovery")) {
181+
BsonDocument testDocument = JsonPoweredTestHelper.getTestDocument(file);
182+
data.add(new Object[]{
183+
file.getName(),
184+
testDocument.getString("uri").getValue(),
185+
toStringList(testDocument.getArray("seeds")),
186+
toServerAddressList(testDocument.getArray("hosts")),
187+
testDocument.getBoolean("error", BsonBoolean.FALSE).getValue(),
188+
testDocument.getDocument("options", new BsonDocument())
189+
});
190+
191+
}
192+
return data;
193+
}
194+
195+
private static List<String> toStringList(final BsonArray bsonArray) {
196+
List<String> retVal = new ArrayList<String>(bsonArray.size());
197+
for (BsonValue cur : bsonArray) {
198+
retVal.add(cur.asString().getValue());
199+
}
200+
return retVal;
201+
}
202+
203+
private static List<ServerAddress> toServerAddressList(final BsonArray bsonArray) {
204+
List<ServerAddress> retVal = new ArrayList<ServerAddress>(bsonArray.size());
205+
for (BsonValue cur : bsonArray) {
206+
retVal.add(new ServerAddress(cur.asString().getValue()));
207+
}
208+
return retVal;
209+
}
210+
}

0 commit comments

Comments
 (0)