/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.activemq.store.jdbc; import java.io.IOException; import java.util.HashMap; import org.apache.activemq.broker.BrokerService; import org.apache.activemq.broker.Locker; import org.apache.activemq.broker.SuppressReplyException; import org.apache.activemq.util.LeaseLockerIOExceptionHandler; import org.apache.activemq.util.ServiceStopper; import org.apache.activemq.util.Wait; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.States; import org.jmock.lib.legacy.ClassImposteriser; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class JDBCIOExceptionHandlerMockeryTest { private static final Logger LOG = LoggerFactory.getLogger(JDBCIOExceptionHandlerMockeryTest.class); private HashMap<Thread, Throwable> exceptions = new HashMap<Thread, Throwable>(); @Test public void testShutdownWithoutTransportRestart() throws Exception { Mockery context = new Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { LOG.error("unexpected exception {} on thread {}", e, t); exceptions.put(t, e); } }); final BrokerService brokerService = context.mock(BrokerService.class); final JDBCPersistenceAdapter jdbcPersistenceAdapter = context.mock(JDBCPersistenceAdapter.class); final Locker locker = context.mock(Locker.class); final States jdbcConn = context.states("jdbc").startsAs("down"); final States broker = context.states("broker").startsAs("started"); // simulate jdbc up between hasLock and checkpoint, so hasLock fails to verify context.checking(new Expectations() {{ allowing(brokerService).isRestartAllowed(); will(returnValue(false)); allowing(brokerService).setSystemExitOnShutdown(with(false)); allowing(brokerService).stopAllConnectors(with(any(ServiceStopper.class))); allowing(brokerService).getPersistenceAdapter(); will(returnValue(jdbcPersistenceAdapter)); allowing(jdbcPersistenceAdapter).getLocker(); will(returnValue(locker)); allowing(locker).keepAlive(); when(jdbcConn.is("down")); will(returnValue(true)); allowing(locker).keepAlive(); when(jdbcConn.is("up")); will(returnValue(false)); allowing(jdbcPersistenceAdapter).checkpoint(with(true)); then(jdbcConn.is("up")); allowing(brokerService).stop(); then(broker.is("stopped")); }}); LeaseLockerIOExceptionHandler underTest = new LeaseLockerIOExceptionHandler(); underTest.setBrokerService(brokerService); try { underTest.handle(new IOException()); fail("except suppress reply ex"); } catch (SuppressReplyException expected) { } assertTrue("broker stopped state triggered", Wait.waitFor(new Wait.Condition() { @Override public boolean isSatisified() throws Exception { LOG.info("broker state {}", broker); return broker.is("stopped").isActive(); } })); context.assertIsSatisfied(); assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); } }