/*
* Copyright (c) 2016 Couchbase, 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.couchbase.client.core.node.locate;
import com.couchbase.client.core.ServiceNotAvailableException;
import com.couchbase.client.core.config.ClusterConfig;
import com.couchbase.client.core.config.CouchbaseBucketConfig;
import com.couchbase.client.core.config.MemcachedBucketConfig;
import com.couchbase.client.core.message.CouchbaseRequest;
import com.couchbase.client.core.message.CouchbaseResponse;
import com.couchbase.client.core.message.view.ViewQueryRequest;
import com.couchbase.client.core.node.Node;
import com.couchbase.client.core.service.ServiceType;
import org.junit.Test;
import rx.observers.TestSubscriber;
import rx.subjects.AsyncSubject;
import rx.subjects.Subject;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Verifies the functionality of the {@link ViewLocator}.
*
* @author Michael Nitschinger
* @since 1.0.2
*/
public class ViewLocatorTest {
@Test
public void shouldSelectNextNode() throws Exception {
Locator locator = new ViewLocator();
ViewQueryRequest request = mock(ViewQueryRequest.class);
when(request.bucket()).thenReturn("default");
ClusterConfig configMock = mock(ClusterConfig.class);
CouchbaseBucketConfig bucketConfigMock = mock(CouchbaseBucketConfig.class);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(any(InetAddress.class))).thenReturn(true);
when(configMock.bucketConfig("default")).thenReturn(bucketConfigMock);
List<Node> nodes = new ArrayList<Node>();
Node node1Mock = mock(Node.class);
when(node1Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.101"));
when(node1Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(true);
Node node2Mock = mock(Node.class);
when(node2Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.102"));
when(node2Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(true);
nodes.addAll(Arrays.asList(node1Mock, node2Mock));
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, times(1)).send(request);
verify(node2Mock, never()).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, times(1)).send(request);
verify(node2Mock, times(1)).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, times(2)).send(request);
verify(node2Mock, times(1)).send(request);
}
@Test
public void shouldSkipNodeWithoutPartition() throws Exception {
Locator locator = new ViewLocator();
ViewQueryRequest request = mock(ViewQueryRequest.class);
when(request.bucket()).thenReturn("default");
ClusterConfig configMock = mock(ClusterConfig.class);
CouchbaseBucketConfig bucketConfigMock = mock(CouchbaseBucketConfig.class);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.101"))).thenReturn(false);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.102"))).thenReturn(true);
when(configMock.bucketConfig("default")).thenReturn(bucketConfigMock);
List<Node> nodes = new ArrayList<Node>();
Node node1Mock = mock(Node.class);
when(node1Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.101"));
when(node1Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(true);
Node node2Mock = mock(Node.class);
when(node2Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.102"));
when(node2Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(true);
nodes.addAll(Arrays.asList(node1Mock, node2Mock));
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, never()).send(request);
verify(node2Mock, times(1)).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, never()).send(request);
verify(node2Mock, times(2)).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, never()).send(request);
verify(node2Mock, times(3)).send(request);
}
@Test
public void shouldSkipNodeWithoutServiceEnabled() throws Exception {
Locator locator = new ViewLocator();
ViewQueryRequest request = mock(ViewQueryRequest.class);
when(request.bucket()).thenReturn("default");
ClusterConfig configMock = mock(ClusterConfig.class);
CouchbaseBucketConfig bucketConfigMock = mock(CouchbaseBucketConfig.class);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.101"))).thenReturn(true);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.102"))).thenReturn(false);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.103"))).thenReturn(true);
when(configMock.bucketConfig("default")).thenReturn(bucketConfigMock);
List<Node> nodes = new ArrayList<Node>();
Node node1Mock = mock(Node.class);
when(node1Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.101"));
when(node1Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(true);
Node node2Mock = mock(Node.class);
when(node2Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.102"));
when(node2Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(false);
Node node3Mock = mock(Node.class);
when(node3Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.103"));
when(node3Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(true);
nodes.addAll(Arrays.asList(node1Mock, node2Mock, node3Mock));
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, times(1)).send(request);
verify(node2Mock, never()).send(request);
verify(node3Mock, never()).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, times(1)).send(request);
verify(node2Mock, never()).send(request);
verify(node3Mock, times(1)).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, times(2)).send(request);
verify(node2Mock, never()).send(request);
verify(node3Mock, times(1)).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, times(2)).send(request);
verify(node2Mock, never()).send(request);
verify(node3Mock, times(2)).send(request);
}
@Test
public void shouldFailWhenUsedAgainstMemcacheBucket() {
Locator locator = new ViewLocator();
ClusterConfig config = mock(ClusterConfig.class);
when(config.bucketConfig("default")).thenReturn(mock(MemcachedBucketConfig.class));
CouchbaseRequest request = mock(ViewQueryRequest.class);
Subject<CouchbaseResponse, CouchbaseResponse> response = AsyncSubject.create();
when(request.bucket()).thenReturn("default");
when(request.observable()).thenReturn(response);
TestSubscriber<CouchbaseResponse> subscriber = new TestSubscriber<CouchbaseResponse>();
response.subscribe(subscriber);
locator.locateAndDispatch(request, Collections.<Node>emptyList(), config, null, null);
subscriber.awaitTerminalEvent(1, TimeUnit.SECONDS);
List<Throwable> errors = subscriber.getOnErrorEvents();
assertEquals(1, errors.size());
assertTrue(errors.get(0) instanceof ServiceNotAvailableException);
}
@Test
public void shouldDistributeFairlyUnderMDS() throws Exception {
Locator locator = new ViewLocator();
ViewQueryRequest request = mock(ViewQueryRequest.class);
when(request.bucket()).thenReturn("default");
ClusterConfig configMock = mock(ClusterConfig.class);
CouchbaseBucketConfig bucketConfigMock = mock(CouchbaseBucketConfig.class);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.101"))).thenReturn(false);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.102"))).thenReturn(false);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.103"))).thenReturn(true);
when(bucketConfigMock.hasPrimaryPartitionsOnNode(InetAddress.getByName("192.168.56.104"))).thenReturn(true);
when(configMock.bucketConfig("default")).thenReturn(bucketConfigMock);
List<Node> nodes = new ArrayList<Node>();
Node node1Mock = mock(Node.class);
when(node1Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.101"));
when(node1Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(false);
Node node2Mock = mock(Node.class);
when(node2Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.102"));
when(node2Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(false);
Node node3Mock = mock(Node.class);
when(node3Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.103"));
when(node3Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(true);
Node node4Mock = mock(Node.class);
when(node4Mock.hostname()).thenReturn(InetAddress.getByName("192.168.56.104"));
when(node4Mock.serviceEnabled(ServiceType.VIEW)).thenReturn(true);
nodes.addAll(Arrays.asList(node1Mock, node2Mock, node3Mock, node4Mock));
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, never()).send(request);
verify(node2Mock, never()).send(request);
verify(node3Mock, times(1)).send(request);
verify(node4Mock, never()).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, never()).send(request);
verify(node2Mock, never()).send(request);
verify(node3Mock, times(1)).send(request);
verify(node4Mock, times(1)).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, never()).send(request);
verify(node2Mock, never()).send(request);
verify(node3Mock, times(2)).send(request);
verify(node4Mock, times(1)).send(request);
locator.locateAndDispatch(request, nodes, configMock, null, null);
verify(node1Mock, never()).send(request);
verify(node2Mock, never()).send(request);
verify(node3Mock, times(2)).send(request);
verify(node4Mock, times(2)).send(request);
}
}