/* * RHQ Management Platform * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.client.test; import static org.testng.Assert.assertEquals; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.HashSet; import java.util.Hashtable; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.spi.InitialContextFactory; import org.jmock.Expectations; import org.jmock.api.Invocation; import org.jmock.lib.action.CustomAction; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.rhq.bindings.client.RhqManager; import org.rhq.core.domain.auth.Subject; import org.rhq.enterprise.client.LocalClient; import org.rhq.test.JMockTest; /** * * * @author Lukas Krejci */ public class LocalClientTest extends JMockTest { public static class FakeContextFactory implements InitialContextFactory { @Override public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException { return CONTEXT_MOCK_FOR_TEST; } } public static Context CONTEXT_MOCK_FOR_TEST = null; @BeforeClass public void setUpNaming() { System.setProperty(Context.INITIAL_CONTEXT_FACTORY, FakeContextFactory.class.getName()); } /** * Needs to be called from within a test method so that the "context" variable is available. * * @throws NamingException */ private void setupFakeJndiLookup() throws NamingException { CONTEXT_MOCK_FOR_TEST = context.mock(Context.class); context.checking(new Expectations() {{ allowing(CONTEXT_MOCK_FOR_TEST).lookup(with(any(String.class))); will(new CustomAction("Fake JNDI lookup") { @Override public Object invoke(Invocation invocation) throws Throwable { // JNDI name format like: java:global/rhq/rhq-server/SystemManagerBean!org.rhq.enterprise.server.system.SystemManagerLocal String jndiName = (String) invocation.getParameter(0); String beanName = jndiName.substring(0,jndiName.indexOf('!')); beanName = beanName.substring(beanName.lastIndexOf('/') + 1); String managerName = beanName.substring(0, beanName.length() - "Bean".length()); //we basically need to define a mock implementation of both the local and remote //interface here - as if it were a proper SLSB. RhqManager manager = Enum.valueOf(RhqManager.class, managerName); Class<?> remoteIface = manager.remote(); String localIfaceName = remoteIface.getName().substring(0, remoteIface.getName().length() - "Remote".length()) + "Local"; Class<?> localIface = Class.forName(localIfaceName); return Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] { localIface, remoteIface }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } }); } }); allowing(CONTEXT_MOCK_FOR_TEST).close(); }}); } @Test public void testAllManagersInstantiable() throws Exception { setupFakeJndiLookup(); //the list of enabled rhq managers is set at compile time //so far only the TagManager can be disabled for the purposes of this test //take this into account when building the expected array for the assertion HashSet<RhqManager> expected = new HashSet<RhqManager>(Arrays.asList(RhqManager.values())); if (!RhqManager.TagManager.enabled()) { expected.remove(RhqManager.TagManager); } LocalClient lc = new LocalClient(null); assertEquals(lc.getScriptingAPI().keySet(), expected, "Scripting API contains different managers than expected."); } @Test public void testResilienceAgainstContextClassloaders() throws Exception { setupFakeJndiLookup(); ClassLoader origCl = Thread.currentThread().getContextClassLoader(); try { ClassLoader differentCl = new URLClassLoader(new URL[0], getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(differentCl); LocalClient lc = new LocalClient(null); //this call creates the proxy and is theoretically prone to the context classloader Object am = lc.getScriptingAPI().get(RhqManager.AlertManager); //check that only the simplified method exists on the returned object try { am.getClass().getMethod("deleteAlerts", new Class<?>[] { Subject.class, int[].class }); Assert.fail("The original remote interface method should not be available on the scripting API proxy."); } catch (NoSuchMethodException e) { //expected } am.getClass().getMethod("deleteAlerts", new Class<?>[] { int[].class }); } finally { Thread.currentThread().setContextClassLoader(origCl); } } }