Clover coverage report - Code Coverage for hivemind release 1.1-beta-3
Coverage timestamp: Mon Aug 22 2005 21:38:15 EDT
file stats: LOC: 622   Methods: 36
NCLOC: 336   Classes: 5
 
 Source file Conditionals Statements Methods TOTAL
HiveMindTestCase.java 79.2% 88.3% 91.7% 86.9%
coverage coverage
 1    // Copyright 2004, 2005 The Apache Software Foundation
 2    //
 3    // Licensed under the Apache License, Version 2.0 (the "License");
 4    // you may not use this file except in compliance with the License.
 5    // You may obtain a copy of the License at
 6    //
 7    // http://www.apache.org/licenses/LICENSE-2.0
 8    //
 9    // Unless required by applicable law or agreed to in writing, software
 10    // distributed under the License is distributed on an "AS IS" BASIS,
 11    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    // See the License for the specific language governing permissions and
 13    // limitations under the License.
 14   
 15    package org.apache.hivemind.test;
 16   
 17    import java.net.URL;
 18    import java.util.ArrayList;
 19    import java.util.Iterator;
 20    import java.util.List;
 21    import java.util.Locale;
 22   
 23    import junit.framework.AssertionFailedError;
 24    import junit.framework.TestCase;
 25   
 26    import org.apache.hivemind.ApplicationRuntimeException;
 27    import org.apache.hivemind.ClassResolver;
 28    import org.apache.hivemind.Location;
 29    import org.apache.hivemind.ModuleDescriptorProvider;
 30    import org.apache.hivemind.Registry;
 31    import org.apache.hivemind.Resource;
 32    import org.apache.hivemind.impl.DefaultClassResolver;
 33    import org.apache.hivemind.impl.LocationImpl;
 34    import org.apache.hivemind.impl.RegistryBuilder;
 35    import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
 36    import org.apache.hivemind.internal.ser.ServiceSerializationHelper;
 37    import org.apache.hivemind.util.ClasspathResource;
 38    import org.apache.hivemind.util.PropertyUtils;
 39    import org.apache.hivemind.util.URLResource;
 40    import org.apache.log4j.Level;
 41    import org.apache.log4j.LogManager;
 42    import org.apache.log4j.Logger;
 43    import org.apache.log4j.spi.LoggingEvent;
 44    import org.apache.oro.text.regex.Pattern;
 45    import org.apache.oro.text.regex.Perl5Compiler;
 46    import org.apache.oro.text.regex.Perl5Matcher;
 47    import org.easymock.MockControl;
 48    import org.easymock.classextension.MockClassControl;
 49   
 50    /**
 51    * Contains some support for creating HiveMind tests; this is useful enough that has been moved into
 52    * the main framework, to simplify creation of tests in the dependent libraries.
 53    *
 54    * @author Howard Lewis Ship
 55    */
 56    public abstract class HiveMindTestCase extends TestCase
 57    {
 58    // /CLOVER:OFF
 59   
 60    /**
 61    * An instance of {@link DefaultClassResolver} that can be used by tests.
 62    */
 63   
 64    private ClassResolver _classResolver;
 65   
 66    protected String _interceptedLoggerName;
 67   
 68    protected StoreAppender _appender;
 69   
 70    private static Perl5Compiler _compiler;
 71   
 72    private static Perl5Matcher _matcher;
 73   
 74    /** List of {@link org.easymock.MockControl}. */
 75   
 76    private List _controls = new ArrayList();
 77   
 78    /** @since 1.1 */
 79    interface MockControlFactory
 80    {
 81    public MockControl newControl(Class mockClass);
 82    }
 83   
 84    /** @since 1.1 */
 85    private static class InterfaceMockControlFactory implements MockControlFactory
 86    {
 87  217 public MockControl newControl(Class mockClass)
 88    {
 89  217 return MockControl.createStrictControl(mockClass);
 90    }
 91    }
 92   
 93    /** @since 1.1 */
 94    private static class ClassMockControlFactory implements MockControlFactory
 95    {
 96  1 public MockControl newControl(Class mockClass)
 97    {
 98  1 return MockClassControl.createStrictControl(mockClass);
 99    }
 100    }
 101   
 102    /** @since 1.1 */
 103    static class PlaceholderClassMockControlFactory implements MockControlFactory
 104    {
 105  1 public MockControl newControl(Class mockClass)
 106    {
 107  1 throw new RuntimeException(
 108    "Unable to instantiate EasyMock control for "
 109    + mockClass
 110    + "; ensure that easymockclassextension-1.1.jar and cglib-full-2.0.1.jar are on the classpath.");
 111    }
 112    }
 113   
 114    /** @since 1.1 */
 115    private static final MockControlFactory _interfaceMockControlFactory = new InterfaceMockControlFactory();
 116   
 117    /** @since 1.1 */
 118    private static MockControlFactory _classMockControlFactory;
 119   
 120    static
 121    {
 122  1 try
 123    {
 124  1 _classMockControlFactory = new ClassMockControlFactory();
 125    }
 126    catch (NoClassDefFoundError ex)
 127    {
 128  0 _classMockControlFactory = new PlaceholderClassMockControlFactory();
 129    }
 130    }
 131   
 132    /**
 133    * Returns the given file as a {@link Resource} from the classpath. Typically, this is to find
 134    * files in the same folder as the invoking class.
 135    */
 136  152 protected Resource getResource(String file)
 137    {
 138  152 URL url = getClass().getResource(file);
 139   
 140  152 if (url == null)
 141  0 throw new NullPointerException("No resource named '" + file + "'.");
 142   
 143  152 return new URLResource(url);
 144    }
 145   
 146    /**
 147    * Converts the actual list to an array and invokes
 148    * {@link #assertListsEqual(Object[], Object[])}.
 149    */
 150  16 protected static void assertListsEqual(Object[] expected, List actual)
 151    {
 152  16 assertListsEqual(expected, actual.toArray());
 153    }
 154   
 155    /**
 156    * Asserts that the two arrays are equal; same length and all elements equal. Checks the
 157    * elements first, then the length.
 158    */
 159  23 protected static void assertListsEqual(Object[] expected, Object[] actual)
 160    {
 161  23 assertNotNull(actual);
 162   
 163  23 int min = Math.min(expected.length, actual.length);
 164   
 165  23 for (int i = 0; i < min; i++)
 166  67 assertEquals("list[" + i + "]", expected[i], actual[i]);
 167   
 168  23 assertEquals("list length", expected.length, actual.length);
 169    }
 170   
 171    /**
 172    * Called when code should not be reachable (because a test is expected to throw an exception);
 173    * throws AssertionFailedError always.
 174    */
 175  0 protected static void unreachable()
 176    {
 177  0 throw new AssertionFailedError("This code should be unreachable.");
 178    }
 179   
 180    /**
 181    * Sets up an appender to intercept logging for the specified logger. Captured log events can be
 182    * recovered via {@link #getInterceptedLogEvents()}.
 183    */
 184  49 protected void interceptLogging(String loggerName)
 185    {
 186  49 Logger logger = LogManager.getLogger(loggerName);
 187   
 188  49 logger.removeAllAppenders();
 189   
 190  49 _interceptedLoggerName = loggerName;
 191  49 _appender = new StoreAppender();
 192  49 _appender.activateOptions();
 193   
 194  49 logger.setLevel(Level.DEBUG);
 195  49 logger.setAdditivity(false);
 196  49 logger.addAppender(_appender);
 197    }
 198   
 199    /**
 200    * Gets the list of events most recently intercepted. This resets the appender, clearing the
 201    * list of stored events.
 202    *
 203    * @see #interceptLogging(String)
 204    */
 205   
 206  56 protected List getInterceptedLogEvents()
 207    {
 208  56 return _appender.getEvents();
 209    }
 210   
 211    /**
 212    * Removes the appender that may have been setup by {@link #interceptLogging(String)}. Also,
 213    * invokes {@link org.apache.hivemind.util.PropertyUtils#clearCache()}.
 214    */
 215  616 protected void tearDown() throws Exception
 216    {
 217  616 super.tearDown();
 218   
 219  616 if (_appender != null)
 220    {
 221  49 _appender = null;
 222   
 223  49 Logger logger = LogManager.getLogger(_interceptedLoggerName);
 224  49 logger.setLevel(null);
 225  49 logger.setAdditivity(true);
 226  49 logger.removeAllAppenders();
 227    }
 228   
 229  616 PropertyUtils.clearCache();
 230   
 231  616 ServiceSerializationHelper.setServiceSerializationSupport(null);
 232    }
 233   
 234    /**
 235    * Checks that the provided substring exists in the exceptions message.
 236    */
 237  51 protected void assertExceptionSubstring(Throwable ex, String substring)
 238    {
 239  51 String message = ex.getMessage();
 240  51 assertNotNull(message);
 241   
 242  51 int pos = message.indexOf(substring);
 243   
 244  51 if (pos < 0)
 245  0 throw new AssertionFailedError("Exception message (" + message + ") does not contain ["
 246    + substring + "]");
 247    }
 248   
 249    /**
 250    * Checks that the message for an exception matches a regular expression.
 251    */
 252   
 253  1 protected void assertExceptionRegexp(Throwable ex, String pattern) throws Exception
 254    {
 255  1 String message = ex.getMessage();
 256  1 assertNotNull(message);
 257   
 258  1 setupMatcher();
 259   
 260  1 Pattern compiled = _compiler.compile(pattern);
 261   
 262  1 if (_matcher.contains(message, compiled))
 263  1 return;
 264   
 265  0 throw new AssertionFailedError("Exception message (" + message
 266    + ") does not contain regular expression [" + pattern + "].");
 267    }
 268   
 269  1 protected void assertRegexp(String pattern, String actual) throws Exception
 270    {
 271  1 setupMatcher();
 272   
 273  1 Pattern compiled = _compiler.compile(pattern);
 274   
 275  1 if (_matcher.contains(actual, compiled))
 276  1 return;
 277   
 278  0 throw new AssertionFailedError("\"" + actual + "\" does not contain regular expression["
 279    + pattern + "].");
 280    }
 281   
 282    /**
 283    * Digs down through (potentially) a stack of ApplicationRuntimeExceptions until it reaches the
 284    * originating exception, which is returned.
 285    */
 286  4 protected Throwable findNestedException(ApplicationRuntimeException ex)
 287    {
 288  4 Throwable cause = ex.getRootCause();
 289   
 290  4 if (cause == null || cause == ex)
 291  1 return ex;
 292   
 293  3 if (cause instanceof ApplicationRuntimeException)
 294  2 return findNestedException((ApplicationRuntimeException) cause);
 295   
 296  1 return cause;
 297    }
 298   
 299    /**
 300    * Checks to see if a specific event matches the name and message.
 301    *
 302    * @param message
 303    * exact message to search for
 304    * @param events
 305    * the list of events {@link #getInterceptedLogEvents()}
 306    * @param index
 307    * the index to check at
 308    */
 309  42 private void assertLoggedMessage(String message, List events, int index)
 310    {
 311  42 LoggingEvent e = (LoggingEvent) events.get(index);
 312   
 313  42 assertEquals("Message", message, e.getMessage());
 314    }
 315   
 316    /**
 317    * Checks the messages for all logged events for exact match against the supplied list.
 318    */
 319  8 protected void assertLoggedMessages(String[] messages)
 320    {
 321  8 List events = getInterceptedLogEvents();
 322   
 323  8 for (int i = 0; i < messages.length; i++)
 324    {
 325  42 assertLoggedMessage(messages[i], events, i);
 326    }
 327    }
 328   
 329    /**
 330    * Asserts that some capture log event matches the given message exactly.
 331    */
 332  24 protected void assertLoggedMessage(String message)
 333    {
 334  24 assertLoggedMessage(message, getInterceptedLogEvents());
 335    }
 336   
 337    /**
 338    * Asserts that some capture log event matches the given message exactly.
 339    *
 340    * @param message
 341    * to search for; success is finding a logged message contain the parameter as a
 342    * substring
 343    * @param events
 344    * from {@link #getInterceptedLogEvents()}
 345    */
 346  26 protected void assertLoggedMessage(String message, List events)
 347    {
 348  26 int count = events.size();
 349   
 350  182 for (int i = 0; i < count; i++)
 351    {
 352  182 LoggingEvent e = (LoggingEvent) events.get(i);
 353   
 354  182 String eventMessage = String.valueOf(e.getMessage());
 355   
 356  182 if (eventMessage.indexOf(message) >= 0)
 357  26 return;
 358    }
 359   
 360  0 throw new AssertionFailedError("Could not find logged message: " + message);
 361    }
 362   
 363  21 protected void assertLoggedMessagePattern(String pattern) throws Exception
 364    {
 365  21 assertLoggedMessagePattern(pattern, getInterceptedLogEvents());
 366    }
 367   
 368  26 protected void assertLoggedMessagePattern(String pattern, List events) throws Exception
 369    {
 370  26 setupMatcher();
 371   
 372  26 Pattern compiled = null;
 373   
 374  26 int count = events.size();
 375   
 376  495 for (int i = 0; i < count; i++)
 377    {
 378  495 LoggingEvent e = (LoggingEvent) events.get(i);
 379   
 380  495 String eventMessage = e.getMessage().toString();
 381   
 382  495 if (compiled == null)
 383  26 compiled = _compiler.compile(pattern);
 384   
 385  495 if (_matcher.contains(eventMessage, compiled))
 386  26 return;
 387   
 388    }
 389   
 390  0 throw new AssertionFailedError("Could not find logged message with pattern: " + pattern);
 391    }
 392   
 393  29 private void setupMatcher()
 394    {
 395  29 if (_compiler == null)
 396  1 _compiler = new Perl5Compiler();
 397   
 398  29 if (_matcher == null)
 399  1 _matcher = new Perl5Matcher();
 400    }
 401   
 402    /**
 403    * Convienience method for invoking {@link #buildFrameworkRegistry(String[])} with only a single
 404    * file.
 405    */
 406  103 protected Registry buildFrameworkRegistry(String file) throws Exception
 407    {
 408  103 return buildFrameworkRegistry(new String[]
 409    { file });
 410    }
 411   
 412    /**
 413    * Builds a minimal registry, containing only the specified files, plus the master module
 414    * descriptor (i.e., those visible on the classpath). Files are resolved using
 415    * {@link HiveMindTestCase#getResource(String)}.
 416    */
 417  107 protected Registry buildFrameworkRegistry(String[] files) throws Exception
 418    {
 419  107 ClassResolver resolver = getClassResolver();
 420   
 421  107 List descriptorResources = new ArrayList();
 422  107 for (int i = 0; i < files.length; i++)
 423    {
 424  113 Resource resource = getResource(files[i]);
 425   
 426  113 descriptorResources.add(resource);
 427    }
 428   
 429  107 ModuleDescriptorProvider provider = new XmlModuleDescriptorProvider(resolver,
 430    descriptorResources);
 431   
 432  107 return buildFrameworkRegistry(provider);
 433    }
 434   
 435    /**
 436    * Builds a registry, containing only the modules delivered by the specified
 437    * {@link org.apache.hivemind.ModuleDescriptorProvider}, plus the master module descriptor
 438    * (i.e., those visible on the classpath).
 439    */
 440  112 protected Registry buildFrameworkRegistry(ModuleDescriptorProvider customProvider)
 441    {
 442  112 ClassResolver resolver = getClassResolver();
 443   
 444  112 RegistryBuilder builder = new RegistryBuilder();
 445   
 446  112 builder.addModuleDescriptorProvider(new XmlModuleDescriptorProvider(resolver));
 447  112 builder.addModuleDescriptorProvider(customProvider);
 448   
 449  112 return builder.constructRegistry(Locale.getDefault());
 450    }
 451   
 452    /**
 453    * Builds a registry from exactly the provided resource; this registry will not include the
 454    * <code>hivemind</code> module.
 455    */
 456  0 protected Registry buildMinimalRegistry(Resource l) throws Exception
 457    {
 458  0 RegistryBuilder builder = new RegistryBuilder();
 459   
 460  0 return builder.constructRegistry(Locale.getDefault());
 461    }
 462   
 463    /**
 464    * Creates a <em>managed</em> control via
 465    * {@link MockControl#createStrictControl(java.lang.Class)}. The created control is remembered,
 466    * and will be invoked by {@link #replayControls()}, {@link #verifyControls()}, etc.
 467    * <p>
 468    * The class to mock may be either an interface or a class. The EasyMock class extension
 469    * (easymockclassextension-1.1.jar) and CGLIB (cglib-full-2.01.jar) must be present in the
 470    * latter case (new since 1.1).
 471    */
 472  218 protected MockControl newControl(Class mockClass)
 473    {
 474  218 MockControlFactory factory = mockClass.isInterface() ? _interfaceMockControlFactory
 475    : _classMockControlFactory;
 476   
 477  218 MockControl result = factory.newControl(mockClass);
 478   
 479  218 addControl(result);
 480   
 481  218 return result;
 482    }
 483   
 484    /**
 485    * Accesses the control for a previously created mock object. Iterates over the list of managed
 486    * controls until one is found whose mock object identity equals the mock object provided.
 487    *
 488    * @param Mock
 489    * object whose control is needed
 490    * @return the corresponding MockControl if found
 491    * @throws IllegalArgumentException
 492    * if not found
 493    * @since 1.1
 494    */
 495   
 496  0 protected MockControl getControl(Object mock)
 497    {
 498  0 Iterator i = _controls.iterator();
 499  0 while (i.hasNext())
 500    {
 501  0 MockControl control = (MockControl) i.next();
 502   
 503  0 if (control.getMock() == mock)
 504  0 return control;
 505    }
 506   
 507  0 throw new IllegalArgumentException(mock
 508    + " is not a mock object controlled by any registered MockControl instance.");
 509    }
 510   
 511    /**
 512    * Adds the control to the list of managed controls used by {@link #replayControls()} and
 513    * {@link #verifyControls()}.
 514    */
 515  219 protected void addControl(MockControl control)
 516    {
 517  219 _controls.add(control);
 518    }
 519   
 520    /**
 521    * Convienience for invoking {@link #newControl(Class)} and then invoking
 522    * {@link MockControl#getMock()} on the result.
 523    */
 524  78 protected Object newMock(Class mockClass)
 525    {
 526  78 return newControl(mockClass).getMock();
 527    }
 528   
 529    /**
 530    * Invokes {@link MockControl#replay()} on all controls created by {@link #newControl(Class)}.
 531    */
 532  132 protected void replayControls()
 533    {
 534  132 Iterator i = _controls.iterator();
 535  132 while (i.hasNext())
 536    {
 537  302 MockControl c = (MockControl) i.next();
 538  302 c.replay();
 539    }
 540    }
 541   
 542    /**
 543    * Invokes {@link org.easymock.MockControl#verify()} and {@link MockControl#reset()} on all
 544    * controls created by {@link #newControl(Class)}.
 545    */
 546   
 547  130 protected void verifyControls()
 548    {
 549  130 Iterator i = _controls.iterator();
 550  130 while (i.hasNext())
 551    {
 552  299 MockControl c = (MockControl) i.next();
 553  299 c.verify();
 554  299 c.reset();
 555    }
 556    }
 557   
 558    /**
 559    * Invokes {@link org.easymock.MockControl#reset()} on all controls.
 560    */
 561   
 562  1 protected void resetControls()
 563    {
 564  1 Iterator i = _controls.iterator();
 565  1 while (i.hasNext())
 566    {
 567  2 MockControl c = (MockControl) i.next();
 568  2 c.reset();
 569    }
 570    }
 571   
 572    /**
 573    * @deprecated To be removed in 1.2. Use {@link #newLocation()} instead.
 574    */
 575  38 protected Location fabricateLocation(int line)
 576    {
 577  38 String path = "/" + getClass().getName().replace('.', '/');
 578   
 579  38 Resource r = new ClasspathResource(getClassResolver(), path);
 580   
 581  38 return new LocationImpl(r, line);
 582    }
 583   
 584    private int _line = 1;
 585   
 586    /**
 587    * Returns a new {@link Location} instance. The resource is the test class, and the line number
 588    * increments by one from one for each invocation (thus each call will get a unique instance not
 589    * equal to any previously obtained instance).
 590    *
 591    * @since 1.1
 592    */
 593  38 protected Location newLocation()
 594    {
 595  38 return fabricateLocation(_line++);
 596    }
 597   
 598    /**
 599    * Returns a {@link DefaultClassResolver}. Repeated calls in the same test return the same
 600    * value.
 601    *
 602    * @since 1.1
 603    */
 604   
 605  291 protected ClassResolver getClassResolver()
 606    {
 607  291 if (_classResolver == null)
 608  156 _classResolver = new DefaultClassResolver();
 609   
 610  291 return _classResolver;
 611    }
 612   
 613  1 protected boolean matches(String input, String pattern) throws Exception
 614    {
 615  1 setupMatcher();
 616   
 617  1 Pattern compiled = _compiler.compile(pattern);
 618   
 619  1 return _matcher.matches(input, compiled);
 620    }
 621   
 622    }