/*
* Copyright 2016 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.
*
*/
package com.mongodb.connection;
import com.mongodb.ServerAddress;
import com.mongodb.event.ClusterDescriptionChangedEvent;
import com.mongodb.event.ClusterOpeningEvent;
import com.mongodb.event.ServerClosedEvent;
import com.mongodb.event.ServerDescriptionChangedEvent;
import com.mongodb.event.ServerListener;
import com.mongodb.event.ServerOpeningEvent;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonValue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.mongodb.connection.ServerConnectionState.CONNECTED;
import static com.mongodb.connection.ServerConnectionState.CONNECTING;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
// See https://github.com/mongodb/specifications/tree/master/source/...
@RunWith(Parameterized.class)
public class ServerDiscoveryAndMonitoringMonitoringTest extends AbstractServerDiscoveryAndMonitoringTest {
private final TestClusterListener clusterListener = new TestClusterListener();
private final TestServerListenerFactory serverListenerFactory = new TestServerListenerFactory();
public ServerDiscoveryAndMonitoringMonitoringTest(final String description, final BsonDocument definition) {
super(definition);
init(serverListenerFactory, clusterListener);
}
@Test
public void shouldPassAllOutcomes() {
for (BsonValue phase : getDefinition().getArray("phases")) {
for (BsonValue response : phase.asDocument().getArray("responses")) {
applyResponse(response.asArray());
}
BsonDocument outcome = phase.asDocument().getDocument("outcome");
assertEvents(outcome.getArray("events"));
}
}
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> data() throws URISyntaxException, IOException {
return data("/server-discovery-and-monitoring-monitoring");
}
private void assertEvents(final BsonArray events) {
Iterator<ClusterDescriptionChangedEvent> clusterDescriptionChangedEventIterator =
clusterListener.getClusterDescriptionChangedEvents().iterator();
for (BsonValue eventValue : events) {
BsonDocument eventDocument = eventValue.asDocument();
if (eventDocument.containsKey("topology_opening_event")) {
ClusterOpeningEvent event = clusterListener.getClusterOpeningEvent();
assertNotNull("event", event);
assertEquals("clusterId", getCluster().getClusterId(), event.getClusterId());
} else if (eventDocument.containsKey("topology_description_changed_event")) {
ClusterDescriptionChangedEvent event = clusterDescriptionChangedEventIterator.next();
assertNotNull("event", event);
assertEquals(getCluster().getClusterId(), event.getClusterId());
BsonDocument topologyDescriptionChangedEventDocument = eventDocument.getDocument("topology_description_changed_event");
assertEqualClusterDescriptions(createClusterDescriptionFromClusterDescriptionDocument(
topologyDescriptionChangedEventDocument.getDocument("previousDescription")),
event.getPreviousDescription());
BsonDocument newDescription = topologyDescriptionChangedEventDocument.getDocument("newDescription");
assertEqualClusterDescriptions(createClusterDescriptionFromClusterDescriptionDocument(newDescription),
event.getNewDescription());
if (newDescription.getString("topologyType").getValue().equals("Single")) {
assertEquals(SingleServerCluster.class, getCluster().getClass());
} else {
assertEquals(MultiServerCluster.class, getCluster().getClass());
}
} else if (eventDocument.containsKey("server_opening_event")) {
BsonDocument serverOpeningEventDocument = eventDocument.getDocument("server_opening_event");
ServerAddress serverAddress = new ServerAddress(serverOpeningEventDocument.getString("address").getValue());
TestServerListener serverListener = serverListenerFactory.getListener(serverAddress);
assertNotNull("serverListener", serverListener);
ServerOpeningEvent event = serverListener.getServerOpeningEvent();
assertNotNull("event", event);
assertEquals("serverId", new ServerId(getCluster().getClusterId(), serverAddress), event.getServerId());
} else if (eventDocument.containsKey("server_closed_event")) {
BsonDocument serverClosedEventDocument = eventDocument.getDocument("server_closed_event");
ServerAddress serverAddress = new ServerAddress(serverClosedEventDocument.getString("address").getValue());
TestServerListener serverListener = serverListenerFactory.getListener(serverAddress);
assertNotNull("serverListener", serverListener);
ServerClosedEvent event = serverListener.getServerClosedEvent();
assertNotNull("event", event);
assertEquals("serverId", new ServerId(getCluster().getClusterId(), serverAddress), event.getServerId());
} else if (eventDocument.containsKey("server_description_changed_event")) {
BsonDocument serverDescriptionChangedEventDocument = eventDocument.getDocument("server_description_changed_event");
ServerAddress serverAddress = new ServerAddress(serverDescriptionChangedEventDocument.getString("address").getValue());
TestServerListener serverListener = serverListenerFactory.getListener(serverAddress);
assertNotNull("serverListener", serverListener);
assertEquals("serverDescriptionChangedEvents size", 1, serverListener.getServerDescriptionChangedEvents().size());
ServerDescriptionChangedEvent event = serverListener.getServerDescriptionChangedEvents().get(0);
assertNotNull("event", event);
assertEquals("serverId", new ServerId(getCluster().getClusterId(), serverAddress), event.getServerId());
assertEqualServerDescriptions(createServerDescriptionFromServerDescriptionDocument(serverDescriptionChangedEventDocument
.getDocument("previousDescription")),
event.getPreviousDescription());
assertEqualServerDescriptions(createServerDescriptionFromServerDescriptionDocument(serverDescriptionChangedEventDocument
.getDocument("newDescription")),
event.getNewDescription());
} else {
throw new IllegalArgumentException("Unsupported event type: " + eventDocument.keySet().iterator().next());
}
}
assertFalse(clusterDescriptionChangedEventIterator.hasNext());
}
private void assertEqualClusterDescriptions(final ClusterDescription expected, final ClusterDescription actual) {
assertEquals(expected.getType(), actual.getType());
assertEquals(expected.getServerDescriptions().size(), actual.getServerDescriptions().size());
for (ServerDescription curExpected: expected.getServerDescriptions()) {
ServerDescription curActual = getByServerAddress(curExpected.getAddress(), actual.getServerDescriptions());
assertNotNull(curActual);
assertEqualServerDescriptions(curExpected, curActual);
}
}
private ServerDescription getByServerAddress(final ServerAddress serverAddress, final List<ServerDescription> serverDescriptions) {
for (ServerDescription cur: serverDescriptions) {
if (cur.getAddress().equals(serverAddress)) {
return cur;
}
}
return null;
}
private void assertEqualServerDescriptions(final ServerDescription expected, final ServerDescription actual) {
assertEquals("address", expected.getAddress(), actual.getAddress());
assertEquals("ok", expected.isOk(), actual.isOk());
assertEquals("type", expected.getType(), actual.getType());
assertEquals("state", expected.getState(), actual.getState());
assertEquals("setName", expected.getSetName(), actual.getSetName());
assertEquals("primary", expected.getPrimary(), actual.getPrimary());
assertEquals("hosts", expected.getHosts(), actual.getHosts());
assertEquals("arbiters", expected.getArbiters(), actual.getArbiters());
assertEquals("passives", expected.getPassives(), actual.getPassives());
}
private ClusterDescription createClusterDescriptionFromClusterDescriptionDocument(final BsonDocument clusterDescriptionDocument) {
List<ServerDescription> serverDescriptions = new ArrayList<ServerDescription>();
for (BsonValue cur : clusterDescriptionDocument.getArray("servers")) {
serverDescriptions.add(createServerDescriptionFromServerDescriptionDocument(cur.asDocument()));
}
return new ClusterDescription(getCluster().getSettings().getMode(),
getClusterType(clusterDescriptionDocument.getString("topologyType").getValue(), serverDescriptions),
serverDescriptions);
}
private ServerDescription createServerDescriptionFromServerDescriptionDocument(final BsonDocument serverDescriptionDocument) {
ServerType serverType = getServerType(serverDescriptionDocument.getString("type").getValue());
return ServerDescription.builder()
.address(new ServerAddress(serverDescriptionDocument.getString("address").getValue()))
.ok(serverType == ServerType.UNKNOWN ? false : true)
.state(serverType == ServerType.UNKNOWN ? CONNECTING : CONNECTED)
.type(serverType)
.setName(serverDescriptionDocument.containsKey("setName")
? serverDescriptionDocument.getString("setName").getValue()
: null)
.primary(serverDescriptionDocument.containsKey("primary")
? serverDescriptionDocument.getString("primary").getValue() : null)
.hosts(getHostNamesSet(serverDescriptionDocument, "hosts"))
.arbiters(getHostNamesSet(serverDescriptionDocument, "arbiters"))
.passives(getHostNamesSet(serverDescriptionDocument, "passives"))
.version(serverType == ServerType.UNKNOWN ? new ServerVersion() : new ServerVersion(2, 6))
.build();
}
private Set<String> getHostNamesSet(final BsonDocument serverDescriptionDocument, final String fieldName) {
Set<String> hostsSet = new HashSet<String>();
for (BsonValue cur : serverDescriptionDocument.getArray(fieldName)) {
hostsSet.add(cur.asString().getValue());
}
return hostsSet;
}
private static class TestServerListenerFactory implements ServerListenerFactory {
private final Map<ServerAddress, TestServerListener> serverAddressServerListenerMap =
new HashMap<ServerAddress, TestServerListener>();
@Override
public ServerListener create(final ServerAddress serverAddress) {
TestServerListener serverListener = new TestServerListener();
serverAddressServerListenerMap.put(serverAddress, serverListener);
return serverListener;
}
TestServerListener getListener(final ServerAddress serverAddress) {
return serverAddressServerListenerMap.get(serverAddress);
}
}
}