| /* |
| * 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.cocoon.core.container; |
| |
| import java.io.InputStream; |
| import java.net.URL; |
| |
| import junit.framework.TestCase; |
| |
| import org.apache.avalon.excalibur.component.DefaultRoleManager; |
| import org.apache.avalon.excalibur.component.ExcaliburComponentManager; |
| import org.apache.avalon.excalibur.logger.LoggerManager; |
| import org.apache.avalon.framework.configuration.Configuration; |
| import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; |
| import org.apache.avalon.framework.container.ContainerUtil; |
| import org.apache.avalon.framework.context.Context; |
| import org.apache.avalon.framework.context.DefaultContext; |
| import org.apache.avalon.framework.logger.ConsoleLogger; |
| import org.apache.avalon.framework.logger.Logger; |
| import org.apache.avalon.framework.service.ServiceException; |
| import org.apache.avalon.framework.service.ServiceManager; |
| import org.apache.avalon.framework.service.WrapperServiceManager; |
| import org.apache.cocoon.util.Deprecation; |
| |
| /** |
| * JUnit TestCase for Cocoon Components. |
| * <p> |
| * This class extends the JUnit TestCase class to setup an environment which |
| * makes it possible to easily test Cocoon Components. The following methods |
| * and instance variables are exposed for convenience testing: |
| * </p> |
| * <dl> |
| * <dt>getManager()</dt> |
| * <dd> |
| * This instance variable contains an initialized service manager which |
| * can be used to lookup components configured in the test configuration |
| * file. (see below) |
| * </dd> |
| * <dt>getLogger()</dt> |
| * <dd> |
| * This method returns a logger for this test case. By default this |
| * logger logs with log level DEBUG. |
| * </dd> |
| * </dl> |
| * <p> |
| * The following test case configuration can be used as a basis for new tests. |
| * Detailed explanations of the configuration elements can be found after |
| * the example. |
| * </p> |
| * <pre> |
| * <testcase> |
| * <context> |
| * <entry name="foo" value="bar"/> |
| * <entry name="baz" class="my.context.Class"/> |
| * </context> |
| * |
| * <roles> |
| * <role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector" |
| * shorthand="datasources" |
| * default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"> |
| * <hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/> |
| * </role> |
| * </roles> |
| * |
| * <components> |
| * <datasources> |
| * <jdbc name="personell"> |
| * <pool-controller min="5" max="10"/> |
| * <jdbc name="personnel"/> |
| * <dburl>jdbc:odbc:test</dburl> |
| * <user>test</user> |
| * <password>test</password> |
| * <driver>sun.jdbc.odbc.JdbcOdbcDriver</driver> |
| * </jdbc> |
| * </datasources> |
| * </components> |
| * </testcase> |
| * </pre> |
| * <p> |
| * Element Explanation: |
| * <dl> |
| * <dt>testcase</dt> |
| * <dd>Defines a test case configuration. Must contain one each of the |
| * following elements: <code>annotation</code>, |
| * <code>context</code>, <code>roles</code>, and <code>components</code> |
| * </dd>. |
| * |
| * <dt>context</dt> |
| * <dd>Allows context properties to be set in the context passed to any |
| * Contextualizable components.</dd> |
| * |
| * <dt>roles</dt> |
| * <dd>Roles configuration for the components configured in the |
| * <code>components</code> element. |
| * </dd> |
| * |
| * <dt>components</dt> |
| * <dd>Used to configure any Components used by the test cases. |
| * </dd> |
| * |
| * </dl> |
| * |
| * @version $Id: $ |
| */ |
| public class ContainerTestCase extends TestCase { |
| |
| /** The default logger */ |
| private Logger logger; |
| |
| /** The service manager to use */ |
| private ServiceManager manager; |
| |
| /** Return the logger */ |
| protected Logger getLogger() { |
| return logger; |
| } |
| |
| /** Return the service manager */ |
| protected ServiceManager getManager() { |
| return this.manager; |
| } |
| |
| /* (non-Javadoc) |
| * @see junit.framework.TestCase#setUp() |
| */ |
| protected void setUp() throws Exception { |
| super.setUp(); |
| |
| String level = System.getProperty("junit.test.loglevel", "" + ConsoleLogger.LEVEL_WARN); |
| this.logger = new ConsoleLogger(Integer.parseInt(level)); |
| Deprecation.setLogger(this.logger); |
| prepare(); |
| } |
| |
| /** |
| * Initializes the ComponentLocator |
| * |
| * The configuration file is determined by the class name plus .xtest appended, |
| * all '.' replaced by '/' and loaded as a resource via classpath |
| */ |
| protected void prepare() |
| throws Exception { |
| final String resourceName = getClass().getName().replace( '.', '/' ) + ".xtest"; |
| URL resource = getClass().getClassLoader().getResource( resourceName ); |
| |
| if (resource != null) { |
| getLogger().debug("Loading resource " + resourceName); |
| prepare(resource.openStream()); |
| } else { |
| getLogger().debug("Resource not found " + resourceName); |
| } |
| } |
| |
| /** |
| * Initializes the ComponentLocator |
| * |
| * @param testconf The configuration file is passed as a <code>InputStream</code> |
| * |
| * A common way to supply a InputStream is to overwrite the initialize() method |
| * in the sub class, do there whatever is needed to get the right InputStream object |
| * supplying a conformant xtest configuartion and pass it to this initialize method. |
| * the mentioned initialize method is also the place to set a different logging priority |
| * to the member variable m_logPriority. |
| */ |
| protected final void prepare(final InputStream testconf) |
| throws Exception { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("ContainerTestCase.initialize"); |
| } |
| |
| final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); |
| final Configuration conf = builder.build(testconf); |
| |
| Context context = this.setupContext(conf.getChild("context")); |
| |
| setupManagers(conf.getChild("components"), |
| conf.getChild("roles"), |
| context); |
| } |
| |
| /* (non-Javadoc) |
| * @see junit.framework.TestCase#tearDown() |
| */ |
| protected void tearDown() throws Exception { |
| done(); |
| super.tearDown(); |
| } |
| |
| /** |
| * Disposes the <code>ComponentLocator</code> |
| */ |
| final private void done() { |
| if (manager != null) { |
| ContainerUtil.dispose(manager); |
| manager = null; |
| } |
| } |
| |
| /** |
| * set up a context according to the xtest configuration specifications context |
| * element. |
| * |
| * A method addContext(DefaultContext context) is called here to enable subclasses |
| * to put additional objects into the context programmatically. |
| */ |
| final private Context setupContext( final Configuration conf ) |
| throws Exception { |
| final DefaultContext context = new DefaultContext(); |
| final Configuration[] confs = conf.getChildren( "entry" ); |
| for (int i = 0; i < confs.length; i++) { |
| final String key = confs[i].getAttribute("name"); |
| final String value = confs[i].getAttribute("value", null); |
| if (value == null) { |
| String clazz = confs[i].getAttribute("class"); |
| Object obj = getClass().getClassLoader().loadClass(clazz).newInstance(); |
| context.put(key, obj); |
| if (getLogger().isInfoEnabled()) { |
| getLogger().info("ContainerTestCase: added an instance of class " + clazz + " to context entry " + key); |
| } |
| } else { |
| context.put(key, value); |
| if (getLogger().isInfoEnabled()) { |
| getLogger().info("ContainerTestCase: added value \"" + value + "\" to context entry " + key); |
| } |
| } |
| } |
| addContext(context); |
| return context ; |
| } |
| |
| /** |
| * This method may be overwritten by subclasses to put additional objects |
| * into the context programmatically. |
| */ |
| protected void addContext(DefaultContext context) { |
| } |
| |
| final private void setupManagers(final Configuration confCM, |
| final Configuration confRM, |
| final Context context) |
| throws Exception { |
| // Setup the RoleManager |
| DefaultRoleManager roleManager = new DefaultRoleManager(); |
| roleManager.enableLogging(getLogger()); |
| roleManager.configure(confRM); |
| |
| // Set up the ComponentLocator |
| ExcaliburComponentManager ecManager = new ExcaliburComponentManager(); |
| ecManager.enableLogging(getLogger()); |
| ecManager.contextualize(context); |
| ecManager.setRoleManager(roleManager); |
| ecManager.setLoggerManager(new DefaultLoggerManager(getLogger())); |
| ecManager.configure(confCM); |
| ecManager.initialize(); |
| this.manager = new WrapperServiceManager(ecManager); |
| } |
| |
| protected final Object lookup(final String key) |
| throws ServiceException { |
| return manager.lookup(key); |
| } |
| |
| protected final void release(final Object object) { |
| manager.release(object); |
| } |
| |
| protected static class DefaultLoggerManager implements LoggerManager { |
| private Logger logger; |
| |
| public DefaultLoggerManager(Logger logger) { |
| this.logger = logger; |
| } |
| /* (non-Javadoc) |
| * @see org.apache.avalon.excalibur.logger.LoggerManager#getDefaultLogger() |
| */ |
| public Logger getDefaultLogger() { |
| return this.logger; |
| } |
| /* (non-Javadoc) |
| * @see org.apache.avalon.excalibur.logger.LoggerManager#getLoggerForCategory(java.lang.String) |
| */ |
| public Logger getLoggerForCategory(String arg0) { |
| return this.logger; |
| } |
| } |
| } |