mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
09.35.2006 d4b8c4a45412fef75de97c9b3bafbc2b50d43f2a
Add new unit tests that perform validation for message IDs.  One test verifies
that there are no duplicate message ID assignments, and the other makes sure
that all message IDs defined are registered with the server and have a valid
default message. This testing is conducted using reflection to examine all
declared fields in the message classes.

This commit also includes a number of updates to the message classes to fix
problems identified by these unit tests.

OpenDS Issue Number: 974
3 files added
7 files modified
493 ■■■■ changed files
opends/src/server/org/opends/server/messages/BackendMessages.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ConfigMessages.java 63 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/CoreMessages.java 20 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ExtensionsMessages.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/PluginMessages.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/SchemaMessages.java 70 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ToolMessages.java 6 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/messages/DuplicateMessageIDsTestCase.java 135 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/messages/MessagesTestCase.java 46 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/messages/UnregisteredMessageIDsTestCase.java 145 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/BackendMessages.java
@@ -2603,7 +2603,7 @@
    registerMessage(MSGID_TASK_CANNOT_PARSE_ACTUAL_START_TIME,
                    "An error occurred while trying to parse the actual " +
                    "start time value %s from task entry %s.");
    registerMessage(MSGID_TASK_CANNOT_PARSE_SCHEDULED_START_TIME,
    registerMessage(MSGID_TASK_CANNOT_PARSE_COMPLETION_TIME,
                    "An error occurred while trying to parse the completion " +
                    "time value %s from task entry %s.");
    registerMessage(MSGID_TASK_MISSING_ATTR,
opends/src/server/org/opends/server/messages/ConfigMessages.java
@@ -4889,26 +4889,6 @@
  /**
   * The message ID for the description of the server time limit configuration
   * attribute.  This does not take any arguments.
   */
  public static final int MSGID_CONFIG_CORE_DESCRIPTION_TIME_LIMIT =
       CATEGORY_MASK_CONFIG | SEVERITY_MASK_INFORMATIONAL | 450;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to process the server time limit.  This takes two arguments, which
   * are the DN of the configuration entry and a string representation of the
   * exception that was caught.
   */
  public static final int MSGID_CONFIG_CORE_INVALID_TIME_LIMIT =
       CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_ERROR | 451;
  /**
   * The message ID for the message that will be used if an error occurs while
   * attempting to retrieve the configuration base entry for the Directory
   * Server synchronization providers.  This takes a single argument, which is
@@ -5575,15 +5555,6 @@
  /**
   * The message ID for the message that will be used if no default password
   * policy has been defined.  This does not take any arguments.
   */
  public static final int MSGID_CONFIG_PWPOLICY_NO_DEFAULT_POLICY =
       CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_ERROR | 514;
  /**
   * The message ID for the message that will be used if a password policy
   * configuration entry is invalid.  This takes two arguments, which are the DN
   * of the invalid password policy configuration entry and a message that
@@ -6153,6 +6124,35 @@
  /**
   * The message ID for the description of the server time limit configuration
   * attribute.  This does not take any arguments.
   */
  public static final int MSGID_CONFIG_CORE_DESCRIPTION_TIME_LIMIT =
       CATEGORY_MASK_CONFIG | SEVERITY_MASK_INFORMATIONAL | 569;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to process the server time limit.  This takes two arguments, which
   * are the DN of the configuration entry and a string representation of the
   * exception that was caught.
   */
  public static final int MSGID_CONFIG_CORE_INVALID_TIME_LIMIT =
       CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_ERROR | 570;
  /**
   * The message ID for the message that will be used if no default password
   * policy has been defined.  This does not take any arguments.
   */
  public static final int MSGID_CONFIG_PWPOLICY_NO_DEFAULT_POLICY =
       CATEGORY_MASK_CONFIG | SEVERITY_MASK_SEVERE_ERROR | 571;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -7607,7 +7607,7 @@
                    "determine whether the plugin associated with " +
                    "configuration entry %s should be enabled or disabled:  " +
                    "%s.  It will be disabled.");
    registerMessage(MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_CLASS,
    registerMessage(MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_PLUGIN_TYPE,
                    "Specifies the plugin type(s) for this plugin, which "+
                    "control the times when this plugin will be invoked " +
                    "during processing.  This value is only read when " +
@@ -7814,6 +7814,9 @@
    registerMessage(MSGID_CONFIG_LOGGER_INVALID_SUPPRESS_INT_OPERATION_VALUE,
        "Invalid value specified for attribute %s. " +
        "Allowed values are true or false.");
    registerMessage(MSGID_CONFIG_LOGGER_SUPPRESS_INTERNAL_OPERATIONS,
                    "Indicates whether messages for internal operations " +
                    "should be excluded from the access log file.");
    registerMessage(MSGID_CONFIG_KEYMANAGER_CANNOT_INSTALL_NULL_PROVIDER,
opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -5887,16 +5887,6 @@
  /**
   * The message ID for the message that will be used if an attempt is made to
   * increment an attribute that does not exist.  This takes a single argument,
   * which is the name of the attribute.
   */
  public static final int MSGID_ENTRY_INCREMENT_NO_SUCH_ATTRIBUTE =
       CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 562;
  /**
   * The message ID for the message that will be used if an attempt is made to
   * increment an attribute that has multiple values.  This takes a single
   * argument, which is the name of the attribute.
   */
@@ -5947,6 +5937,16 @@
  /**
   * The message ID for the message that will be used if an attempt is made to
   * increment an attribute that does not exist.  This takes a single argument,
   * which is the name of the attribute.
   */
  public static final int MSGID_ENTRY_INCREMENT_NO_SUCH_ATTRIBUTE =
       CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 568;
  /**
   * Associates a set of generic messages with the message IDs defined
   * in this class.
   */
opends/src/server/org/opends/server/messages/ExtensionsMessages.java
@@ -4192,7 +4192,7 @@
    registerMessage(MSGID_FIFOCACHE_UPDATED_INCLUDE_FILTERS,
                    "The set of search filters that will control which " +
                    "entries may be included in the cache has been updated.");
    registerMessage(MSGID_FIFOCACHE_UPDATED_INCLUDE_FILTERS,
    registerMessage(MSGID_FIFOCACHE_UPDATED_EXCLUDE_FILTERS,
                    "The set of search filters that will control which " +
                    "entries should be be excluded from the cache has been " +
                    "updated.");
@@ -5675,7 +5675,7 @@
    registerMessage(MSGID_SOFTREFCACHE_UPDATED_INCLUDE_FILTERS,
                    "The set of search filters that will control which " +
                    "entries may be included in the cache has been updated.");
    registerMessage(MSGID_SOFTREFCACHE_UPDATED_INCLUDE_FILTERS,
    registerMessage(MSGID_SOFTREFCACHE_UPDATED_EXCLUDE_FILTERS,
                    "The set of search filters that will control which " +
                    "entries should be be excluded from the cache has been " +
                    "updated.");
opends/src/server/org/opends/server/messages/PluginMessages.java
@@ -879,7 +879,7 @@
                    ATTR_PROFILE_DIR + " of configuration entry %s is " +
                    "invalid because the specified path does not exist or " +
                    "is not a directory.");
    registerMessage(MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_INTERVAL,
    registerMessage(MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_ACTION,
                    "An unexpected error occurred while attempting to " +
                    "determine the value of the " + ATTR_PROFILE_ACTION +
                    " attribute in the %s entry:  %s.  No action will be " +
opends/src/server/org/opends/server/messages/SchemaMessages.java
@@ -2797,35 +2797,6 @@
  /**
   * The message ID for the message that will be used if an authPassword value
   * has an invalid character in the authValue element.  This takes a single
   * argument, which is the position of the invalid character.
   */
  public static final int MSGID_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR =
       CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_ERROR | 246;
  /**
   * The message ID for the message that will be used if an authPassword value
   * has an empty authValue element.  This does not take any arguments.
   */
  public static final int MSGID_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE =
       CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_ERROR | 247;
  /**
   * The message ID for the message that will be used if an authPassword value
   * has an invalid character after the authValue element.  This takes a single
   * argument, which is the position of the invalid character.
   */
  public static final int MSGID_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR =
       CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_ERROR | 248;
  /**
   * The message ID for the message that will be used if a value does not start
   * with an opening parenthesis.  This takes a single argument, which is the
   * provided value string.
@@ -2948,6 +2919,35 @@
  /**
   * The message ID for the message that will be used if an authPassword value
   * has an invalid character in the authValue element.  This takes a single
   * argument, which is the position of the invalid character.
   */
  public static final int MSGID_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR =
       CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_ERROR | 261;
  /**
   * The message ID for the message that will be used if an authPassword value
   * has an empty authValue element.  This does not take any arguments.
   */
  public static final int MSGID_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE =
       CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_ERROR | 262;
  /**
   * The message ID for the message that will be used if an authPassword value
   * has an invalid character after the authValue element.  This takes a single
   * argument, which is the position of the invalid character.
   */
  public static final int MSGID_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR =
       CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_ERROR | 263;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -3631,6 +3631,18 @@
                    "objectclass with OID %s (%s).  This objectclass exists " +
                    "in the server schema but is defined as %s rather than " +
                    "structural.");
    registerMessage(MSGID_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR,
                    "The definition for the name form with OID %s declared " +
                    "that it should include required attribute \"%s\".  No " +
                    "attribute type matching this name or OID exists in the " +
                    "server schema, so a default attribute type with the " +
                    "directory string syntax will be used.");
    registerMessage(MSGID_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR,
                    "The definition for the name form with OID %s declared " +
                    "that it should include optional attribute \"%s\".  No " +
                    "attribute type matching this name or OID exists in the " +
                    "server schema, so a default attribute type with the " +
                    "directory string syntax will be used.");
    registerMessage(MSGID_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS,
                    "The provided value \"%s\" could not be parsed as a name " +
                    "form description because it does not specify the " +
opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -7093,7 +7093,7 @@
    registerMessage(MSGID_LDIFIMPORT_CANNOT_INITIALIZE_PWPOLICY,
                    "An error occurred while attempting to initialize the " +
                    "password policy components:  %s.");
    registerMessage(MSGID_LDIFEXPORT_CANNOT_INITIALIZE_PLUGINS,
    registerMessage(MSGID_LDIFIMPORT_CANNOT_INITIALIZE_PLUGINS,
                    "An error occurred while attempting to initialize the " +
                    "LDIF import plugins:  %s.");
    registerMessage(MSGID_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER,
@@ -7213,6 +7213,8 @@
                    "# Your password has expired.");
    registerMessage(MSGID_BIND_PASSWORD_EXPIRING,
                    "# Your password will expire in %s.");
    registerMessage(MSGID_BIND_ACCOUNT_LOCKED,
                    "# Your account has been locked.");
    registerMessage(MSGID_BIND_MUST_CHANGE_PASSWORD,
                    "# You must change your password before any other " +
                    "operations will be allowed.");
@@ -8585,7 +8587,7 @@
                    "Line %d of the template file contains an incomplete " +
                    "tag that starts with either '<' or '{' but does get " +
                    "closed.");
    registerMessage(MSGID_MAKELDIF_NO_COLON_IN_BRANCH_EXTRA_LINE,
    registerMessage(MSGID_MAKELDIF_NO_COLON_IN_TEMPLATE_LINE,
                    "There is no colon to separate the attribute name from " +
                    "the value pattern on line %s of the template file in " +
                    "the definition for template %s.");
opends/tests/unit-tests-testng/src/server/org/opends/server/messages/DuplicateMessageIDsTestCase.java
New file
@@ -0,0 +1,135 @@
/*
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.messages;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import static org.testng.Assert.*;
/**
 * This class provides a mechanism for determining whether any of the messages
 * files have duplicate message IDs.
 */
public class DuplicateMessageIDsTestCase
       extends MessagesTestCase
{
  /**
   * Look in the build filesystem for files in the org.opends.server.messages
   * package.  Dynamically load all of those classes and use reflection to look
   * at all fields in those classes.  Make sure that there are no duplicate
   * values between any of those constant fields.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void TestDuplicateMessageIDs()
         throws Exception
  {
    String s = File.separator;
    String buildRoot = System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT);
    String messageClassesDir = buildRoot + s + "build" + s + "classes" + s +
                               "org" + s + "opends" + s + "server" + s +
                               "messages";
    File f = new File(messageClassesDir);
    LinkedList<String> classNames = new LinkedList<String>();
    for (String filename : f.list())
    {
      if (! filename.endsWith(".class"))
      {
        continue;
      }
      classNames.add("org.opends.server.messages." +
                     filename.substring(0, filename.length()-6));
    }
    assertFalse(classNames.isEmpty());
    HashMap<Integer,String> messageIDs = new HashMap<Integer,String>();
    LinkedList<String> conflictingMessageIDs = new LinkedList<String>();
    for (String className : classNames)
    {
      Class c = Class.forName(className);
      for (Field field : c.getDeclaredFields())
      {
        if (field.getType().getName().equals("int"))
        {
          if (Modifier.isStatic(field.getModifiers()) &&
              Modifier.isFinal(field.getModifiers()) &&
              field.getName().startsWith("MSGID_"))
          {
            String fieldName  = className + "." + field.getName();
            int    fieldValue = field.getInt(null);
            String conflictingField = messageIDs.get(fieldValue);
            if (conflictingField == null)
            {
              messageIDs.put(fieldValue, fieldName);
            }
            else
            {
              conflictingMessageIDs.add(conflictingField + "==" +
                                        fieldName + "==" + fieldValue);
            }
          }
        }
      }
    }
    assertFalse(messageIDs.isEmpty());
    if (! conflictingMessageIDs.isEmpty())
    {
      StringBuilder buffer = new StringBuilder();
      Iterator<String> iterator = conflictingMessageIDs.iterator();
      buffer.append("Conflicting message IDs detected:  ");
      buffer.append(iterator.next());
      while (iterator.hasNext())
      {
        buffer.append(", ");
        buffer.append(iterator.next());
      }
      assertTrue(conflictingMessageIDs.isEmpty(), buffer.toString());
    }
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/messages/MessagesTestCase.java
New file
@@ -0,0 +1,46 @@
/*
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.messages;
import org.testng.annotations.Test;
import org.opends.server.DirectoryServerTestCase;
/**
 * An abstract base class for all messages test cases.
 */
@Test(groups = { "precommit", "messages" })
public abstract class MessagesTestCase
       extends DirectoryServerTestCase
{
  // No implementation required.
}
opends/tests/unit-tests-testng/src/server/org/opends/server/messages/UnregisteredMessageIDsTestCase.java
New file
@@ -0,0 +1,145 @@
/*
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.messages;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import static org.testng.Assert.*;
/**
 * This class provides a mechanism for determining whether any of the message
 * IDs defined have not been registered with the server (and therefore may not
 * have a default message).
 */
public class UnregisteredMessageIDsTestCase
       extends MessagesTestCase
{
  /**
   * Make sure that the Directory Server is running.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @BeforeClass()
  public void startServer()
         throws Exception
  {
    TestCaseUtils.startServer();
  }
  /**
   * Look in the build filesystem for files in the org.opends.server.messages
   * package.  Dynamically load all of those classes and use reflection to look
   * at all fields in those classes.  For each field, make sure that it has a
   * corresponding message registered with the server.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void TestUnregisteredMessageIDs()
         throws Exception
  {
    ConcurrentHashMap<Integer,String> messages = MessageHandler.getMessages();
    String s = File.separator;
    String buildRoot = System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT);
    String messageClassesDir = buildRoot + s + "build" + s + "classes" + s +
                               "org" + s + "opends" + s + "server" + s +
                               "messages";
    File f = new File(messageClassesDir);
    LinkedList<String> classNames = new LinkedList<String>();
    for (String filename : f.list())
    {
      if (! filename.endsWith(".class"))
      {
        continue;
      }
      classNames.add("org.opends.server.messages." +
                     filename.substring(0, filename.length()-6));
    }
    assertFalse(classNames.isEmpty());
    LinkedList<String> unregisteredMessageIDs = new LinkedList<String>();
    for (String className : classNames)
    {
      Class c = Class.forName(className);
      for (Field field : c.getDeclaredFields())
      {
        if (field.getType().getName().equals("int"))
        {
          if (Modifier.isStatic(field.getModifiers()) &&
              Modifier.isFinal(field.getModifiers()) &&
              field.getName().startsWith("MSGID_"))
          {
            String fieldName  = className + "." + field.getName();
            int    fieldValue = field.getInt(null);
            if (! messages.containsKey(fieldValue))
            {
              unregisteredMessageIDs.add(fieldName);
            }
          }
        }
      }
    }
    if (! unregisteredMessageIDs.isEmpty())
    {
      StringBuilder buffer = new StringBuilder();
      Iterator<String> iterator = unregisteredMessageIDs.iterator();
      buffer.append("Unregistered message IDs detected:  ");
      buffer.append(iterator.next());
      while (iterator.hasNext())
      {
        buffer.append(", ");
        buffer.append(iterator.next());
      }
      assertTrue(unregisteredMessageIDs.isEmpty(), buffer.toString());
    }
  }
}