blob: 7bee2d68c6d1836c38691034ba8619ddb1a0d394 [file] [log] [blame]
/*
* 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.hadoop.service;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.service.AbstractService;
import org.apache.hadoop.service.LoggingStateChangeListener;
import org.apache.hadoop.service.Service;
import org.apache.hadoop.service.ServiceStateChangeListener;
import org.junit.After;
import org.junit.Test;
/**
* Test global state changes. It is critical for all tests to clean up the
* global listener afterwards to avoid interfering with follow-on tests.
*
* One listener, {@link #listener} is defined which is automatically
* unregistered on cleanup. All other listeners must be unregistered in the
* finally clauses of the tests.
*/
public class TestGlobalStateChangeListener extends ServiceAssert {
BreakableStateChangeListener listener = new BreakableStateChangeListener("listener");
private void register() {
register(listener);
}
private boolean unregister() {
return unregister(listener);
}
private void register(ServiceStateChangeListener l) {
AbstractService.registerGlobalListener(l);
}
private boolean unregister(ServiceStateChangeListener l) {
return AbstractService.unregisterGlobalListener(l);
}
/**
* After every test case reset the list of global listeners.
*/
@After
public void cleanup() {
AbstractService.resetGlobalListeners();
}
/**
* Assert that the last state of the listener is that the test expected.
* @param breakable a breakable listener
* @param state the expected state
*/
public void assertListenerState(BreakableStateChangeListener breakable,
Service.STATE state) {
assertEquals("Wrong state in " + breakable, state, breakable.getLastState());
}
/**
* Assert that the number of state change notifications matches expectations.
* @param breakable the listener
* @param count the expected count.
*/
public void assertListenerEventCount(BreakableStateChangeListener breakable,
int count) {
assertEquals("Wrong event count in " + breakable, count,
breakable.getEventCount());
}
/**
* Test that register/unregister works
*/
@Test
public void testRegisterListener() {
register();
assertTrue("listener not registered", unregister());
}
/**
* Test that double registration results in one registration only.
*/
@Test
public void testRegisterListenerTwice() {
register();
register();
assertTrue("listener not registered", unregister());
//there should be no listener to unregister the second time
assertFalse("listener double registered", unregister());
}
/**
* Test that the {@link BreakableStateChangeListener} is picking up
* the state changes and that its last event field is as expected.
*/
@Test
public void testEventHistory() {
register();
BreakableService service = new BreakableService();
assertListenerState(listener, Service.STATE.NOTINITED);
assertEquals(0, listener.getEventCount());
service.init(new Configuration());
assertListenerState(listener, Service.STATE.INITED);
assertSame(service, listener.getLastService());
assertListenerEventCount(listener, 1);
service.start();
assertListenerState(listener, Service.STATE.STARTED);
assertListenerEventCount(listener, 2);
service.stop();
assertListenerState(listener, Service.STATE.STOPPED);
assertListenerEventCount(listener, 3);
}
/**
* This test triggers a failure in the listener - the expectation is that the
* service has already reached it's desired state, purely because the
* notifications take place afterwards.
*
*/
@Test
public void testListenerFailure() {
listener.setFailingState(Service.STATE.INITED);
register();
BreakableStateChangeListener l2 = new BreakableStateChangeListener();
register(l2);
BreakableService service = new BreakableService();
service.init(new Configuration());
//expected notifications to fail
//still should record its invocation
assertListenerState(listener, Service.STATE.INITED);
assertListenerEventCount(listener, 1);
//and second listener didn't get notified of anything
assertListenerEventCount(l2, 0);
//service should still consider itself started
assertServiceStateInited(service);
service.start();
service.stop();
}
/**
* Create a chain of listeners and set one in the middle to fail; verify that
* those in front got called, and those after did not.
*/
@Test
public void testListenerChain() {
//create and register the listeners
LoggingStateChangeListener logListener = new LoggingStateChangeListener();
register(logListener);
BreakableStateChangeListener l0 = new BreakableStateChangeListener("l0");
register(l0);
listener.setFailingState(Service.STATE.STARTED);
register();
BreakableStateChangeListener l3 = new BreakableStateChangeListener("l3");
register(l3);
//create and init a service.
BreakableService service = new BreakableService();
service.init(new Configuration());
assertServiceStateInited(service);
assertListenerState(l0, Service.STATE.INITED);
assertListenerState(listener, Service.STATE.INITED);
assertListenerState(l3, Service.STATE.INITED);
service.start();
//expect that listener l1 and the failing listener are in start, but
//not the final one
assertServiceStateStarted(service);
assertListenerState(l0, Service.STATE.STARTED);
assertListenerEventCount(l0, 2);
assertListenerState(listener, Service.STATE.STARTED);
assertListenerEventCount(listener, 2);
//this is the listener that is not expected to have been invoked
assertListenerState(l3, Service.STATE.INITED);
assertListenerEventCount(l3, 1);
//stop the service
service.stop();
//listeners are all updated
assertListenerEventCount(l0, 3);
assertListenerEventCount(listener, 3);
assertListenerEventCount(l3, 2);
//can all be unregistered in any order
unregister(logListener);
unregister(l0);
unregister(l3);
//check that the listeners are all unregistered, even
//though they were registered in a different order.
//rather than do this by doing unregister checks, a new service is created
service = new BreakableService();
//this service is initialized
service.init(new Configuration());
//it is asserted that the event count has not changed for the unregistered
//listeners
assertListenerEventCount(l0, 3);
assertListenerEventCount(l3, 2);
//except for the one listener that was not unregistered, which
//has incremented by one
assertListenerEventCount(listener, 4);
}
}