/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013 ForgeRock AS. */ package org.forgerock.opendj.config; import static org.mockito.Mockito.*; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.util.Collection; import java.util.SortedSet; import java.util.TreeSet; import org.mockito.invocation.InvocationOnMock; import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider; import org.opends.server.admin.AliasDefaultBehaviorProvider; import org.opends.server.admin.Configuration; import org.opends.server.admin.DefaultBehaviorProvider; import org.opends.server.admin.DefaultBehaviorProviderVisitor; import org.opends.server.admin.DefinedDefaultBehaviorProvider; import org.opends.server.admin.ManagedObjectDefinition; import org.opends.server.admin.PropertyDefinition; import org.opends.server.admin.PropertyDefinitionsOptions; import org.opends.server.admin.PropertyOption; import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider; import org.opends.server.admin.UndefinedDefaultBehaviorProvider; /** * Provides Mockito mocks for Configuration objects with default values * corresponding to those defined in xml configuration files. *

* These mocks can be used like any other mocks, e.g, you can define stubs using * {@code when} method or verify calls using {@code verify} method. *

* Example: * *

 *  LDAPConnectionHandlerCfg mockCfg = mockCfg(LDAPConnectionHandlerCfg.class);
 *  assertThat(mockCfg.getMaxRequestSize()).isEqualTo(5 * 1000 * 1000);
 * 
*/ public final class ConfigurationMock { private static final ConfigAnswer CONFIG_ANSWER = new ConfigAnswer(); /** * Returns a mock for the provided configuration class. *

* If a setting has a default value, the mock automatically returns the * default value when the getter is called on the setting. *

* It is possible to override this default behavior with the usual methods * calls with Mockito (e.g, {@code when} method). * * @param * The type of configuration. * @param configClass * The configuration class. * @return a mock */ public static T mockCfg(Class configClass) { return mock(configClass, CONFIG_ANSWER); } /** * A stubbed answer for Configuration objects, allowing to return default * value for settings when available. */ private static class ConfigAnswer implements org.mockito.stubbing.Answer { /** {@inheritDoc} */ @Override public Object answer(InvocationOnMock invocation) throws Throwable { String definitionClassName = toDefinitionClassName(invocation.getMethod().getDeclaringClass() .getName()); Class definitionClass = Class.forName(definitionClassName); ManagedObjectDefinition definition = (ManagedObjectDefinition) definitionClass.getMethod( "getInstance").invoke(null); Method getPropertyDefMethod = definitionClass.getMethod(invocation.getMethod().getName() + "PropertyDefinition"); Class propertyReturnType = getPropertyReturnType(getPropertyDefMethod); return getDefaultValue(definition, getPropertyDefMethod, propertyReturnType); } /** * Returns the type of values returned by the property. */ private Class getPropertyReturnType(Method getPropertyDefMethod) { Class returnClass = getPropertyDefMethod.getReturnType(); return ((ParameterizedType) returnClass.getGenericSuperclass()) .getActualTypeArguments()[0].getClass(); } /** * Retrieve class name of definition from class name of configuration. *

* Convert class name "[package].admin.server.FooCfg" to * "[package].admin.meta.FooCfgDef" */ private String toDefinitionClassName(String configClassName) { return configClassName.replaceAll("\\.admin\\.server", ".admin.meta") + "Defn"; } /** * Returns the default value corresponding to the provided property * definition getter method from the provided managed object definition. * * @param * The data type of values provided by the property * definition. * @param definition * The definition of the managed object. * @param getPropertyDefMethod * The method to retrieve the property definition from the * definition. * @param propertyReturnClass * The class of values provided by the property definition. * @return the default value of property definition, or * {@code null} if there is no default value. * @throws Exception * If an error occurs. */ @SuppressWarnings("unchecked") private Object getDefaultValue(ManagedObjectDefinition definition, Method getPropertyDefMethod, Class propertyReturnClass) throws Exception { PropertyDefinition propertyDefinition = (PropertyDefinition) getPropertyDefMethod.invoke(definition); DefaultBehaviorProvider defaultBehaviorProvider = (DefaultBehaviorProvider) propertyDefinition .getClass().getMethod("getDefaultBehaviorProvider").invoke(propertyDefinition); MockProviderVisitor visitor = new MockProviderVisitor(propertyDefinition); Collection values = defaultBehaviorProvider.accept(visitor, null); if (propertyDefinition.hasOption(PropertyOption.MULTI_VALUED)) { return values; } else { // single value returned return values.iterator().next(); } } } /** Visitor used to retrieve the default value. */ private static class MockProviderVisitor implements DefaultBehaviorProviderVisitor, Void> { /** The property definition used to decode the values. */ private PropertyDefinition propertyDef; MockProviderVisitor(PropertyDefinition propertyDef) { this.propertyDef = propertyDef; } /** {@inheritDoc} */ @Override public Collection visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider provider, Void p) { // not handled return null; } /** {@inheritDoc} */ @Override public Collection visitAlias(AliasDefaultBehaviorProvider provider, Void p) { // not handled return null; } /** * Returns the default value for the property as a collection. */ @Override public Collection visitDefined(DefinedDefaultBehaviorProvider provider, Void p) { SortedSet values = new TreeSet(); for (String stringValue : provider.getDefaultValues()) { values.add(propertyDef.decodeValue(stringValue, PropertyDefinitionsOptions.NO_VALIDATION_OPTIONS)); } return values; } /** {@inheritDoc} */ @Override public Collection visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider d, Void p) { // not handled return null; } /** {@inheritDoc} */ @Override public Collection visitUndefined(UndefinedDefaultBehaviorProvider d, Void p) { // not handled return null; } } }