// Copyright 2009 Google Inc. All Rights Reserved.
//
// 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.google.enterprise.connector.manager;
import com.google.enterprise.connector.manager.TestService.TestServiceToken;
import junit.framework.TestCase;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Tests starting and stopping {@link ContextService} instances when the
* {@link Context} is started and stopped.
*/
public class TestServiceTest extends TestCase {
private static final String TEST_DIR =
"testdata/contextTests/contextService/";
private static final String APPLICATION_CONTEXT = "applicationContext.xml";
// IDs from the test applicationContext.xml file.
private static final String TEST_SERVICE_ONE = "TestServiceOne";
private static final String TEST_SERVICE_TWO = "TestServiceTwo";
private static final String TEST_SERVICE_THREE = "TestServiceThree";
// Lists of expected service names.
private static final List<String> allServiceNames = Arrays.asList(
new String[] {TEST_SERVICE_ONE, TEST_SERVICE_TWO, TEST_SERVICE_THREE});
private static final List<String> orderedServiceIds = Arrays.asList(
new String[] {"1", "2"});
private static final List<String> orderedServiceNames = Arrays.asList(
new String[] {TEST_SERVICE_THREE, TEST_SERVICE_TWO});
private static final List<String> allOrderedServiceNames = Arrays.asList(
new String[] {TEST_SERVICE_THREE, TEST_SERVICE_TWO, TEST_SERVICE_ONE});
private Context context;
@Override
protected void setUp() throws Exception {
// Setup a Context to point to stand alone XML file with just the needed
// beans.
Context.refresh();
context = Context.getInstance();
context.setStandaloneContext(TEST_DIR + APPLICATION_CONTEXT, null);
}
@Override
protected void tearDown() throws Exception {
context = null;
Context.refresh();
}
/**
* Tests to make sure the expected beans are in the context.
*/
public void testServiceBeans() {
ApplicationContext appContext = context.getApplicationContext();
// Check to make sure the right services are in the context.
Map<String, ContextService> services = getServicesBeans(appContext);
assertEquals("Correct number of services",
allServiceNames.size(), services.size());
assertCorrectKeys("Correct service names", allServiceNames, services);
// Check to make sure the right services have been registered for load
// order and that they are in the expected order.
@SuppressWarnings("unchecked")
Map<String, ?> contextServices = (Map<String, ?>)
getBean(Context.ORDERED_SERVICES_BEAN_NAME, null);
assertEquals("Correct number of ordered services",
orderedServiceIds.size(), contextServices.size());
assertCorrectKeys("Correct ordered service ids",
orderedServiceIds, contextServices);
assertServicesInOrder("Ordered services are in correct order",
orderedServiceNames, contextServices);
}
/**
* Tests the order of starting and stopping of the services.
*/
public void testServiceOrder() {
// Get the total list of services and register token queue with them.
List<TestServiceToken> tokenList = new ArrayList<TestServiceToken>();
ApplicationContext appContext = context.getApplicationContext();
for (ContextService service : getServicesBeans(appContext).values()) {
((TestService)service).setTokenList(tokenList);
}
// Start and shutdown the Context and test the tokens.
// TODO(mgronber): Remove this when the Scheduler has become a service.
context.setFeeding(false);
context.start();
context.shutdown(false);
assertEquals("check amount of tokens",
2 * allOrderedServiceNames.size(), tokenList.size());
assertTokenOrder("services started/stopped in right order",
false, allOrderedServiceNames, tokenList);
tokenList.clear();
context.start();
context.shutdown(true);
assertTokenOrder("services started/stopped in right order",
true, allOrderedServiceNames, tokenList);
}
/**
* Tests the order of starting and stopping of the services.
*/
public void testServiceState() {
// Get the total list of services and register token queue with them.
List<TestServiceToken> tokenList = new ArrayList<TestServiceToken>();
ApplicationContext appContext = context.getApplicationContext();
Map<String, ContextService> services = getServicesBeans(appContext);
for (ContextService service : services.values()) {
((TestService)service).setTokenList(tokenList);
}
// Start and shutdown the Context and test the status of the service.
// TODO(mgronber): Remove this when the Scheduler has become a service.
context.setFeeding(false);
context.start();
assertServicesStarted("check services are running",
true, services.values());
context.shutdown(false);
assertServicesStarted("check services are not running",
false, services.values());
context.start();
assertServicesStarted("check services are running",
true, services.values());
context.shutdown(true);
assertServicesStarted("check services are not running",
false, services.values());
}
/**
* Tests that services can be retrieved from the Context.
*/
public void testFindService() {
ApplicationContext appContext = context.getApplicationContext();
for (ContextService service : getServicesBeans(appContext).values()) {
assertEquals("found expected service",
service, context.findService(service.getName()));
}
assertTrue("null if not found", context.findService("bogus") == null);
}
/**
* Checks the status of all the given services to make sure it matches the
* given expected state.
*/
private void assertServicesStarted(String message, boolean expectedState,
Collection<ContextService> services) {
for (ContextService service : services) {
assertEquals(message, expectedState, service.isRunning());
}
}
@SuppressWarnings("unchecked")
private Map<String, ContextService> getServicesBeans(
ListableBeanFactory factory) {
return factory.getBeansOfType(ContextService.class);
}
private Object getBean(String name, Class<?> requiredType) {
return context.getRequiredBean(name, requiredType);
}
/**
* Compares the given list of expected keys with the key set from the
* given map of services to make sure they are all included. Does not check
* for additional keys in the key set.
*/
private void assertCorrectKeys(String message, List<String> expectedKeys,
Map<String, ?> services) {
List<String> missingServiceNames = new ArrayList<String>();
for (String serviceName : expectedKeys) {
if (!services.containsKey(serviceName)) {
missingServiceNames.add(serviceName);
}
}
assertTrue(message, missingServiceNames.isEmpty());
}
/**
* Compares the order of the given keys with the order of the related values
* in the given map of services. Size of list is known to be equal to the
* size of the map.
*/
private void assertServicesInOrder(String message, List<String> orderedKeys,
Map<String, ?> contextServices) {
Iterator<String> listIter = orderedKeys.iterator();
Iterator<String> mapIter = contextServices.keySet().iterator();
while (listIter.hasNext()) {
String serviceName = listIter.next();
TestService service = (TestService) contextServices.get(mapIter.next());
assertEquals(message, serviceName, service.getName());
}
}
/**
* Compares the order of the tokens in the given token list with the service
* names in the given list of service names and force value. It is expected
* that the token list would contain tokens showing the services being started
* in the order given and then stopped in reverse order with the given force
* value.
*/
private void assertTokenOrder(String message, boolean force,
List<String> orderedServiceNames, List<TestServiceToken> tokenList) {
Iterator<TestServiceToken> tokenIter = tokenList.iterator();
TestServiceToken token;
// First check for start tokens.
for (int index = 0; index < orderedServiceNames.size(); index++) {
token = tokenIter.next();
assertEquals(message,
orderedServiceNames.get(index), token.getService());
assertEquals(message, "start", token.getAction());
}
// Then check for stop tokens. Note they should be in reverse order.
for (int index = orderedServiceNames.size() - 1; index >= 0; index--) {
token = tokenIter.next();
assertEquals(message,
orderedServiceNames.get(index), token.getService());
assertEquals(message, "stop", token.getAction());
assertEquals(message, force, token.isActionForced());
}
}
}