/* * 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; import com.couchbase.client.core.RequestCancelledException; import com.couchbase.client.core.env.CoreEnvironment; import com.couchbase.client.core.env.DefaultCoreEnvironment; import com.couchbase.client.core.message.CouchbaseRequest; import com.couchbase.client.core.message.CouchbaseResponse; import com.couchbase.client.core.message.internal.AddServiceRequest; import com.couchbase.client.core.message.internal.RemoveServiceRequest; import com.couchbase.client.core.retry.FailFastRetryStrategy; import com.couchbase.client.core.service.ConfigService; import com.couchbase.client.core.service.KeyValueService; import com.couchbase.client.core.service.Service; import com.couchbase.client.core.service.ServiceType; import com.couchbase.client.core.state.LifecycleState; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import rx.Observable; import rx.subjects.AsyncSubject; import rx.subjects.BehaviorSubject; import java.net.InetAddress; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * Verifies the functionality of a {@link CouchbaseNode}. */ public class CouchbaseNodeTest { private static final CoreEnvironment environment = DefaultCoreEnvironment.create(); private static InetAddress host; @BeforeClass public static void setup() throws Exception { host = InetAddress.getLocalHost(); } @Test public void shouldBeDisconnectedIfNoServicesRegisteredOnConnect() { CouchbaseNode node = new CouchbaseNode(host, environment, null); assertEquals(LifecycleState.DISCONNECTED, node.connect().toBlocking().single()); } @Test public void shouldBeEqualOnSameInetAddr() throws Exception { CouchbaseNode node1 = new CouchbaseNode(InetAddress.getByName("1.2.3.4"), environment, null); CouchbaseNode node2 = new CouchbaseNode(InetAddress.getByName("1.2.3.4"), environment, null); assertEquals(node1, node2); assertEquals(node1.hashCode(), node2.hashCode()); } @Test public void shouldNotBeEqualOnDifferentInetAddr() throws Exception { CouchbaseNode node1 = new CouchbaseNode(InetAddress.getByName("1.2.3.4"), environment, null); CouchbaseNode node2 = new CouchbaseNode(InetAddress.getByName("2.3.4.5"), environment, null); assertNotEquals(node1, node2); } @Test @Ignore public void shouldBeConnectedIfAllServicesConnectedOnConnect() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service service1Mock = mock(Service.class); Service service2Mock = mock(Service.class); when(registryMock.services()).thenReturn(new Service[] {service1Mock, service2Mock}); when(service1Mock.connect()).thenReturn(Observable.just(LifecycleState.CONNECTED)); when(service2Mock.connect()).thenReturn(Observable.just(LifecycleState.CONNECTED)); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); assertEquals(LifecycleState.CONNECTED, node.connect().toBlocking().single()); } @Test @Ignore public void shouldBeDegradedIfAtLeastOneServiceConnectedOnConnect() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service service1Mock = mock(Service.class); Service service2Mock = mock(Service.class); when(registryMock.services()).thenReturn(new Service[] {service1Mock, service2Mock}); when(service1Mock.connect()).thenReturn(Observable.just(LifecycleState.CONNECTED)); when(service2Mock.connect()).thenReturn(Observable.just(LifecycleState.CONNECTING)); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); assertEquals(LifecycleState.DEGRADED, node.connect().toBlocking().single()); } @Test @Ignore public void shouldBeConnectingIfAtLeastOneServiceConnectingOnConnect() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service service1Mock = mock(Service.class); Service service2Mock = mock(Service.class); when(registryMock.services()).thenReturn(new Service[] {service1Mock, service2Mock}); when(service1Mock.connect()).thenReturn(Observable.just(LifecycleState.DISCONNECTED)); when(service2Mock.connect()).thenReturn(Observable.just(LifecycleState.CONNECTING)); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); assertEquals(LifecycleState.CONNECTING, node.connect().toBlocking().single()); } @Test public void shouldBeDisconnectedIfNoServiceConnectingOnConnect() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service service1Mock = mock(Service.class); Service service2Mock = mock(Service.class); when(registryMock.services()).thenReturn(new Service[] {service1Mock, service2Mock}); when(service1Mock.connect()).thenReturn(Observable.just(LifecycleState.DISCONNECTED)); when(service2Mock.connect()).thenReturn(Observable.just(LifecycleState.DISCONNECTED)); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); assertEquals(LifecycleState.DISCONNECTED, node.connect().toBlocking().single()); } @Test @Ignore public void shouldBeDisconnectingIfServicesDisconnectingOnDisconnect() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service service1Mock = mock(Service.class); Service service2Mock = mock(Service.class); when(registryMock.services()).thenReturn(new Service[] {service1Mock, service2Mock}); when(service1Mock.disconnect()).thenReturn(Observable.just(LifecycleState.DISCONNECTING)); when(service2Mock.disconnect()).thenReturn(Observable.just(LifecycleState.DISCONNECTED)); BehaviorSubject<LifecycleState> states1 = BehaviorSubject.create(); BehaviorSubject<LifecycleState> states2 = BehaviorSubject.create(); when(service1Mock.states()).thenReturn(states1); when(service2Mock.states()).thenReturn(states2); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); Observable<LifecycleState> disconnect = node.disconnect(); states1.onNext(LifecycleState.DISCONNECTING); states2.onNext(LifecycleState.DISCONNECTED); assertEquals(LifecycleState.DISCONNECTING, disconnect.toBlocking().single()); } @Test public void shouldBeDisconnectedIfServicesDisconnectedOnDisconnect() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service service1Mock = mock(Service.class); Service service2Mock = mock(Service.class); when(registryMock.services()).thenReturn(new Service[] {service1Mock, service2Mock}); when(service1Mock.disconnect()).thenReturn(Observable.just(LifecycleState.DISCONNECTED)); when(service2Mock.disconnect()).thenReturn(Observable.just(LifecycleState.DISCONNECTED)); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); assertEquals(LifecycleState.DISCONNECTED, node.disconnect().toBlocking().single()); } @Test public void shouldRegisterGlobalService() { ServiceRegistry registryMock = mock(ServiceRegistry.class); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); Service registered = node.addService(new AddServiceRequest(ServiceType.CONFIG, null, null, 0, host)) .toBlocking().single(); verify(registryMock).addService(any(ConfigService.class), anyString()); assertEquals(ServiceType.CONFIG, registered.type()); } @Test public void shouldRegisterLocalService() { ServiceRegistry registryMock = mock(ServiceRegistry.class); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); Service registered = node.addService(new AddServiceRequest(ServiceType.BINARY, "bucket", null, 0, host)) .toBlocking().single(); verify(registryMock).addService(any(KeyValueService.class), anyString()); assertEquals(ServiceType.BINARY, registered.type()); } @Test public void shouldRemoveGlobalService() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service serviceMock = mock(Service.class); when(serviceMock.type()).thenReturn(ServiceType.CONFIG); when(registryMock.serviceBy(ServiceType.CONFIG, null)).thenReturn(serviceMock); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); node.removeService(new RemoveServiceRequest(ServiceType.CONFIG, null, host)) .toBlocking().single(); verify(registryMock).removeService(any(Service.class), anyString()); } @Test public void shouldRemoveLocalService() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service serviceMock = mock(Service.class); when(serviceMock.type()).thenReturn(ServiceType.BINARY); when(registryMock.serviceBy(ServiceType.BINARY, "bucket")).thenReturn(serviceMock); when(serviceMock.states()).thenReturn(Observable.<LifecycleState>empty()); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); node.removeService(new RemoveServiceRequest(ServiceType.BINARY, "bucket", host)) .toBlocking().single(); verify(registryMock).removeService(any(Service.class), anyString()); } @Test(expected = RequestCancelledException.class) public void shouldCancelIfServiceCouldNotBeLocated() { ServiceRegistry registryMock = mock(ServiceRegistry.class); Service serviceMock = mock(Service.class); when(registryMock.serviceBy(ServiceType.BINARY, "bucket")).thenReturn(serviceMock); when(serviceMock.states()).thenReturn(Observable.<LifecycleState>empty()); CoreEnvironment env = mock(CoreEnvironment.class); when(env.retryStrategy()).thenReturn(FailFastRetryStrategy.INSTANCE); CouchbaseNode node = new CouchbaseNode(host, registryMock, env, null); CouchbaseRequest request = mock(CouchbaseRequest.class); AsyncSubject<CouchbaseResponse> response = AsyncSubject.create(); when(request.observable()).thenReturn(response); node.send(request); response.toBlocking().single(); } @Test public void shouldCacheEnabledServices() { ServiceRegistry registryMock = mock(ServiceRegistry.class); CouchbaseNode node = new CouchbaseNode(host, registryMock, environment, null); assertFalse(node.serviceEnabled(ServiceType.BINARY)); assertFalse(node.serviceEnabled(ServiceType.CONFIG)); assertFalse(node.serviceEnabled(ServiceType.QUERY)); node.addService(new AddServiceRequest(ServiceType.BINARY, "bucket", null, 0, host)) .toBlocking().single(); assertTrue(node.serviceEnabled(ServiceType.BINARY)); assertFalse(node.serviceEnabled(ServiceType.CONFIG)); assertFalse(node.serviceEnabled(ServiceType.QUERY)); node.addService(new AddServiceRequest(ServiceType.CONFIG, null, null, 0, host)) .toBlocking().single(); assertTrue(node.serviceEnabled(ServiceType.BINARY)); assertTrue(node.serviceEnabled(ServiceType.CONFIG)); assertFalse(node.serviceEnabled(ServiceType.QUERY)); // Pretend services are properly stored in the registry before removal Service binaryServiceMock = mock(Service.class); when(binaryServiceMock.type()).thenReturn(ServiceType.BINARY); when(registryMock.serviceBy(ServiceType.BINARY, "bucket")).thenReturn(binaryServiceMock); Service configServiceMock = mock(Service.class); when(configServiceMock.type()).thenReturn(ServiceType.CONFIG); when(registryMock.serviceBy(ServiceType.CONFIG, null)).thenReturn(configServiceMock); node.removeService(new RemoveServiceRequest(ServiceType.BINARY, "bucket", host)) .toBlocking().single(); assertFalse(node.serviceEnabled(ServiceType.BINARY)); assertTrue(node.serviceEnabled(ServiceType.CONFIG)); assertFalse(node.serviceEnabled(ServiceType.QUERY)); node.removeService(new RemoveServiceRequest(ServiceType.CONFIG, null, host)) .toBlocking().single(); assertFalse(node.serviceEnabled(ServiceType.BINARY)); assertFalse(node.serviceEnabled(ServiceType.CONFIG)); assertFalse(node.serviceEnabled(ServiceType.QUERY)); } }