/** * Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis * * The present code is developed in the scope of the joint LINAGORA - * Université Joseph Fourier - Floralis research program and is designated * as a "Result" pursuant to the terms and conditions of the LINAGORA * - Université Joseph Fourier - Floralis research program. Each copyright * holder of Results enumerated here above fully & independently holds complete * ownership of the complete Intellectual Property rights applicable to the whole * of said Results, and may freely exploit it in any manner which does not infringe * the moral rights of the other copyright holders. * * 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 net.roboconf.messaging.api.reconfigurables; import java.io.IOException; import java.io.PrintStream; import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Logger; import org.junit.Assert; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import net.roboconf.core.internal.tests.TestUtils; import net.roboconf.core.model.beans.Application; import net.roboconf.core.model.beans.ApplicationTemplate; import net.roboconf.messaging.api.AbstractMessageProcessor; import net.roboconf.messaging.api.MessagingConstants; import net.roboconf.messaging.api.business.IAgentClient; import net.roboconf.messaging.api.business.IDmClient; import net.roboconf.messaging.api.extensions.IMessagingClient; import net.roboconf.messaging.api.factory.IMessagingClientFactory; import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry; import net.roboconf.messaging.api.internal.client.test.TestClient; import net.roboconf.messaging.api.internal.jmx.JmxWrapperForMessagingClient; import net.roboconf.messaging.api.jmx.RoboconfMessageQueue; import net.roboconf.messaging.api.messages.Message; import net.roboconf.messaging.api.processors.AbstractMessageProcessorTest.EmptyTestDmMessageProcessor; import net.roboconf.messaging.api.utils.OsgiHelper; /** * @author Vincent Zurczak - Linagora */ public class ReconfigurableClientTest { @Test public void testTerminateClient_1() throws Exception { Logger logger = Logger.getLogger( getClass().getName()); IMessagingClient client = Mockito.mock( IMessagingClient.class ); ReconfigurableClient.terminateClient( client, "", logger ); Mockito.verify( client, Mockito.only()).closeConnection(); } @Test public void testTerminateClient_2() throws Exception { Logger logger = Logger.getLogger( getClass().getName()); JmxWrapperForMessagingClient client = Mockito.mock( JmxWrapperForMessagingClient.class ); ReconfigurableClient.terminateClient( client, "", logger ); Mockito.verify( client ).closeConnection(); Mockito.verify( client ).unregisterService();; Mockito.verifyNoMoreInteractions( client ); } @Test public void testTerminateClient_3() throws Exception { Logger logger = Logger.getLogger( getClass().getName()); JmxWrapperForMessagingClient client = Mockito.mock( JmxWrapperForMessagingClient.class ); Mockito.doThrow( new IOException( "for test" )).when( client ).closeConnection(); ReconfigurableClient.terminateClient( client, "", logger ); Mockito.verify( client ).closeConnection(); Mockito.verify( client ).unregisterService();; Mockito.verifyNoMoreInteractions( client ); } @Test public void testInvalidFactory_dm() throws Exception { // The internal client will be null. // But still, there will be no NPE or other exception. ReconfigurableClientDm client = new ReconfigurableClientDm(); client.switchMessagingType( null ); client.openConnection(); } @Test public void testInvalidFactory_agent() throws Exception { // The internal client will be null. // But still, there will be no NPE or other exception. ReconfigurableClientAgent client = new ReconfigurableClientAgent(); client.setApplicationName( "app" ); client.setScopedInstancePath( "/root" ); client.switchMessagingType( null ); client.openConnection(); } @Test public void testHasValidClient() { ReconfigurableClientAgent client = new ReconfigurableClientAgent(); Assert.assertFalse( client.hasValidClient()); } @Test public void testDm() throws Exception { // The messaging client is never null ReconfigurableClientDm client = new ReconfigurableClientDm(); Assert.assertNotNull( client.getMessagingClient()); // Invoke other method, no matter in which order client.setMessageQueue( new RoboconfMessageQueue()); Assert.assertFalse( client.hasValidClient()); Assert.assertFalse( client.isConnected()); client.deleteMessagingServerArtifacts( new Application( "app", new ApplicationTemplate())); client.propagateAgentTermination( null, null ); } @Test public void testAgent() throws Exception { // The messaging client is never null ReconfigurableClientAgent client = new ReconfigurableClientAgent(); Assert.assertNotNull( client.getMessagingClient()); // Invoke other method, no matter in which order client.setMessageQueue( new RoboconfMessageQueue()); Assert.assertFalse( client.hasValidClient()); Assert.assertFalse( client.isConnected()); } @Test( expected = IllegalArgumentException.class ) public void testAssociateMessageProcessor_exception() { ReconfigurableClientDm client = new ReconfigurableClientDm(); Assert.assertFalse( client.hasValidClient()); EmptyTestDmMessageProcessor processor = new EmptyTestDmMessageProcessor(); try { client.associateMessageProcessor( processor ); } catch( Throwable t ) { Assert.fail( "No exception was expected here" ); } client.associateMessageProcessor( processor ); } @Test public void testSetFactory() throws Exception { // Set a first factory ReconfigurableClientDm client = new ReconfigurableClientDm(); final MessagingClientFactoryRegistry registry1 = new MessagingClientFactoryRegistry(); ConcurrentLinkedQueue<?> listeners1 = TestUtils.getInternalField( registry1, "listeners", ConcurrentLinkedQueue.class ); Assert.assertEquals( 0, listeners1.size()); Assert.assertNull( TestUtils.getInternalField( client, "registry", MessagingClientFactoryRegistry.class )); client.setRegistry( registry1 ); Assert.assertEquals( 1, listeners1.size()); Assert.assertEquals( registry1, TestUtils.getInternalField( client, "registry", MessagingClientFactoryRegistry.class )); // Change the factory final MessagingClientFactoryRegistry registry2 = new MessagingClientFactoryRegistry(); ConcurrentLinkedQueue<?> listeners2 = TestUtils.getInternalField( registry2, "listeners", ConcurrentLinkedQueue.class ); Assert.assertEquals( 0, listeners2.size()); client.setRegistry( registry2 ); Assert.assertEquals( 0, listeners1.size()); Assert.assertEquals( 1, listeners2.size()); Assert.assertEquals( registry2, TestUtils.getInternalField( client, "registry", MessagingClientFactoryRegistry.class )); } @Test public void testRegistryCallbacks() throws Exception { // Instead of creating a messaging client explicitly, we rely // on the registry callbacks. At runtime, this can happen // when we configured the DM or an agent with a messaging type that was not // yet deployed or available in the OSGi registry. ReconfigurableClientDm client = new ReconfigurableClientDm(); MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry(); client.setRegistry( registry ); client.associateMessageProcessor( new AbstractMessageProcessor<IDmClient>( "dummy.messageProcessor" ) { @Override protected void processMessage( final Message message ) { // nothing } }); client.switchMessagingType( "foo" ); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertTrue(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); // Make a new factory appear. DummyMessagingClientFactory factory = new DummyMessagingClientFactory( "foo" ); registry.addMessagingClientFactory( factory ); // Verify a new client was instantiated, with the right type. Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertFalse(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); Object internalClient = TestUtils.getInternalField( (client.getMessagingClient()), "messagingClient", IMessagingClient.class ); Assert.assertEquals( DummyMessagingClient.class, internalClient.getClass()); // Now, remove the factory (e.g. we remove the messaging bundle associated with "foo" ). registry.removeMessagingClientFactory( factory ); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertTrue(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); } @Test public void testFactorySwitchClientDm() throws Exception { // Here, the factories are created BEFORE the registry is // associated with the reconfigurable client. It is a different scenario // than the one covered by #testRegistryCallbacks(). // Create the messaging client factory registry, and register the "foo" and "bar" dummy factories. final MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry(); registry.addMessagingClientFactory( new DummyMessagingClientFactory( "foo" )); registry.addMessagingClientFactory( new DummyMessagingClientFactory( "bar" )); // Create the client DM final ReconfigurableClientDm client = new ReconfigurableClientDm(); client.associateMessageProcessor(new AbstractMessageProcessor<IDmClient>( "dummy.messageProcessor" ) { @Override protected void processMessage( final Message message ) { // nothing } }); client.setRegistry( registry ); client.console = Mockito.mock( PrintStream.class ); // Check initial state. Assert.assertNull( client.getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertTrue(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); Assert.assertSame( registry, client.getRegistry()); // Switch to foo! client.switchMessagingType( "foo" ); Assert.assertEquals( "foo", client.getMessagingType()); Assert.assertEquals( "foo", client.getMessagingClient().getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertFalse(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); Object internalClient = TestUtils.getInternalField( (client.getMessagingClient()), "messagingClient", IMessagingClient.class ); Assert.assertEquals( DummyMessagingClient.class, internalClient.getClass()); // Switch to bar! client.switchMessagingType( "bar" ); Assert.assertEquals( "bar", client.getMessagingType()); Assert.assertEquals( "bar", client.getMessagingClient().getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertFalse(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); internalClient = TestUtils.getInternalField( (client.getMessagingClient()), "messagingClient", IMessagingClient.class ); Assert.assertEquals( DummyMessagingClient.class, internalClient.getClass()); // Switch to null! client.switchMessagingType( null ); Assert.assertNull( client.getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertTrue(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); // No error was output Mockito.verifyNoMoreInteractions( client.console ); } @Test public void testFactorySwitchClientAgent() throws Exception { // Create the messaging client factory registry, and register the "foo" and "bar" dummy factories. final MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry(); registry.addMessagingClientFactory( new DummyMessagingClientFactory( "foo" )); registry.addMessagingClientFactory( new DummyMessagingClientFactory( "bar" )); // Create the client DM final ReconfigurableClientAgent client = new ReconfigurableClientAgent(); client.console = Mockito.mock( PrintStream.class ); client.setApplicationName( "app" ); client.setScopedInstancePath( "/root" ); client.associateMessageProcessor( new AbstractMessageProcessor<IAgentClient>( "dummy.messageProcessor" ) { @Override protected void processMessage( final Message message ) { // nothing } }); client.setRegistry(registry); // Check initial state. Assert.assertNull( client.getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertTrue(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); Assert.assertSame( registry, client.getRegistry()); // Switch to foo! client.switchMessagingType( "foo" ); Assert.assertEquals( "foo", client.getMessagingType()); Assert.assertEquals( "foo", client.getMessagingClient().getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertFalse(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); Object internalClient = TestUtils.getInternalField( (client.getMessagingClient()), "messagingClient", IMessagingClient.class ); Assert.assertEquals( DummyMessagingClient.class, internalClient.getClass()); // Switch to bar! client.switchMessagingType( "bar" ); Assert.assertEquals( "bar", client.getMessagingType()); Assert.assertEquals( "bar", client.getMessagingClient().getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertFalse(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); internalClient = TestUtils.getInternalField( (client.getMessagingClient()), "messagingClient", IMessagingClient.class ); Assert.assertEquals( DummyMessagingClient.class, internalClient.getClass()); Assert.assertEquals( MessagingConstants.FACTORY_TEST, client.getConfiguration().get( MessagingConstants.MESSAGING_TYPE_PROPERTY )); // Switch to null! client.switchMessagingType( null ); Assert.assertNull( client.getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertEquals( 0, client.getConfiguration().size()); // No error was output Mockito.verifyNoMoreInteractions( client.console ); } @Test public void testFactorySwitch_connectionError() throws Exception { // Two things to check here: // - There must always be a wrapper client. // - An error must be output in the console. final MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry(); registry.addMessagingClientFactory( new DummyMessagingClientFactory( "foo" ) { @Override public IMessagingClient createClient( ReconfigurableClient<?> parent ) { return new DummyMessagingClient(this.type) { @Override public void openConnection() throws IOException { throw new IOException( "for test" ); } }; } }); // Create the client DM final ReconfigurableClientDm client = new ReconfigurableClientDm(); client.associateMessageProcessor(new AbstractMessageProcessor<IDmClient>( "dummy.messageProcessor" ) { @Override protected void processMessage( final Message message ) { // nothing } }); client.setRegistry( registry ); client.console = Mockito.mock( PrintStream.class ); // Switch to foo! client.switchMessagingType( "foo" ); Assert.assertEquals( "foo", client.getMessagingType()); Assert.assertEquals( "foo", client.getMessagingClient().getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertFalse(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); ArgumentCaptor<String> errorMsgCapture = ArgumentCaptor.forClass( String.class ); Mockito.verify( client.console, Mockito.only()).println( errorMsgCapture.capture()); Assert.assertTrue( errorMsgCapture.getValue().startsWith( "\n\n**** WARNING ****\n" )); // Switch to null! Mockito.reset( client.console ); client.switchMessagingType( null ); Assert.assertNull( client.getMessagingType()); Assert.assertEquals( JmxWrapperForMessagingClient.class, client.getMessagingClient().getClass()); Assert.assertTrue(((JmxWrapperForMessagingClient) client.getMessagingClient()).isDismissClient()); Mockito.verifyNoMoreInteractions( client.console ); } @Test public void testLookupMessagingClientFactoryRegistryService_noReference() { BundleContext bundleCtx = Mockito.mock( BundleContext.class ); OsgiHelper osgiHelper = Mockito.mock( OsgiHelper.class ); Mockito.when( osgiHelper.findBundleContext()).thenReturn( bundleCtx ); MessagingClientFactoryRegistry registry = ReconfigurableClient.lookupMessagingClientFactoryRegistryService( osgiHelper ); Assert.assertNull( registry ); } @Test @SuppressWarnings( "unchecked" ) public void testLookupMessagingClientFactoryRegistryService_withReference() { BundleContext bundleCtx = Mockito.mock( BundleContext.class ); OsgiHelper osgiHelper = Mockito.mock( OsgiHelper.class ); Mockito.when( osgiHelper.findBundleContext()).thenReturn( bundleCtx ); ServiceReference<MessagingClientFactoryRegistry> reference = Mockito.mock( ServiceReference.class ); Mockito.when( bundleCtx.getServiceReference( MessagingClientFactoryRegistry.class )).thenReturn( reference ); MessagingClientFactoryRegistry registryMock = Mockito.mock( MessagingClientFactoryRegistry.class ); Mockito.when( bundleCtx.getService( reference )).thenReturn( registryMock ); MessagingClientFactoryRegistry registry = ReconfigurableClient.lookupMessagingClientFactoryRegistryService( osgiHelper ); Assert.assertNotNull( registry ); Assert.assertEquals( registryMock, registry ); } /** * A stupid messaging client. */ private static class DummyMessagingClientFactory implements IMessagingClientFactory { /** * The type of the messaging factory. */ final String type; /** * Constructor. * @param type the type of the messaging factory. */ DummyMessagingClientFactory( final String type ) { this.type = type; } @Override public String getType() { return this.type; } @Override public IMessagingClient createClient( ReconfigurableClient<?> parent ) { return new DummyMessagingClient(this.type); } @Override public boolean setConfiguration( final Map<String, String> configuration ) { return this.type.equals(configuration.get(MessagingConstants.MESSAGING_TYPE_PROPERTY)); } } /** * A dummy DM messaging client. */ private static class DummyMessagingClient extends TestClient { /** * The type of the messaging client. */ final String type; /** * Constructor. * @param type the type of the messaging client. */ DummyMessagingClient( final String type ) { this.type = type; } @Override public String getMessagingType() { return this.type; } } }