From 62aa718cdea635386849628730fd841a6c6cc1f9 Mon Sep 17 00:00:00 2001 From: Neil Wilson Date: Thu, 18 Jan 2024 15:09:06 -0600 Subject: [PATCH] Add a compare-ldap-schemas tool Added a compare-ldap-schemas command-line tool that can be used to identify differences between the schemas of two LDAP servers. --- dist-root/tools/compare-ldap-schemas | 52 + dist-root/tools/compare-ldap-schemas.bat | 46 + docs/release-notes.html | 6 + messages/unboundid-ldapsdk-tools.properties | 163 + src/com/unboundid/ldap/sdk/schema/Schema.java | 20 +- .../ldap/sdk/unboundidds/Launcher.java | 9 + .../unboundidds/tools/CompareLDAPSchemas.java | 3096 ++++++ .../sdk/unboundidds/LauncherTestCase.java | 1 + .../tools/CompareLDAPSchemasTestCase.java | 8467 +++++++++++++++++ 9 files changed, 11854 insertions(+), 6 deletions(-) create mode 100644 dist-root/tools/compare-ldap-schemas create mode 100644 dist-root/tools/compare-ldap-schemas.bat create mode 100644 src/com/unboundid/ldap/sdk/unboundidds/tools/CompareLDAPSchemas.java create mode 100644 tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/CompareLDAPSchemasTestCase.java diff --git a/dist-root/tools/compare-ldap-schemas b/dist-root/tools/compare-ldap-schemas new file mode 100644 index 000000000..086aca0e1 --- /dev/null +++ b/dist-root/tools/compare-ldap-schemas @@ -0,0 +1,52 @@ +#!/bin/sh + +# Copyright 2008-2024 Ping Identity Corporation +# All Rights Reserved. +# +# ----- +# +# Copyright 2008-2024 Ping Identity Corporation +# +# 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. +# +# ----- +# +# Copyright (C) 2008-2024 Ping Identity Corporation +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License (GPLv2 only) +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License + + +# Get the current working directory and the tools directory. +CURRENT_DIR=`pwd` +cd "`dirname "${0}"`" +TOOLS_DIR=`pwd` +cd ${CURRENT_DIR} + + +# Invoke a number of common script utility functions. +. "${TOOLS_DIR}/.script-util.sh" + + +# Invoke the tool with the provided command-line arguments. +"${JAVA_CMD}" ${JAVA_ARGS} \ + -cp "${TOOLS_DIR}/../unboundid-ldapsdk.jar:${CLASSPATH}" \ + com.unboundid.ldap.sdk.unboundidds.tools.CompareLDAPSchemas "${@}" + diff --git a/dist-root/tools/compare-ldap-schemas.bat b/dist-root/tools/compare-ldap-schemas.bat new file mode 100644 index 000000000..79ab2d0b5 --- /dev/null +++ b/dist-root/tools/compare-ldap-schemas.bat @@ -0,0 +1,46 @@ +@echo off + +rem Copyright 2008-2024 Ping Identity Corporation +rem All Rights Reserved. +rem +rem ----- +rem +rem Copyright 2008-2024 Ping Identity Corporation +rem +rem Licensed under the Apache License, Version 2.0 (the "License"); +rem you may not use this file except in compliance with the License. +rem You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. +rem +rem ----- +rem +rem Copyright (C) 2008-2024 Ping Identity Corporation +rem This program is free software; you can redistribute it and/or modify +rem it under the terms of the GNU General Public License (GPLv2 only) +rem or the terms of the GNU Lesser General Public License (LGPLv2.1 only) +rem as published by the Free Software Foundation. +rem +rem This program is distributed in the hope that it will be useful, +rem but WITHOUT ANY WARRANTY; without even the implied warranty of +rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +rem GNU General Public License for more details. +rem +rem You should have received a copy of the GNU General Public License + + +rem Get the directory containing this batch file. +set BATDIR=%~dp0 + +rem Invoke a number of common script utility functions. +call "%BATDIR%\.script-util.bat" + +rem Invoke the tool with the provided command-line arguments. +"%JAVA_CMD%" %JAVA_ARGS% -cp "%BATDIR%\..\unboundid-ldapsdk.jar;%CLASSPATH%" com.unboundid.ldap.sdk.unboundidds.tools.CompareLDAPSchemas %* + diff --git a/docs/release-notes.html b/docs/release-notes.html index 823a97c77..9f527b71f 100644 --- a/docs/release-notes.html +++ b/docs/release-notes.html @@ -19,6 +19,12 @@

Version 7.0.0



+
  • + Added a compare-ldap-schemas command-line tool that can be used to identify + differences between the schemas of two LDAP servers. +

    +
  • +
  • Added the ability to reuse automatically generated JAAS configuration files if possible when attempting a SASL GSSAPI bind. Previously, if the caller didn't diff --git a/messages/unboundid-ldapsdk-tools.properties b/messages/unboundid-ldapsdk-tools.properties index f86585e10..c1dba4859 100644 --- a/messages/unboundid-ldapsdk-tools.properties +++ b/messages/unboundid-ldapsdk-tools.properties @@ -4427,4 +4427,167 @@ ERR_LDAP_DIFF_PROCESSOR_ERROR_GETTING_ENTRY_FROM_SOURCE=An error occurred \ while attempting to retrieve entry ''{0}'' from the source server: {1} ERR_LDAP_DIFF_PROCESSOR_ERROR_GETTING_ENTRY_FROM_TARGET=An error occurred \ while attempting to retrieve entry ''{0}'' from the target server: {1} +INFO_COMPARE_SCHEMA_TOOL_DESC=This tool can be used to compare the schemas of \ + two LDAP servers to identify schema elements that may be present in one but \ + not the other, or elements that may be present in both servers but have \ + differences between them. +INFO_COMPARE_SCHEMA_ARG_DESC_FIRST_SCHEMA_ENTRY_DN=The DN of the subschema \ + subentry in the first server that contains the definitions to examine. If \ + this is not specified, then the entry referenced by the subschemaSubentry \ + attribute in the server''s root DSE will be used. +INFO_COMPARE_SCHEMA_ARG_DESC_SECOND_SCHEMA_ENTRY_DN=The DN of the subschema \ + subentry in the second server that contains the definitions to examine. If \ + this is not specified, then the entry referenced by the subschemaSubentry \ + attribute in the server''s root DSE will be used. +INFO_COMPARE_SCHEMA_ARG_PLACEHOLDER_SCHEMA_ELEMENT_TYPE='{'elementType'}' +INFO_COMPARE_SCHEMA_ARG_DESC_SCHEMA_ELEMENT_TYPE=The types of schema elements \ + to examine. Allowed values include {0}, {1}, {2}, {3}, {4}, {5}, {6}, and \ + {7}. This may be provided multiple times to include multiple specific \ + schema element types. If this argument is not provided, then all schema \ + element types will be considered. +INFO_COMPARE_SCHEMA_ARG_DESC_GET_EXTENDED_SCHEMA_INFO=Use the extended \ + schema info request control, which may be used to retrieve additional \ + information about schema element definitions from a Ping Identity Directory \ + Server. +INFO_COMPARE_SCHEMA_ARG_DESC_IGNORE_DESCRIPTIONS=Indicates that the tool \ + should ignore differences in descriptions when comparing schema elements. +INFO_COMPARE_SCHEMA_ARG_DESC_IGNORE_EXTENSIONS=Indicates that the tool should \ + ignore differences in extensions when comparing schema elements. +INFO_COMPARE_SCHEMA_ARG_PLACEHOLDER_PREFIX='{'prefix'}' +INFO_COMPARE_SCHEMA_ARG_DESC_INCLUDE_NAME_MATCHING_PREFIX=Indicates that the \ + tool should only examine schema elements with names that match the \ + specified prefix. This argument may be provided multiple times to specify \ + multiple include prefixes. If no include or exclude prefixes are \ + specified, then names will not be used when considering which elements to \ + examine. +INFO_COMPARE_SCHEMA_ARG_DESC_EXCLUDE_NAME_MATCHING_PREFIX=Indicates that the \ + tool should not examine schema elements with names that match the specified \ + prefix. This argument may be provided multiple times to specify multiple \ + exclude prefixes. If no include or exclude prefixes are specified, then \ + names will not be used when considering which elements to examine. +INFO_COMPARE_SCHEMA_ARG_PLACEHOLDER_EXTENSION_VALUE='{'name=value'}' +INFO_COMPARE_SCHEMA_ARG_DESC_INCLUDE_EXTENSION_VALUE=Indicates that the tool \ + should only examine schema elements with an extension that has the \ + specified name and value. This argument may be provided multiple times to \ + specify multiple include extension values. If no include or exclude \ + extension values are specified, then extensions will not be used when \ + considering which elements to examine. +INFO_COMPARE_SCHEMA_ARG_DESC_EXCLUDE_EXTENSION_VALUE=Indicates that the tool \ + should no examine schema elements with an extension that has the specified \ + name and value. This argument may be provided multiple times to specify \ + multiple exclude extension values. If no include or exclude extension \ + values are specified, then extensions will not be used when considering \ + which elements to examine. +ERR_COMPARE_SCHEMA_INVALID_SCHEMA_ELEMENT_TYPE=Invalid value ''{0}'' \ + specified for the --{1} argument. Allowed values include ''{2}'', ''{3}'', \ + ''{4}'', ''{5}'', ''{6}'', ''{7}'', ''{8}'', and ''{9}''. +INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL=first +INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL=second +ERR_COMPARE_SCHEMA_SUMMARY_UNPARSABLE_NO_DIFFERENCES=No differences were \ + identified between the server schemas, but one or more unparsable schema \ + elements were encountered. +ERR_COMPARE_SCHEMA_SUMMARY_UNPARSABLE_WITH_DIFFERENCE=One difference was \ + identified between the server schemas, and one or more unparsable schema \ + elements were encountered. +ERR_COMPARE_SCHEMA_SUMMARY_UNPARSABLE_WITH_DIFFERENCES={0} differences were \ + identified between the server schemas, and one or more unparsable schema \ + elements were encountered. +ERR_COMPARE_SCHEMA_SUMMARY_DIFFERENCE=One difference was identified between \ + the server schemas. +ERR_COMPARE_SCHEMA_SUMMARY_DIFFERENCES={0} difference were identified between \ + the server schemas. +INFO_COMPARE_SCHEMA_SUMMARY_NO_DIFFERENCES=No differences were identified \ + between the server schemas. +ERR_COMPARE_SCHEMA_CANNOT_CONNECT=Unable to establish a connection to the {0} \ + server: {1} +ERR_COMPARE_SCHEMA_CANNOT_GET_ROOT_DSE=Unable to retrieve the root DSE from \ + the {0} server to determine the DN of the subschema subentry. +ERR_COMPARE_SCHEMA_CANNOT_GET_ROOT_DSE_SCHEMA_DN=The {0} server''s root DSE \ + does not include the {1} attribute that is expected to specify the location \ + of the subschema subentry. +ERR_COMPARE_SCHEMA_CANNOT_GET_SCHEMA_ENTRY=Unable to retrieve subschema \ + subentry ''{0}'' from the {1} server to obtain its schema definitions. +ERR_COMPARE_SCHEMA_CANNOT_GET_SCHEMA=An error occurred while attempting to \ + obtain the schema definitions from the {0} server: {1} +ERR_COMPARE_SCHEMA_EXTENSION_VALUE_NO_EQUALS=--{0} argument value ''{0}'' is \ + not valid because it does not contain an equal sign to separate the \ + extension name from its value. +ERR_COMPARE_SCHEMA_EXTENSION_VALUE_EMPTY_NAME=--{0} argument value ''{0}'' is \ + not valid because it contains an empty extension name. +ERR_COMPARE_SCHEMA_EXTENSION_VALUE_EMPTY_VALUE=--{0} argument value ''{0}'' is \ + not valid because it contains an empty extension value. +INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAX=attribute syntax +INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE=matching rule +INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE=attribute type +INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS=object class +INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE=DIT content rule +INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULE=DIT structure rule +INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM=name form +INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USE=matching rule use +ERR_COMPARE_SCHEMA_UNPARSABLE_ELEMENT=The following {0} definition was found \ + in the {1} server ({2}): +WARN_COMPARE_SCHEMA_MISSING_SYNTAX=The {0} server contains an attribute \ + syntax definition that is missing from the {1} server: +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION=description +WARN_COMPARE_SCHEMA_MISSING_MATCHING_RULE=The {0} server contains a matching \ + rule definition that is missing from the {1} server: +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SYNTAX_OID=syntax OID +INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_OBSOLETE=OBSOLETE +WARN_COMPARE_SCHEMA_MISSING_ATTRIBUTE_TYPE=The {0} server contains an \ + attribute type definition that is missing from the {1} server: +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SUPERIOR_TYPE=superior type +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_EQUALITY_MR=equality matching rule +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_ORDERING_MR=ordering matching rule +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SUBSTRING_MR=substring matching rule +INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_SINGLE_VALUE=SINGLE-VALUE +INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_NO_USER_MOD=NO-USER-MODIFICATION +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_USAGE=usage +INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_COLLECTIVE=COLLECTIVE +WARN_COMPARE_SCHEMA_MISSING_OBJECT_CLASS=The {0} server contains an object \ + class definition that is missing from the {1} server: +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_REQUIRED_ATTRIBUTE=required attribute +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_OPTIONAL_ATTRIBUTE=optional attribute +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_OBJECT_CLASS_TYPE=object class type +WARN_COMPARE_SCHEMA_MISSING_DIT_CONTENT_RULE=The {0} server contains a DIT \ + content rule definition that is missing from the {1} server: +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_PROHIBITED_ATTRIBUTE=prohibited attribute +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_AUXILIARY_CLASS=auxiliary object class +WARN_COMPARE_SCHEMA_MISSING_DIT_STRUCTURE_RULE=The {0} server contains a DIT \ + structure rule definition that is missing from the {1} server: +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_NAME_FORM=name form +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SUPERIOR_RULE_ID=superior rule ID +WARN_COMPARE_SCHEMA_MISSING_NAME_FORM=The {0} server contains a name form \ + definition that is missing from the {1} server: +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_STRUCTURAL_CLASS=structural object class +WARN_COMPARE_SCHEMA_MISSING_MATCHING_RULE_USE=The {0} server contains a \ + matching rule use definition that is missing from the {1} server: +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_APPLICABLE_ATTRIBUTE=applicable \ + attribute type +WARN_COMPARE_SCHEMA_STRING_MISSING_FROM_SERVER=The {0} server contains {0} \ + ''{1}'' with {2} ''{3}'', but the corresponding definition from the {4} \ + server does not contain any value for that field. +WARN_COMPARE_SCHEMA_STRING_DIFFERENT_BETWEEN_SERVERS=Both servers contain \ + {0} ''{1}'' with {2} values, but the first server has a value of ''{3}'', \ + while the second server has a value of ''{4}''. +WARN_COMPARE_SCHEMA_STRING_ARRAY_SINGLE_IN_ONLY_ONE_SERVER=The {0} server \ + contains {1} ''{2}'' with {3} ''{4}'', but the corresponding definition \ + from the {5} server does not have any values for that field. +WARN_COMPARE_SCHEMA_STRING_ARRAY_MULTIPLE_IN_ONLY_ONE_SERVER=The {0} server \ + contains {1} ''{2}'' with {3} values {4}, but the corresponding \ + definition from the {5} server does not have any values for that field. +WARN_COMPARE_SCHEMA_STRING_ARRAY_VALUE_MISSING_FROM_SERVER=Both servers \ + contain {0} ''{1}'' with values for the ''{2}'' field, but the {3} server \ + has value ''{4}'' that the {5} server does not have. +WARN_COMPARE_SCHEMA_BOOLEAN_DIFFERENCE=The {0} ''{1}'' definition is defined \ + with ''{2}'' in the {3} server, but not in the {4} server. +WARN_COMPARE_SCHEMA_MISSING_EXTENSION=The {0} server contains {1} ''{2}'' \ + with extension ''{3}'' that is not present in the corresponding definition \ + from the {4} server. +WARN_COMPARE_SCHEMA_EXTENSION_DIFFERENCE=Both servers contain a {0} ''{1}'' \ + definition with the ''{2}'' extension, but that extension has a different \ + set of values in each server. +INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_NAME=name +INFO_COMPARE_LDAP_SCHEMAS_EXAMPLE=Compares the LDAP schemas for the two \ + directory servers using the default settings, which will identify any \ + differences between the schemas. diff --git a/src/com/unboundid/ldap/sdk/schema/Schema.java b/src/com/unboundid/ldap/sdk/schema/Schema.java index 52767ec3a..e19d1e69a 100644 --- a/src/com/unboundid/ldap/sdk/schema/Schema.java +++ b/src/com/unboundid/ldap/sdk/schema/Schema.java @@ -86,6 +86,14 @@ public final class Schema implements Serializable { + /** + * The filter that should be used to retrieve the subsechema subentry. + */ + @NotNull public static final Filter SUBSCHEMA_SUBENTRY_FILTER = + Filter.createEqualityFilter("objectClass", "subschema"); + + + /** * The name of the attribute used to hold the attribute syntax definitions. */ @@ -165,7 +173,7 @@ public final class Schema * The set of request attributes that will be used when retrieving the server * subschema subentry in order to retrieve all of the schema elements. */ - @NotNull private static final String[] SCHEMA_REQUEST_ATTRS = + @NotNull public static final String[] SCHEMA_REQUEST_ATTRS = { "*", ATTR_ATTRIBUTE_SYNTAX, @@ -788,8 +796,10 @@ public Schema(@NotNull final Entry schemaEntry, * Parses all schema elements contained in the provided entry. This method * differs from the {@link #Schema(Entry)} constructor in that this method * will throw an exception if it encounters any unparsable schema elements, - * while the constructor will silently ignore them. Alternately, the - * 'constructor that takes a bunch of maps can be used to + * while the constructor will silently ignore them. Alternatively, the + * constructor that takes a bunch of maps can be used to obtain information + * about any unparsable schema elements while still providing access to the + * parsed schema. * * @param schemaEntry The schema entry to parse. It must not be * {@code null}. @@ -1051,9 +1061,7 @@ public static Schema getSchema(@NotNull final LDAPConnection connection, } final Entry schemaEntry = connection.searchForEntry(subschemaSubentryDN, - SearchScope.BASE, - Filter.createEqualityFilter("objectClass", "subschema"), - SCHEMA_REQUEST_ATTRS); + SearchScope.BASE, SUBSCHEMA_SUBENTRY_FILTER, SCHEMA_REQUEST_ATTRS); if (schemaEntry == null) { return null; diff --git a/src/com/unboundid/ldap/sdk/unboundidds/Launcher.java b/src/com/unboundid/ldap/sdk/unboundidds/Launcher.java index 55079072f..9758f6e4e 100644 --- a/src/com/unboundid/ldap/sdk/unboundidds/Launcher.java +++ b/src/com/unboundid/ldap/sdk/unboundidds/Launcher.java @@ -66,6 +66,7 @@ import com.unboundid.ldap.sdk.unboundidds.examples.SubtreeAccessibility; import com.unboundid.ldap.sdk.unboundidds.examples.SummarizeAccessLog; import com.unboundid.ldap.sdk.unboundidds.tools.CollectSupportData; +import com.unboundid.ldap.sdk.unboundidds.tools.CompareLDAPSchemas; import com.unboundid.ldap.sdk.unboundidds.tools.GenerateTOTPSharedSecret; import com.unboundid.ldap.sdk.unboundidds.tools.LDAPCompare; import com.unboundid.ldap.sdk.unboundidds.tools.LDAPDelete; @@ -120,6 +121,8 @@ *
  • base64 -- Launch the {@link Base64Tool} tool.
  • *
  • collect-support-data -- Launch the * {@link CollectSupportData} tool.
  • + *
  • compare-ldap-schemas -- Launch the + * {@link CompareLDAPSchemas} tool.
  • *
  • deliver-one-time-password -- Launch the * {@link DeliverOneTimePassword} tool.
  • *
  • deliver-password-reset-token -- Launch the @@ -251,6 +254,10 @@ else if (firstArg.equals("collect-support-data")) { return CollectSupportData.main(outStream, errStream, remainingArgs); } + else if (firstArg.equals("compare-ldap-schemas")) + { + return CompareLDAPSchemas.main(outStream, errStream, remainingArgs); + } else if (firstArg.equals("deliver-one-time-password")) { return DeliverOneTimePassword.main(remainingArgs, outStream, errStream); @@ -418,6 +425,7 @@ else if (firstArg.equals("validate-ldif")) err.println(" authrate"); err.println(" base64"); err.println(" collect-support-data"); + err.println(" compare-ldap-schemas"); err.println(" deliver-one-time-password"); err.println(" deliver-password-reset-token"); err.println(" dump-dns"); @@ -479,6 +487,7 @@ public static List> getToolClasses() AuthRate.class, Base64Tool.class, CollectSupportData.class, + CompareLDAPSchemas.class, DeliverOneTimePassword.class, DeliverPasswordResetToken.class, DumpDNs.class, diff --git a/src/com/unboundid/ldap/sdk/unboundidds/tools/CompareLDAPSchemas.java b/src/com/unboundid/ldap/sdk/unboundidds/tools/CompareLDAPSchemas.java new file mode 100644 index 000000000..1b1700e85 --- /dev/null +++ b/src/com/unboundid/ldap/sdk/unboundidds/tools/CompareLDAPSchemas.java @@ -0,0 +1,3096 @@ +/* + * Copyright 2024 Ping Identity Corporation + * All Rights Reserved. + */ +/* + * Copyright 2024 Ping Identity Corporation + * + * 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. + */ +/* + * Copyright (C) 2024 Ping Identity Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (GPLv2 only) + * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +package com.unboundid.ldap.sdk.unboundidds.tools; + + + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import com.unboundid.ldap.sdk.Entry; +import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.ResultCode; +import com.unboundid.ldap.sdk.RootDSE; +import com.unboundid.ldap.sdk.SearchRequest; +import com.unboundid.ldap.sdk.SearchScope; +import com.unboundid.ldap.sdk.Version; +import com.unboundid.ldap.sdk.schema.AttributeSyntaxDefinition; +import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; +import com.unboundid.ldap.sdk.schema.DITContentRuleDefinition; +import com.unboundid.ldap.sdk.schema.DITStructureRuleDefinition; +import com.unboundid.ldap.sdk.schema.MatchingRuleDefinition; +import com.unboundid.ldap.sdk.schema.MatchingRuleUseDefinition; +import com.unboundid.ldap.sdk.schema.NameFormDefinition; +import com.unboundid.ldap.sdk.schema.ObjectClassDefinition; +import com.unboundid.ldap.sdk.schema.Schema; +import com.unboundid.ldap.sdk.unboundidds.controls. + ExtendedSchemaInfoRequestControl; +import com.unboundid.util.Debug; +import com.unboundid.util.MultiServerLDAPCommandLineTool; +import com.unboundid.util.NotNull; +import com.unboundid.util.Nullable; +import com.unboundid.util.OID; +import com.unboundid.util.StaticUtils; +import com.unboundid.util.ThreadSafety; +import com.unboundid.util.ThreadSafetyLevel; +import com.unboundid.util.args.ArgumentException; +import com.unboundid.util.args.ArgumentParser; +import com.unboundid.util.args.BooleanArgument; +import com.unboundid.util.args.DNArgument; +import com.unboundid.util.args.StringArgument; + +import static com.unboundid.ldap.sdk.unboundidds.tools.ToolMessages.*; + + + +/** + * This class implements a command-line tool that can be used to retrieve the + * schemas from two LDAP servers and identify any differences between them. + *
    + *
    + * NOTE: This class, and other classes within the + * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only + * supported for use against Ping Identity, UnboundID, and + * Nokia/Alcatel-Lucent 8661 server products. These classes provide support + * for proprietary functionality or for external specifications that are not + * considered stable or mature enough to be guaranteed to work in an + * interoperable way with other types of LDAP servers. + *
    + *
    + * Comparisons that this tool may perform include: + *
      + *
    • Definitions that are present in one server but not another.
    • + *
    • Corresponding definitions with the same OID but different names or sets + * of names.
    • + *
    • Corresponding definitions with different descriptions, obsolete state, + * or sets of extensions.
    • + *
    • Corresponding attribute types with differences in syntaxes, matching + * rules, superior type, single-valued/multivalued behavior, usage, + * collective state, or NO-USER-MODIFICATION state.
    • + *
    • Corresponding object classes with differences in required or optional + * attributes, superior class, or object class type.
    • + *
    • Corresponding DIT content rules with differences in required, optional, + * or prohibited attributes, or allowed auxiliary classes.
    • + *
    • Corresponding name forms with differences in structural class, + * required attributes, or optional attributes.
    • + *
    • Corresponding DIT structure rules with different name form IDs or + * superior rule IDs.
    • + *
    • Corresponding matching rule uses with different sets of applicable + * attribute types.
    • + *
    + */ +@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) +public final class CompareLDAPSchemas + extends MultiServerLDAPCommandLineTool +{ + /** + * The column at which long lines should be wrapped. + */ + private static final int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1; + + + + /** + * The index number used to reference the first server. + */ + private static final int FIRST_SERVER_INDEX = 0; + + + + /** + * The index number used to reference the second server. + */ + private static final int SECOND_SERVER_INDEX = 1; + + + + /** + * The name of the command-line argument used to indicate that the tool should + * not examine schema elements that have an extension with a given name and + * value. + */ + @NotNull private static final String + ARG_NAME_EXCLUDE_ELEMENTS_WITH_EXTENSION_VALUE = + "excludeElementsWithExtensionValue"; + + + + /** + * The name of the command-line argument used to indicate that the tool should + * not examine schema elements with names matching a specified prefix. + */ + @NotNull private static final String + ARG_NAME_EXCLUDE_ELEMENTS_WITH_NAME_MATCHING_PREFIX = + "excludeElementsWithNameMatchingPrefix"; + + + + /** + * The name of the command-line argument used to specify the DN of the first + * server's subschema subentry. + */ + @NotNull private static final String ARG_NAME_FIRST_SCHEMA_ENTRY_DN = + "firstSchemaEntryDN"; + + + + /** + * The name of the command-line argument used to indicate that the tool should + * use the get extended schema info request control if the server reports that + * it is supported. + */ + @NotNull private static final String ARG_NAME_GET_EXTENDED_SCHEMA_INFO = + "getExtendedSchemaInfo"; + + + + /** + * The name of the command-line argument used to indicate that the tool should + * ignore differences in element descriptions. + */ + @NotNull private static final String ARG_NAME_IGNORE_DESCRIPTIONS = + "ignoreDescriptions"; + + + + /** + * The name of the command-line argument used to indicate that the tool should + * ignore differences in element extensions. + */ + @NotNull private static final String ARG_NAME_IGNORE_EXTENSIONS = + "ignoreExtensions"; + + + + /** + * The name of the command-line argument used to indicate that the tool should + * only examine schema elements that have an extension with a given name and + * value. + */ + @NotNull private static final String + ARG_NAME_INCLUDE_ELEMENTS_WITH_EXTENSION_VALUE = + "includeElementsWithExtensionValue"; + + + + /** + * The name of the command-line argument used to indicate that the tool should + * only examine schema elements with names matching a specified prefix. + */ + @NotNull private static final String + ARG_NAME_INCLUDE_ELEMENTS_WITH_NAME_MATCHING_PREFIX = + "includeElementsWithNameMatchingPrefix"; + + + + /** + * The name of the command-line argument used to specify the types of schema + * elements that the server should examine. + */ + @NotNull private static final String ARG_NAME_SCHEMA_ELEMENT_TYPE = + "schemaElementType"; + + + + /** + * The name of the command-line argument used to specify the DN of the second + * server's subschema subentry. + */ + @NotNull private static final String ARG_NAME_SECOND_SCHEMA_ENTRY_DN = + "secondSchemaEntryDN"; + + + + /** + * The name of the schema element type value that indicates that the tool + * should examine attribute syntaxes. + */ + @NotNull private static final String SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAXES = + "attribute-syntaxes"; + + + + /** + * The name of the schema element type value that indicates that the tool + * should examine attribute types. + */ + @NotNull private static final String SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPES = + "attribute-types"; + + + + /** + * The name of the schema element type value that indicates that the tool + * should examine DIT content rules. + */ + @NotNull private static final String SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULES = + "dit-content-rules"; + + + + /** + * The name of the schema element type value that indicates that the tool + * should examine DIT structure rules. + */ + @NotNull private static final String SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULES = + "dit-structure-rules"; + + + + /** + * The name of the schema element type value that indicates that the tool + * should examine matching rule uses. + */ + @NotNull private static final String SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USES = + "matching-rule-uses"; + + + + /** + * The name of the schema element type value that indicates that the tool + * should examine matching rules. + */ + @NotNull private static final String SCHEMA_ELEMENT_TYPE_MATCHING_RULES = + "matching-rules"; + + + + /** + * The name of the schema element type value that indicates that the tool + * should examine object classes. + */ + @NotNull private static final String SCHEMA_ELEMENT_TYPE_OBJECT_CLASSES = + "object-classes"; + + + + /** + * The name of the schema element type value that indicates that the tool + * should examine name forms. + */ + @NotNull private static final String SCHEMA_ELEMENT_TYPE_NAME_FORMS = + "name-forms"; + + + + // A reference to the argument parser for this tool. + @NotNull private final AtomicReference parserRef; + + // A reference to the completion message for this tool. + @NotNull private final AtomicReference completionMessageRef; + + // Indicates whether to ignore differences in schema element descriptions. + private boolean ignoreDescriptions; + + // Indicates whether to ignore differences in schema element extensions. + private boolean ignoreExtensions; + + // Indicates whether we may include or exclude schema elements based on their + // extensions. + private boolean includeOrExcludeBasedOnExtensions; + + // Indicates whether we may include or exclude schema elements based on their + // name. + private boolean includeOrExcludeBasedOnName; + + // A list of name prefixes for schema elements to exclude from the comparison. + @NotNull private final List excludeNamePrefixes; + + // A list of name prefixes for schema elements to include in the comparison. + @NotNull private final List includeNamePrefixes; + + // A map of schema extension values for schema elements to exclude from the + // comparison. + @NotNull private final Map> excludeExtensionValues; + + // A map of schema extension values for schema elements to include in the + // comparison. + @NotNull private final Map> includeExtensionValues; + + // The set of schema element types to examine. + @NotNull private final Set schemaElementTypes; + + + + /** + * Runs this tool with the provided set of arguments, using the default + * streams for standard output and standard error. + * + * @param args The command-line arguments to use to run this program. It + * must not be {@code null}, but may be empty. + */ + public static void main(@NotNull final String... args) + { + final ResultCode resultCode = main(System.out, System.err, args); + if (resultCode != ResultCode.SUCCESS) + { + System.exit(resultCode.intValue()); + } + } + + + + /** + * Runs this tool with the provided set of arguments, using the provided + * streams for standard output and standard error. + * + * @param out The output stream to use for standard output. It may be + * {@code null} if standard output should be suppressed. + * @param err The output stream to use for standard error. It may be + * {@code null} if standard error should be suppressed. + * @param args The command-line arguments to use to run this program. It + * must not be {@code null}, but may be empty. + * + * @return The result code with information about the result of processing. + * A result code of {@code SUCCESS} indicates that all processing + * completed successfully and no differences were identified. A + * result code of {@code COMPARE_FALSE} indicates that all processing + * completed successfully, but one or more differences were + * identified between the server schemas. Any other result code + * indicates that some problem occurred during processing. + */ + @NotNull() + public static ResultCode main(@Nullable final OutputStream out, + @Nullable final OutputStream err, + @NotNull final String... args) + { + final CompareLDAPSchemas tool = new CompareLDAPSchemas(out, err); + return tool.runTool(args); + } + + + + /** + * Creates a new instance of this tool with the provided streams for standard + * output and standard error. + * + * @param out The output stream to use for standard output. It may be + * {@code null} if standard output should be suppressed. + * @param err The output stream to use for standard error. It may be + * {@code null} if standard error should be suppressed. + */ + public CompareLDAPSchemas(@Nullable final OutputStream out, + @Nullable final OutputStream err) + { + super(out, err, new String[] { "first", "second" }, null); + + parserRef = new AtomicReference<>(); + completionMessageRef = new AtomicReference<>(); + + schemaElementTypes = new HashSet<>(StaticUtils.setOf( + SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAXES, + SCHEMA_ELEMENT_TYPE_MATCHING_RULES, + SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPES, + SCHEMA_ELEMENT_TYPE_OBJECT_CLASSES, + SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULES, + SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULES, + SCHEMA_ELEMENT_TYPE_NAME_FORMS, + SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USES)); + + ignoreDescriptions = false; + ignoreExtensions = false; + includeNamePrefixes = new ArrayList<>(); + excludeNamePrefixes = new ArrayList<>(); + includeExtensionValues = new HashMap<>(); + excludeExtensionValues = new HashMap<>(); + } + + + + /** + * {@inheritDoc} + */ + @Override() + @NotNull() + public String getToolName() + { + return "compare-ldap-schemas"; + } + + + + /** + * {@inheritDoc} + */ + @Override() + @NotNull() + public String getToolDescription() + { + return INFO_COMPARE_SCHEMA_TOOL_DESC.get(); + } + + + + /** + * {@inheritDoc} + */ + @Override() + @NotNull() + public String getToolVersion() + { + return Version.getNumericVersionString(); + } + + + + /** + * {@inheritDoc} + */ + @Override() + protected boolean includeAlternateLongIdentifiers() + { + return true; + } + + + + /** + * {@inheritDoc} + */ + @Override() + public void addNonLDAPArguments(@NotNull final ArgumentParser parser) + throws ArgumentException + { + parserRef.set(parser); + + final DNArgument firstSchemaEntryDNArg = new DNArgument(null, + ARG_NAME_FIRST_SCHEMA_ENTRY_DN, false, 1, null, + INFO_COMPARE_SCHEMA_ARG_DESC_FIRST_SCHEMA_ENTRY_DN.get()); + firstSchemaEntryDNArg.addLongIdentifier("first-schema-entry-dn", true); + firstSchemaEntryDNArg.addLongIdentifier("firstSchemaEntry", true); + firstSchemaEntryDNArg.addLongIdentifier("first-schema-entry", true); + firstSchemaEntryDNArg.addLongIdentifier("firstSchemaDN", true); + firstSchemaEntryDNArg.addLongIdentifier("first-schema-dn", true); + firstSchemaEntryDNArg.addLongIdentifier("firstSchema", true); + firstSchemaEntryDNArg.addLongIdentifier("first-schema", true); + parser.addArgument(firstSchemaEntryDNArg); + + final DNArgument secondSchemaEntryDNArg = new DNArgument(null, + ARG_NAME_SECOND_SCHEMA_ENTRY_DN, false, 1, null, + INFO_COMPARE_SCHEMA_ARG_DESC_SECOND_SCHEMA_ENTRY_DN.get()); + secondSchemaEntryDNArg.addLongIdentifier("second-schema-entry-dn", true); + secondSchemaEntryDNArg.addLongIdentifier("secondSchemaEntry", true); + secondSchemaEntryDNArg.addLongIdentifier("second-schema-entry", true); + secondSchemaEntryDNArg.addLongIdentifier("secondSchemaDN", true); + secondSchemaEntryDNArg.addLongIdentifier("second-schema-dn", true); + secondSchemaEntryDNArg.addLongIdentifier("secondSchema", true); + secondSchemaEntryDNArg.addLongIdentifier("second-schema", true); + parser.addArgument(secondSchemaEntryDNArg); + + final StringArgument schemaElementTypesArg = new StringArgument(null, + ARG_NAME_SCHEMA_ELEMENT_TYPE, false, 0, + INFO_COMPARE_SCHEMA_ARG_PLACEHOLDER_SCHEMA_ELEMENT_TYPE.get(), + INFO_COMPARE_SCHEMA_ARG_DESC_SCHEMA_ELEMENT_TYPE.get( + SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAXES, + SCHEMA_ELEMENT_TYPE_MATCHING_RULES, + SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPES, + SCHEMA_ELEMENT_TYPE_OBJECT_CLASSES, + SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULES, + SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULES, + SCHEMA_ELEMENT_TYPE_NAME_FORMS, + SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USES)); + schemaElementTypesArg.addLongIdentifier("schema-element-types", true); + parser.addArgument(schemaElementTypesArg); + + final BooleanArgument getExtendedSchemaInfoArg = new BooleanArgument(null, + ARG_NAME_GET_EXTENDED_SCHEMA_INFO, 1, + INFO_COMPARE_SCHEMA_ARG_DESC_GET_EXTENDED_SCHEMA_INFO.get()); + getExtendedSchemaInfoArg.addLongIdentifier("get-extended-schema-info", + true); + parser.addArgument(getExtendedSchemaInfoArg); + + final BooleanArgument ignoreDescriptionsArg = new BooleanArgument(null, + ARG_NAME_IGNORE_DESCRIPTIONS, 1, + INFO_COMPARE_SCHEMA_ARG_DESC_IGNORE_DESCRIPTIONS.get()); + ignoreDescriptionsArg.addLongIdentifier("ignore-descriptions", true); + ignoreDescriptionsArg.addLongIdentifier("ignoreDescription", true); + ignoreDescriptionsArg.addLongIdentifier("ignore-description", true); + parser.addArgument(ignoreDescriptionsArg); + + final BooleanArgument ignoreExtensionsArg = new BooleanArgument(null, + ARG_NAME_IGNORE_EXTENSIONS, 1, + INFO_COMPARE_SCHEMA_ARG_DESC_IGNORE_EXTENSIONS.get()); + ignoreExtensionsArg.addLongIdentifier("ignore-extensions", true); + ignoreExtensionsArg.addLongIdentifier("ignoreExtension", true); + ignoreExtensionsArg.addLongIdentifier("ignore-extension", true); + parser.addArgument(ignoreExtensionsArg); + + final StringArgument includeElementsWithNameMatchingPrefixArg = + new StringArgument(null, + ARG_NAME_INCLUDE_ELEMENTS_WITH_NAME_MATCHING_PREFIX, false, 0, + INFO_COMPARE_SCHEMA_ARG_PLACEHOLDER_PREFIX.get(), + INFO_COMPARE_SCHEMA_ARG_DESC_INCLUDE_NAME_MATCHING_PREFIX.get()); + includeElementsWithNameMatchingPrefixArg.addLongIdentifier( + "include-elements-with-name-matching-prefix", true); + parser.addArgument(includeElementsWithNameMatchingPrefixArg); + + final StringArgument excludeElementsWithNameMatchingPrefixArg = + new StringArgument(null, + ARG_NAME_EXCLUDE_ELEMENTS_WITH_NAME_MATCHING_PREFIX, false, 0, + INFO_COMPARE_SCHEMA_ARG_PLACEHOLDER_PREFIX.get(), + INFO_COMPARE_SCHEMA_ARG_DESC_EXCLUDE_NAME_MATCHING_PREFIX.get()); + excludeElementsWithNameMatchingPrefixArg.addLongIdentifier( + "exclude-elements-with-name-matching-prefix", true); + parser.addArgument(excludeElementsWithNameMatchingPrefixArg); + + final StringArgument includeElementsWithExtensionValueArg = + new StringArgument(null, + ARG_NAME_INCLUDE_ELEMENTS_WITH_EXTENSION_VALUE, false, 0, + INFO_COMPARE_SCHEMA_ARG_PLACEHOLDER_EXTENSION_VALUE.get(), + INFO_COMPARE_SCHEMA_ARG_DESC_INCLUDE_EXTENSION_VALUE.get()); + includeElementsWithExtensionValueArg.addLongIdentifier( + "include-elements-with-extension-value", true); + parser.addArgument(includeElementsWithExtensionValueArg); + + final StringArgument excludeElementsWithExtensionValueArg = + new StringArgument(null, + ARG_NAME_EXCLUDE_ELEMENTS_WITH_EXTENSION_VALUE, false, 0, + INFO_COMPARE_SCHEMA_ARG_PLACEHOLDER_EXTENSION_VALUE.get(), + INFO_COMPARE_SCHEMA_ARG_DESC_EXCLUDE_EXTENSION_VALUE.get()); + excludeElementsWithExtensionValueArg.addLongIdentifier( + "exclude-elements-with-extension-value", true); + parser.addArgument(excludeElementsWithExtensionValueArg); + } + + + + /** + * {@inheritDoc} + */ + @Override() + public void doExtendedNonLDAPArgumentValidation() + throws ArgumentException + { + // Identify the types of schema elements to examine. + final ArgumentParser parser = parserRef.get(); + final StringArgument schemaElementTypesArg = + parser.getStringArgument(ARG_NAME_SCHEMA_ELEMENT_TYPE); + if ((schemaElementTypesArg != null) && schemaElementTypesArg.isPresent()) + { + schemaElementTypes.clear(); + for (final String value : schemaElementTypesArg.getValues()) + { + if (value.equalsIgnoreCase(SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAXES)) + { + schemaElementTypes.add(SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAXES); + } + else if (value.equalsIgnoreCase(SCHEMA_ELEMENT_TYPE_MATCHING_RULES)) + { + schemaElementTypes.add(SCHEMA_ELEMENT_TYPE_MATCHING_RULES); + } + else if (value.equalsIgnoreCase(SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPES)) + { + schemaElementTypes.add(SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPES); + } + else if (value.equalsIgnoreCase(SCHEMA_ELEMENT_TYPE_OBJECT_CLASSES)) + { + schemaElementTypes.add(SCHEMA_ELEMENT_TYPE_OBJECT_CLASSES); + } + else if (value.equalsIgnoreCase(SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULES)) + { + schemaElementTypes.add(SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULES); + } + else if (value.equalsIgnoreCase( + SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULES)) + { + schemaElementTypes.add(SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULES); + } + else if (value.equalsIgnoreCase(SCHEMA_ELEMENT_TYPE_NAME_FORMS)) + { + schemaElementTypes.add(SCHEMA_ELEMENT_TYPE_NAME_FORMS); + } + else if (value.equalsIgnoreCase(SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USES)) + { + schemaElementTypes.add(SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USES); + } + else + { + throw new ArgumentException( + ERR_COMPARE_SCHEMA_INVALID_SCHEMA_ELEMENT_TYPE.get(value, + ARG_NAME_SCHEMA_ELEMENT_TYPE, + SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAXES, + SCHEMA_ELEMENT_TYPE_MATCHING_RULES, + SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPES, + SCHEMA_ELEMENT_TYPE_OBJECT_CLASSES, + SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULES, + SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULES, + SCHEMA_ELEMENT_TYPE_NAME_FORMS, + SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USES)); + } + } + } + + + // Determine whether to ignore schema element descriptions or extensions. + final BooleanArgument ignoreDescriptionsArg = + parser.getBooleanArgument(ARG_NAME_IGNORE_DESCRIPTIONS); + ignoreDescriptions = + ((ignoreDescriptionsArg != null) && ignoreDescriptionsArg.isPresent()); + + final BooleanArgument ignoreExtensionsArg = + parser.getBooleanArgument(ARG_NAME_IGNORE_EXTENSIONS); + ignoreExtensions = + ((ignoreExtensionsArg != null) && ignoreExtensionsArg.isPresent()); + + + // Identify the schema element name prefixes to include and exclude. + getNamePrefixes(ARG_NAME_INCLUDE_ELEMENTS_WITH_NAME_MATCHING_PREFIX, + includeNamePrefixes); + getNamePrefixes(ARG_NAME_EXCLUDE_ELEMENTS_WITH_NAME_MATCHING_PREFIX, + excludeNamePrefixes); + includeOrExcludeBasedOnName = (! includeNamePrefixes.isEmpty()) || + (! excludeNamePrefixes.isEmpty()); + + + // Identify the schema element extension values to include and exclude. + getExtensionValues(ARG_NAME_INCLUDE_ELEMENTS_WITH_EXTENSION_VALUE, + includeExtensionValues); + getExtensionValues(ARG_NAME_EXCLUDE_ELEMENTS_WITH_EXTENSION_VALUE, + excludeExtensionValues); + includeOrExcludeBasedOnExtensions = (! includeExtensionValues.isEmpty()) || + (! excludeExtensionValues.isEmpty()); + } + + + + /** + * Populates the provided list with the set of schema element prefixes + * contained in the specified argument. + * + * @param argumentName The name of the argument whose values will be used to + * populate the given list. + * @param prefixList The list to be updated to include the values of the + * specified argument. + */ + private void getNamePrefixes(@NotNull final String argumentName, + @NotNull final List prefixList) + { + prefixList.clear(); + final StringArgument arg = parserRef.get().getStringArgument(argumentName); + if ((arg == null) || (! arg.isPresent())) + { + return; + } + + for (final String value : arg.getValues()) + { + prefixList.add(StaticUtils.toLowerCase(value)); + } + } + + + + /** + * Populates the provided map with the set of schema element extension + * name-value pairs contained in the specified argument. + * + * @param argumentName The name of the argument whose values will be used to + * populate the given map. + * @param extensionMap The map to be updated to include the values of the + * specified argument. + * + * @throws ArgumentException If there is a problem with any of the values of + * the specified argument. + */ + private void getExtensionValues( + @NotNull final String argumentName, + @NotNull final Map> extensionMap) + throws ArgumentException + { + extensionMap.clear(); + final StringArgument arg = parserRef.get().getStringArgument(argumentName); + if ((arg == null) || (! arg.isPresent())) + { + return; + } + + for (final String value : arg.getValues()) + { + final int equalPos = value.indexOf('='); + if (equalPos < 0) + { + throw new ArgumentException( + ERR_COMPARE_SCHEMA_EXTENSION_VALUE_NO_EQUALS.get(argumentName, + value)); + } + + final String extensionName = + StaticUtils.toLowerCase(value.substring(0, equalPos)); + if (extensionName.isEmpty()) + { + throw new ArgumentException( + ERR_COMPARE_SCHEMA_EXTENSION_VALUE_EMPTY_NAME.get(argumentName, + value)); + } + + final String extensionValue = + StaticUtils.toLowerCase(value.substring(equalPos + 1)); + if (extensionValue.isEmpty()) + { + throw new ArgumentException( + ERR_COMPARE_SCHEMA_EXTENSION_VALUE_EMPTY_VALUE.get(argumentName, + value)); + } + + List valueList = extensionMap.get(extensionName); + if (valueList == null) + { + valueList = new ArrayList<>(); + extensionMap.put(extensionName, valueList); + } + + valueList.add(extensionValue); + } + } + + + + /** + * {@inheritDoc} + */ + @Override() + public boolean supportsInteractiveMode() + { + return true; + } + + + + /** + * {@inheritDoc} + */ + @Override() + public boolean defaultsToInteractiveMode() + { + return true; + } + + + + /** + * {@inheritDoc} + */ + @Override() + public boolean supportsPropertiesFile() + { + return true; + } + + + + /** + * {@inheritDoc} + */ + @Override() + protected boolean supportsOutputFile() + { + return true; + } + + + + /** + * {@inheritDoc} + */ + @Override() + protected boolean logToolInvocationByDefault() + { + return false; + } + + + + /** + * {@inheritDoc} + */ + @Override() + @Nullable() + protected String getToolCompletionMessage() + { + return completionMessageRef.get(); + } + + + + /** + * {@inheritDoc} + */ + @Override() + @NotNull() + public ResultCode doToolProcessing() + { + // Get the schemas from each of the servers. + final Schema firstServerSchema; + final Map firstUnparsableAttributeSyntaxes = + new LinkedHashMap<>(); + final Map firstUnparsableMatchingRules = + new LinkedHashMap<>(); + final Map firstUnparsableAttributeTypes = + new LinkedHashMap<>(); + final Map firstUnparsableObjectClasses = + new LinkedHashMap<>(); + final Map firstUnparsableDITContentRules = + new LinkedHashMap<>(); + final Map firstUnparsableDITStructureRules = + new LinkedHashMap<>(); + final Map firstUnparsableNameForms = + new LinkedHashMap<>(); + final Map firstUnparsableMatchingRuleUses = + new LinkedHashMap<>(); + try + { + firstServerSchema = getSchema(FIRST_SERVER_INDEX, + ARG_NAME_FIRST_SCHEMA_ENTRY_DN, + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + firstUnparsableAttributeSyntaxes, firstUnparsableMatchingRules, + firstUnparsableAttributeTypes, firstUnparsableObjectClasses, + firstUnparsableDITContentRules, firstUnparsableDITStructureRules, + firstUnparsableNameForms, firstUnparsableMatchingRuleUses); + } + catch (final LDAPException e) + { + logCompletionError(e.getMessage()); + return e.getResultCode(); + } + + final Schema secondServerSchema; + final Map secondUnparsableAttributeSyntaxes = + new LinkedHashMap<>(); + final Map secondUnparsableMatchingRules = + new LinkedHashMap<>(); + final Map secondUnparsableAttributeTypes = + new LinkedHashMap<>(); + final Map secondUnparsableObjectClasses = + new LinkedHashMap<>(); + final Map secondUnparsableDITContentRules = + new LinkedHashMap<>(); + final Map secondUnparsableDITStructureRules = + new LinkedHashMap<>(); + final Map secondUnparsableNameForms = + new LinkedHashMap<>(); + final Map secondUnparsableMatchingRuleUses = + new LinkedHashMap<>(); + try + { + secondServerSchema = getSchema(SECOND_SERVER_INDEX, + ARG_NAME_SECOND_SCHEMA_ENTRY_DN, + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + secondUnparsableAttributeSyntaxes, secondUnparsableMatchingRules, + secondUnparsableAttributeTypes, secondUnparsableObjectClasses, + secondUnparsableDITContentRules, secondUnparsableDITStructureRules, + secondUnparsableNameForms, secondUnparsableMatchingRuleUses); + } + catch (final LDAPException e) + { + logCompletionError(e.getMessage()); + return e.getResultCode(); + } + + + // Report on any unparsable schema elements. + final AtomicReference resultCodeRef = new AtomicReference<>(); + boolean unparsableElementsEncountered = reportUnparsableSchemaElements( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + firstUnparsableAttributeSyntaxes, firstUnparsableMatchingRules, + firstUnparsableAttributeTypes, firstUnparsableObjectClasses, + firstUnparsableDITContentRules, firstUnparsableDITStructureRules, + firstUnparsableNameForms, firstUnparsableMatchingRuleUses); + + unparsableElementsEncountered |= reportUnparsableSchemaElements( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + secondUnparsableAttributeSyntaxes, secondUnparsableMatchingRules, + secondUnparsableAttributeTypes, secondUnparsableObjectClasses, + secondUnparsableDITContentRules, secondUnparsableDITStructureRules, + secondUnparsableNameForms, secondUnparsableMatchingRuleUses); + + if (unparsableElementsEncountered) + { + resultCodeRef.set(ResultCode.INVALID_ATTRIBUTE_SYNTAX); + } + + + // Validate the different types of schema elements. + final AtomicInteger numDifferences = new AtomicInteger(); + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAXES)) + { + compareAttributeSyntaxes(firstServerSchema, secondServerSchema, + numDifferences); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_MATCHING_RULES)) + { + compareMatchingRules(firstServerSchema, secondServerSchema, + numDifferences); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPES)) + { + compareAttributeTypes(firstServerSchema, secondServerSchema, + numDifferences); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_OBJECT_CLASSES)) + { + compareObjectClasses(firstServerSchema, secondServerSchema, + numDifferences); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULES)) + { + compareDITContentRules(firstServerSchema, secondServerSchema, + numDifferences); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULES)) + { + compareDITStructureRules(firstServerSchema, secondServerSchema, + numDifferences); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_NAME_FORMS)) + { + compareNameForms(firstServerSchema, secondServerSchema, numDifferences); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USES)) + { + compareMatchingRuleUses(firstServerSchema, secondServerSchema, + numDifferences); + } + + + // If any errors were encountered, then return an error result code. + // Otherwise, if any differences were encountered, then return a + // COMPARE_FALSE result code. Otherwise, return a SUCCESS result code. + final int differenceCount = numDifferences.get(); + if (unparsableElementsEncountered) + { + switch (differenceCount) + { + case 0: + logCompletionError( + ERR_COMPARE_SCHEMA_SUMMARY_UNPARSABLE_NO_DIFFERENCES.get()); + break; + case 1: + logCompletionError( + ERR_COMPARE_SCHEMA_SUMMARY_UNPARSABLE_WITH_DIFFERENCE.get()); + break; + default: + logCompletionError( + ERR_COMPARE_SCHEMA_SUMMARY_UNPARSABLE_WITH_DIFFERENCES.get( + differenceCount)); + break; + } + } + else if (differenceCount > 0) + { + resultCodeRef.compareAndSet(null, ResultCode.COMPARE_FALSE); + if (differenceCount == 1) + { + logCompletionError( + ERR_COMPARE_SCHEMA_SUMMARY_DIFFERENCE.get()); + } + else + { + logCompletionError( + ERR_COMPARE_SCHEMA_SUMMARY_DIFFERENCES.get(differenceCount)); + } + } + else + { + resultCodeRef.compareAndSet(null, ResultCode.SUCCESS); + final String message = INFO_COMPARE_SCHEMA_SUMMARY_NO_DIFFERENCES.get(); + completionMessageRef.compareAndSet(null, message); + wrapOut(0, WRAP_COLUMN, message); + } + + return resultCodeRef.get(); + } + + + + /** + * Retrieves the schema from the specified server. + * + * @param serverIndex + * The index for the server from which to retrieve the schema. + * @param schemaDNArgName + * The name of the argument to use to retrieve the DN of the + * subschema subentry, if specified. It must not be + * {@code null}. + * @param serverLabel + * The label to use to refer to the server. It must not be + * {@code null}. + * @param unparsableAttributeSyntaxes + * A map that will be updated with information about any + * unparsable attribute syntax definitions found in the schema + * from the specified server. Each key will be the unparsable + * definition, and the corresponding value will be the exception + * caught while trying to parse it. It must not be {@code null}. + * @param unparsableMatchingRules + * A map that will be updated with information about any + * unparsable matching rule definitions found in the schema + * from the specified server. Each key will be the unparsable + * definition, and the corresponding value will be the exception + * caught while trying to parse it. It must not be {@code null}. + * @param unparsableAttributeTypes + * A map that will be updated with information about any + * unparsable attribute type definitions found in the schema + * from the specified server. Each key will be the unparsable + * definition, and the corresponding value will be the exception + * caught while trying to parse it. It must not be {@code null}. + * @param unparsableObjectClasses + * A map that will be updated with information about any + * unparsable object class definitions found in the schema + * from the specified server. Each key will be the unparsable + * definition, and the corresponding value will be the exception + * caught while trying to parse it. It must not be {@code null}. + * @param unparsableDITContentRules + * A map that will be updated with information about any + * unparsable DIT content rule definitions found in the schema + * from the specified server. Each key will be the unparsable + * definition, and the corresponding value will be the exception + * caught while trying to parse it. It must not be {@code null}. + * @param unparsableDITStructureRules + * A map that will be updated with information about any + * unparsable DIT structure rule definitions found in the schema + * from the specified server. Each key will be the unparsable + * definition, and the corresponding value will be the exception + * caught while trying to parse it. It must not be {@code null}. + * @param unparsableNameForms + * A map that will be updated with information about any + * unparsable name form definitions found in the schema + * from the specified server. Each key will be the unparsable + * definition, and the corresponding value will be the exception + * caught while trying to parse it. It must not be {@code null}. + * @param unparsableMatchingRuleUses + * A map that will be updated with information about any + * unparsable matching rule use definitions found in the schema + * from the specified server. Each key will be the unparsable + * definition, and the corresponding value will be the exception + * caught while trying to parse it. It must not be {@code null}. + * + * @return The schema retrieved from the server. + * + * @throws LDAPException If a problem occurs while attempting to obtain the + * schema. + */ + @NotNull() + private Schema getSchema(final int serverIndex, + @NotNull final String schemaDNArgName, + @NotNull final String serverLabel, + @NotNull final Map unparsableAttributeSyntaxes, + @NotNull final Map unparsableMatchingRules, + @NotNull final Map unparsableAttributeTypes, + @NotNull final Map unparsableObjectClasses, + @NotNull final Map unparsableDITContentRules, + @NotNull final Map unparsableDITStructureRules, + @NotNull final Map unparsableNameForms, + @NotNull final Map unparsableMatchingRuleUses) + throws LDAPException + { + // Establish a connection to the server. + final LDAPConnection conn; + try + { + conn = getConnection(serverIndex); + } + catch (final LDAPException e) + { + Debug.debugException(e); + throw new LDAPException(e.getResultCode(), + ERR_COMPARE_SCHEMA_CANNOT_CONNECT.get(serverLabel, e.getMessage()), + e); + } + + final ArgumentParser parser = parserRef.get(); + final BooleanArgument getExtendedSchemaInfoArg = + parser.getBooleanArgument(ARG_NAME_GET_EXTENDED_SCHEMA_INFO); + final boolean getExtendedSchemaInfo = + ((getExtendedSchemaInfoArg != null) && + getExtendedSchemaInfoArg.isPresent()); + + + try + { + // See if the schema entry DN was specified as an argument. If so, then + // retrieve that entry and parse it as a schema entry. Otherwise, use the + // default method for obtaining the schema. + final String schemaEntryDN; + final DNArgument schemaEntryDNArg = parser.getDNArgument(schemaDNArgName); + if (schemaEntryDNArg.isPresent()) + { + schemaEntryDN = schemaEntryDNArg.getStringValue(); + } + else + { + final RootDSE rootDSE = conn.getRootDSE(); + if (rootDSE == null) + { + throw new LDAPException(ResultCode.LOCAL_ERROR, + ERR_COMPARE_SCHEMA_CANNOT_GET_ROOT_DSE.get(serverLabel)); + } + + schemaEntryDN = rootDSE.getSubschemaSubentryDN(); + if (schemaEntryDN == null) + { + throw new LDAPException(ResultCode.LOCAL_ERROR, + ERR_COMPARE_SCHEMA_CANNOT_GET_ROOT_DSE_SCHEMA_DN.get(serverLabel, + RootDSE.ATTR_SUBSCHEMA_SUBENTRY)); + } + } + + final SearchRequest searchRequest = new SearchRequest(schemaEntryDN, + SearchScope.BASE, Schema.SUBSCHEMA_SUBENTRY_FILTER, + Schema.SCHEMA_REQUEST_ATTRS); + if (getExtendedSchemaInfo) + { + searchRequest.addControl(new ExtendedSchemaInfoRequestControl(false)); + } + + final Entry schemaEntry = conn.searchForEntry(searchRequest); + if (schemaEntry == null) + { + throw new LDAPException(ResultCode.NO_SUCH_OBJECT, + ERR_COMPARE_SCHEMA_CANNOT_GET_SCHEMA_ENTRY.get( + String.valueOf(schemaEntryDN), serverLabel)); + } + + return new Schema(schemaEntry, unparsableAttributeSyntaxes, + unparsableMatchingRules, unparsableAttributeTypes, + unparsableObjectClasses, unparsableDITContentRules, + unparsableDITStructureRules, unparsableNameForms, + unparsableMatchingRuleUses); + } + catch (final LDAPException e) + { + Debug.debugException(e); + throw new LDAPException(e.getResultCode(), + ERR_COMPARE_SCHEMA_CANNOT_GET_SCHEMA.get(serverLabel, + e.getMessage()), + e); + } + finally + { + conn.close(); + } + } + + + + /** + * Reports error messages about any unparsable elements found in a server's + * schema. + * + * @param serverLabel + * The label for the associated directory server instance. + * @param unparsableAttributeSyntaxes + * A map with information about any unparsable attribute syntax + * definitions found in the schema. + * @param unparsableMatchingRules + * A map with information about any unparsable matching rule + * definitions found in the schema. + * @param unparsableAttributeTypes + * A map with information about any unparsable attribute type + * definitions found in the schema. + * @param unparsableObjectClasses + * A map with information about any unparsable object class + * definitions found in the schema. + * @param unparsableDITContentRules + * A map with information about any unparsable DIT content rule + * definitions found in the schema. + * @param unparsableDITStructureRules + * A map with information about any unparsable DIT structure rule + * definitions found in the schema. + * @param unparsableNameForms + * A map with information about any unparsable name form + * definitions found in the schema. + * @param unparsableMatchingRuleUses + * A map with information about any unparsable matching rule use + * definitions found in the schema. + * + * @return {@code true} if the schema contained any unparsable elements, or + * {@code false} if not. + */ + private boolean reportUnparsableSchemaElements( + @NotNull final String serverLabel, + @NotNull final Map unparsableAttributeSyntaxes, + @NotNull final Map unparsableMatchingRules, + @NotNull final Map unparsableAttributeTypes, + @NotNull final Map unparsableObjectClasses, + @NotNull final Map unparsableDITContentRules, + @NotNull final Map unparsableDITStructureRules, + @NotNull final Map unparsableNameForms, + @NotNull final Map unparsableMatchingRuleUses) + { + boolean unparsableFound = false; + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAXES)) + { + unparsableFound |= reportUnparsableSchemaElements(serverLabel, + unparsableAttributeSyntaxes, + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAX.get()); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_MATCHING_RULES)) + { + unparsableFound |= reportUnparsableSchemaElements(serverLabel, + unparsableMatchingRules, + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE.get()); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPES)) + { + unparsableFound |= reportUnparsableSchemaElements(serverLabel, + unparsableAttributeTypes, + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get()); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_OBJECT_CLASSES)) + { + unparsableFound |= reportUnparsableSchemaElements(serverLabel, + unparsableObjectClasses, + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get()); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULES)) + { + unparsableFound |= reportUnparsableSchemaElements(serverLabel, + unparsableDITContentRules, + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get()); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULES)) + { + unparsableFound |= reportUnparsableSchemaElements(serverLabel, + unparsableDITStructureRules, + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULE.get()); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_NAME_FORMS)) + { + unparsableFound |= reportUnparsableSchemaElements(serverLabel, + unparsableNameForms, + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM.get()); + } + + if (schemaElementTypes.contains(SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USES)) + { + unparsableFound |= reportUnparsableSchemaElements(serverLabel, + unparsableMatchingRuleUses, + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USE.get()); + } + + return unparsableFound; + } + + + + /** + * Reports error messages about any unparsable elements of the specified type + * found in a server's schema. + * + * @param serverLabel The label for the associated directory server + * instance. It must not be {@code null}. + * @param unparsableElements The set of unparsable elements of a given type. + * It must not be {@code null}, but may be empty. + * @param elementTypeName The name of the schema element type. It must + * not be {@code null}. + * + * @return {@code true} if the provided map contained information about one + * or more unparsable elements, or {@code false} if not. + */ + private boolean reportUnparsableSchemaElements( + @NotNull final String serverLabel, + @NotNull final Map unparsableElements, + @NotNull final String elementTypeName) + { + for (final Map.Entry e : + unparsableElements.entrySet()) + { + wrapErr(0, WRAP_COLUMN, + ERR_COMPARE_SCHEMA_UNPARSABLE_ELEMENT.get(elementTypeName, + serverLabel, e.getValue().getMessage())); + err(e.getKey()); + err(); + } + + return (! unparsableElements.isEmpty()); + } + + + + /** + * Compares the attribute syntax definitions contained in the provided + * schemas. + * + * @param firstServerSchema The schema retrieved from the first server. It + * must not be {@code null}. + * @param secondServerSchema The schema retrieved from the second server. + * It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareAttributeSyntaxes( + @NotNull final Schema firstServerSchema, + @NotNull final Schema secondServerSchema, + @NotNull final AtomicInteger numDifferences) + { + // Get the attribute syntax definitions from each of the schemas. + final Map syntaxes1 = + getAttributeSyntaxMap(firstServerSchema); + final Map syntaxes2 = + getAttributeSyntaxMap(secondServerSchema); + + + // Identify syntaxes that exist in one server but not another. If any are + // found, then report them and remove them from the set. + Iterator> iterator = + syntaxes1.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! syntaxes2.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_SYNTAX.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + iterator = syntaxes2.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! syntaxes1.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_SYNTAX.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + + // Any remaining syntaxes should exist in both servers. Compare them and + // see if there are any differences between them. + for (final OID oid : syntaxes1.keySet()) + { + final AttributeSyntaxDefinition d1 = syntaxes1.get(oid); + final AttributeSyntaxDefinition d2 = syntaxes2.get(oid); + + if (! ignoreDescriptions) + { + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAX.get(), + oid.toString(), + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION.get(), + d1.getDescription(), d2.getDescription(), numDifferences); + } + + compareExtensions( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAX.get(), + oid.toString(), d1.getExtensions(), d2.getExtensions(), + numDifferences); + } + } + + + + /** + * Retrieves a map of the attribute syntax definitions contained in the + * provided schema, indexed by OID. + * + * @param schema The schema from which to retrieve the attribute syntaxes. + * It must not be {@code null}. + * + * @return A map of the attribute syntax definitions contained in the + * provided schema. + */ + @NotNull() + private Map getAttributeSyntaxMap( + @NotNull final Schema schema) + { + final Map syntaxes = new TreeMap<>(); + for (final AttributeSyntaxDefinition d : schema.getAttributeSyntaxes()) + { + if (includeBasedOnNameAndExtensions(StaticUtils.NO_STRINGS, + d.getExtensions())) + { + syntaxes.put(new OID(StaticUtils.toLowerCase(d.getOID())), d); + } + } + + return syntaxes; + } + + + + /** + * Compares the matching rule definitions contained in the provided schemas. + * + * @param firstServerSchema The schema retrieved from the first server. It + * must not be {@code null}. + * @param secondServerSchema The schema retrieved from the second server. + * It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareMatchingRules( + @NotNull final Schema firstServerSchema, + @NotNull final Schema secondServerSchema, + @NotNull final AtomicInteger numDifferences) + { + // Get the matching rule definitions from each of the schemas. + final Map matchingRules1 = + getMatchingRuleMap(firstServerSchema); + final Map matchingRules2 = + getMatchingRuleMap(secondServerSchema); + + + // Identify matching rules that exist in one server but not another. If any + // are found, then report them and remove them from the set. + Iterator> iterator = + matchingRules1.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! matchingRules2.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_MATCHING_RULE.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + iterator = matchingRules2.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! matchingRules1.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_MATCHING_RULE.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + + // Any remaining matching rules should exist in both servers. Compare them + // and see if there are any differences between them. + for (final OID oid : matchingRules1.keySet()) + { + final MatchingRuleDefinition d1 = matchingRules1.get(oid); + final MatchingRuleDefinition d2 = matchingRules2.get(oid); + + final String identifier = compareNames( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE.get(), + oid.toString(), d1.getNames(), d2.getNames(), numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SYNTAX_OID.get(), + d1.getSyntaxOID(), d2.getSyntaxOID(), numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_OBSOLETE.get(), + d1.isObsolete(), d2.isObsolete(), numDifferences); + + if (! ignoreDescriptions) + { + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION.get(), + d1.getDescription(), d2.getDescription(), numDifferences); + } + + compareExtensions( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAX.get(), + identifier, d1.getExtensions(), d2.getExtensions(), + numDifferences); + } + } + + + + /** + * Retrieves a map of the matching rule definitions contained in the provided + * schema, indexed by OID. + * + * @param schema The schema from which to retrieve the matching rules. It + * must not be {@code null}. + * + * @return A map of the matching rule definitions contained in the provided + * schema. + */ + @NotNull() + private Map getMatchingRuleMap( + @NotNull final Schema schema) + { + final Map matchingRules = new TreeMap<>(); + for (final MatchingRuleDefinition d : schema.getMatchingRules()) + { + if (includeBasedOnNameAndExtensions(d.getNames(), d.getExtensions())) + { + matchingRules.put(new OID(StaticUtils.toLowerCase(d.getOID())), d); + } + } + + return matchingRules; + } + + + + /** + * Compares the attribute type definitions contained in the provided schemas. + * + * @param firstServerSchema The schema retrieved from the first server. It + * must not be {@code null}. + * @param secondServerSchema The schema retrieved from the second server. + * It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareAttributeTypes( + @NotNull final Schema firstServerSchema, + @NotNull final Schema secondServerSchema, + @NotNull final AtomicInteger numDifferences) + { + // Get the attribute type definitions from each of the schemas. + final Map attributeTypes1 = + getAttributeTypeMap(firstServerSchema); + final Map attributeTypes2 = + getAttributeTypeMap(secondServerSchema); + + + // Identify attribute types that exist in one server but not another. If + // any are found, then report them and remove them from the set. + Iterator> iterator = + attributeTypes1.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! attributeTypes2.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_ATTRIBUTE_TYPE.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + iterator = attributeTypes2.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! attributeTypes1.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_ATTRIBUTE_TYPE.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + + // Any remaining attribute types should exist in both servers. Compare them + // and see if there are any differences between them. + for (final OID oid : attributeTypes1.keySet()) + { + final AttributeTypeDefinition d1 = attributeTypes1.get(oid); + final AttributeTypeDefinition d2 = attributeTypes2.get(oid); + + final String identifier = compareNames( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), + oid.toString(), d1.getNames(), d2.getNames(), numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SUPERIOR_TYPE.get(), + d1.getSuperiorType(), d2.getSuperiorType(), numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SYNTAX_OID.get(), + d1.getSyntaxOID(), d2.getSyntaxOID(), numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_EQUALITY_MR.get(), + d1.getEqualityMatchingRule(), d2.getEqualityMatchingRule(), + numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_ORDERING_MR.get(), + d1.getOrderingMatchingRule(), d2.getOrderingMatchingRule(), + numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SUBSTRING_MR.get(), + d1.getSubstringMatchingRule(), d2.getSubstringMatchingRule(), + numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_SINGLE_VALUE.get(), + d1.isSingleValued(), d2.isSingleValued(), numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_USAGE.get(), + d1.getUsage().getName(), d2.getUsage().getName(), + numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_NO_USER_MOD.get(), + d1.isNoUserModification(), d2.isNoUserModification(), + numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_COLLECTIVE.get(), + d1.isCollective(), d2.isCollective(), numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_OBSOLETE.get(), + d1.isObsolete(), d2.isObsolete(), numDifferences); + + if (! ignoreDescriptions) + { + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_TYPE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION.get(), + d1.getDescription(), d2.getDescription(), numDifferences); + } + + compareExtensions( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_ATTRIBUTE_SYNTAX.get(), + identifier, d1.getExtensions(), d2.getExtensions(), + numDifferences); + } + } + + + + /** + * Retrieves a map of the attribute type definitions contained in the provided + * schema, indexed by OID. + * + * @param schema The schema from which to retrieve the attribute types. It + * must not be {@code null}. + * + * @return A map of the attribute type definitions contained in the provided + * schema. + */ + @NotNull() + private Map getAttributeTypeMap( + @NotNull final Schema schema) + { + final Map attributeTypes = new TreeMap<>(); + for (final AttributeTypeDefinition d : schema.getAttributeTypes()) + { + if (includeBasedOnNameAndExtensions(d.getNames(), d.getExtensions())) + { + attributeTypes.put(new OID(StaticUtils.toLowerCase(d.getOID())), d); + } + } + + return attributeTypes; + } + + + + /** + * Compares the object class definitions contained in the provided schemas. + * + * @param firstServerSchema The schema retrieved from the first server. It + * must not be {@code null}. + * @param secondServerSchema The schema retrieved from the second server. + * It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareObjectClasses( + @NotNull final Schema firstServerSchema, + @NotNull final Schema secondServerSchema, + @NotNull final AtomicInteger numDifferences) + { + // Get the object class definitions from each of the schemas. + final Map objectClasses1 = + getObjectClassMap(firstServerSchema); + final Map objectClasses2 = + getObjectClassMap(secondServerSchema); + + + // Identify object classes that exist in one server but not another. If + // any are found, then report them and remove them from the set. + Iterator> iterator = + objectClasses1.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! objectClasses2.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_OBJECT_CLASS.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + iterator = objectClasses2.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! objectClasses1.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_OBJECT_CLASS.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + + // Any remaining object classes should exist in both servers. Compare them + // and see if there are any differences between them. + for (final OID oid : objectClasses1.keySet()) + { + final ObjectClassDefinition d1 = objectClasses1.get(oid); + final ObjectClassDefinition d2 = objectClasses2.get(oid); + + final String identifier = compareNames( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get(), + oid.toString(), d1.getNames(), d2.getNames(), numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SUPERIOR_TYPE.get(), + d1.getSuperiorClasses(), d2.getSuperiorClasses(), numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_REQUIRED_ATTRIBUTE.get(), + d1.getRequiredAttributes(), d2.getRequiredAttributes(), + numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_OPTIONAL_ATTRIBUTE.get(), + d1.getOptionalAttributes(), d2.getOptionalAttributes(), + numDifferences); + + final String oc1Type = (d1.getObjectClassType() == null) + ? null + : d1.getObjectClassType().getName(); + final String oc2Type = (d2.getObjectClassType() == null) + ? null + : d2.getObjectClassType().getName(); + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_OBJECT_CLASS_TYPE.get(), + oc1Type, oc2Type, numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_OBSOLETE.get(), + d1.isObsolete(), d2.isObsolete(), numDifferences); + + if (! ignoreDescriptions) + { + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION.get(), + d1.getDescription(), d2.getDescription(), numDifferences); + } + + compareExtensions( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_OBJECT_CLASS.get(), + identifier, d1.getExtensions(), d2.getExtensions(), + numDifferences); + } + } + + + + /** + * Retrieves a map of the object class definitions contained in the provided + * schema, indexed by OID. + * + * @param schema The schema from which to retrieve the object classes. It + * must not be {@code null}. + * + * @return A map of the object class definitions contained in the provided + * schema. + */ + @NotNull() + private Map getObjectClassMap( + @NotNull final Schema schema) + { + final Map objectClasses = new TreeMap<>(); + for (final ObjectClassDefinition d : schema.getObjectClasses()) + { + if (includeBasedOnNameAndExtensions(d.getNames(), d.getExtensions())) + { + objectClasses.put(new OID(StaticUtils.toLowerCase(d.getOID())), d); + } + } + + return objectClasses; + } + + + + /** + * Compares the DIT content rule definitions contained in the provided + * schemas. + * + * @param firstServerSchema The schema retrieved from the first server. It + * must not be {@code null}. + * @param secondServerSchema The schema retrieved from the second server. + * It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareDITContentRules( + @NotNull final Schema firstServerSchema, + @NotNull final Schema secondServerSchema, + @NotNull final AtomicInteger numDifferences) + { + // Get the DIT content rule definitions from each of the schemas. + final Map ditContentRules1 = + getDITContentRuleMap(firstServerSchema); + final Map ditContentRules2 = + getDITContentRuleMap(secondServerSchema); + + + // Identify DIT content rules that exist in one server but not another. If + // any are found, then report them and remove them from the set. + Iterator> iterator = + ditContentRules1.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! ditContentRules2.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_DIT_CONTENT_RULE.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + iterator = ditContentRules2.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! ditContentRules1.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_DIT_CONTENT_RULE.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + + // Any remaining DIT content rules should exist in both servers. Compare + // them and see if there are any differences between them. + for (final OID oid : ditContentRules1.keySet()) + { + final DITContentRuleDefinition d1 = ditContentRules1.get(oid); + final DITContentRuleDefinition d2 = ditContentRules2.get(oid); + + final String identifier = compareNames( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get(), + oid.toString(), d1.getNames(), d2.getNames(), numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_REQUIRED_ATTRIBUTE.get(), + d1.getRequiredAttributes(), d2.getRequiredAttributes(), + numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_OPTIONAL_ATTRIBUTE.get(), + d1.getOptionalAttributes(), d2.getOptionalAttributes(), + numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_PROHIBITED_ATTRIBUTE.get(), + d1.getProhibitedAttributes(), d2.getProhibitedAttributes(), + numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_AUXILIARY_CLASS.get(), + d1.getAuxiliaryClasses(), d2.getAuxiliaryClasses(), numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_OBSOLETE.get(), + d1.isObsolete(), d2.isObsolete(), numDifferences); + + if (! ignoreDescriptions) + { + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get(), + identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION.get(), + d1.getDescription(), d2.getDescription(), numDifferences); + } + + compareExtensions( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_CONTENT_RULE.get(), + identifier, d1.getExtensions(), d2.getExtensions(), + numDifferences); + } + } + + + + /** + * Retrieves a map of the DIT content rule definitions contained in the + * provided schema, indexed by OID. + * + * @param schema The schema from which to retrieve the DIT content rules. + * It must not be {@code null}. + * + * @return A map of the DIT content rule definitions contained in the + * provided schema. + */ + @NotNull() + private Map getDITContentRuleMap( + @NotNull final Schema schema) + { + final Map ditContentRules = new TreeMap<>(); + for (final DITContentRuleDefinition d : schema.getDITContentRules()) + { + if (includeBasedOnNameAndExtensions(d.getNames(), d.getExtensions())) + { + ditContentRules.put(new OID(StaticUtils.toLowerCase(d.getOID())), d); + } + } + + return ditContentRules; + } + + + + /** + * Compares the DIT structure rule definitions contained in the provided + * schemas. + * + * @param firstServerSchema The schema retrieved from the first server. It + * must not be {@code null}. + * @param secondServerSchema The schema retrieved from the second server. + * It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareDITStructureRules( + @NotNull final Schema firstServerSchema, + @NotNull final Schema secondServerSchema, + @NotNull final AtomicInteger numDifferences) + { + // Get the DIT structure rule definitions from each of the schemas. + final Map ditStructureRules1 = + getDITStructureRuleMap(firstServerSchema); + final Map ditStructureRules2 = + getDITStructureRuleMap(secondServerSchema); + + + // Identify DIT structure rules that exist in one server but not another. + // If any are found, then report them and remove them from the set. + Iterator> iterator = + ditStructureRules1.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final Integer id = e.getKey(); + if (! ditStructureRules2.containsKey(id)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_DIT_STRUCTURE_RULE.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + iterator = ditStructureRules2.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final Integer oid = e.getKey(); + if (! ditStructureRules1.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_DIT_STRUCTURE_RULE.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + + // Any remaining DIT structure rules should exist in both servers. Compare + // them and see if there are any differences between them. + for (final Integer id : ditStructureRules1.keySet()) + { + final DITStructureRuleDefinition d1 = ditStructureRules1.get(id); + final DITStructureRuleDefinition d2 = ditStructureRules2.get(id); + + final String identifier = compareNames( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULE.get(), + id.toString(), d1.getNames(), d2.getNames(), numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULE.get(), + identifier, INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_NAME_FORM.get(), + d1.getNameFormID(), d2.getNameFormID(), numDifferences); + + final String[] superiorRuleIDs1 = + intArrayToStringArray(d1.getSuperiorRuleIDs()); + final String[] superiorRuleIDs2 = + intArrayToStringArray(d2.getSuperiorRuleIDs()); + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULE.get(), + identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_SUPERIOR_RULE_ID.get(), + superiorRuleIDs1, superiorRuleIDs2, numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULE.get(), + identifier, INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_OBSOLETE.get(), + d1.isObsolete(), d2.isObsolete(), numDifferences); + + if (! ignoreDescriptions) + { + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULE.get(), + identifier, INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION.get(), + d1.getDescription(), d2.getDescription(), numDifferences); + } + + compareExtensions( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_DIT_STRUCTURE_RULE.get(), + identifier, d1.getExtensions(), d2.getExtensions(), + numDifferences); + } + } + + + + /** + * Retrieves a map of the DIT structure rule definitions contained in the + * provided schema, indexed by rule ID. + * + * @param schema The schema from which to retrieve the DIT structure rules. + * It must not be {@code null}. + * + * @return A map of the DIT structure rule definitions contained in the + * provided schema. + */ + @NotNull() + private Map getDITStructureRuleMap( + @NotNull final Schema schema) + { + final Map ditStructureRules = + new TreeMap<>(); + for (final DITStructureRuleDefinition d : schema.getDITStructureRules()) + { + if (includeBasedOnNameAndExtensions(StaticUtils.NO_STRINGS, + d.getExtensions())) + { + ditStructureRules.put(d.getRuleID(), d); + } + } + + return ditStructureRules; + } + + + + /** + * Converts the provided integer array to a string array in which each element + * is the string representation of the corresponding element in the provided + * integer array. + * + * @param intArray The integer array to convert to a string array. It must + * not be {@code null}, but may be empty. + * + * @return A string array in which each element is the string representation + * of the corresponding element in the provided integer array. + */ + @NotNull() + private static String[] intArrayToStringArray(@NotNull final int[] intArray) + { + final String[] stringArray = new String[intArray.length]; + for (int i=0; i < intArray.length; i++) + { + stringArray[i] = String.valueOf(intArray[i]); + } + + return stringArray; + } + + + + /** + * Compares the name form definitions contained in the provided schemas. + * + * @param firstServerSchema The schema retrieved from the first server. It + * must not be {@code null}. + * @param secondServerSchema The schema retrieved from the second server. + * It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareNameForms( + @NotNull final Schema firstServerSchema, + @NotNull final Schema secondServerSchema, + @NotNull final AtomicInteger numDifferences) + { + // Get the name form definitions from each of the schemas. + final Map nameForms1 = + getNameFormMap(firstServerSchema); + final Map nameForms2 = + getNameFormMap(secondServerSchema); + + + // Identify name forms that exist in one server but not another. If + // any are found, then report them and remove them from the set. + Iterator> iterator = + nameForms1.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! nameForms2.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_NAME_FORM.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + iterator = nameForms2.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! nameForms1.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_NAME_FORM.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + + // Any remaining name forms should exist in both servers. Compare them and + // see if there are any differences between them. + for (final OID oid : nameForms1.keySet()) + { + final NameFormDefinition d1 = nameForms1.get(oid); + final NameFormDefinition d2 = nameForms2.get(oid); + + final String identifier = compareNames( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM.get(), + oid.toString(), d1.getNames(), d2.getNames(), numDifferences); + + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_STRUCTURAL_CLASS.get(), + d1.getStructuralClass(), d2.getStructuralClass(), numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_REQUIRED_ATTRIBUTE.get(), + d1.getRequiredAttributes(), d2.getRequiredAttributes(), + numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_OPTIONAL_ATTRIBUTE.get(), + d1.getOptionalAttributes(), d2.getOptionalAttributes(), + numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_OBSOLETE.get(), + d1.isObsolete(), d2.isObsolete(), numDifferences); + + if (! ignoreDescriptions) + { + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION.get(), + d1.getDescription(), d2.getDescription(), numDifferences); + } + + compareExtensions( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_NAME_FORM.get(), + identifier, d1.getExtensions(), d2.getExtensions(), + numDifferences); + } + } + + + + /** + * Retrieves a map of the name form definitions contained in the provided + * schema, indexed by OID. + * + * @param schema The schema from which to retrieve the name forms. It must + * not be {@code null}. + * + * @return A map of the name form definitions contained in the provided + * schema. + */ + @NotNull() + private Map getNameFormMap( + @NotNull final Schema schema) + { + final Map nameForms = new TreeMap<>(); + for (final NameFormDefinition d : schema.getNameForms()) + { + if (includeBasedOnNameAndExtensions(d.getNames(), d.getExtensions())) + { + nameForms.put(new OID(StaticUtils.toLowerCase(d.getOID())), d); + } + } + + return nameForms; + } + + + + /** + * Compares the matching rule use definitions contained in the provided + * schemas. + * + * @param firstServerSchema The schema retrieved from the first server. It + * must not be {@code null}. + * @param secondServerSchema The schema retrieved from the second server. + * It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareMatchingRuleUses( + @NotNull final Schema firstServerSchema, + @NotNull final Schema secondServerSchema, + @NotNull final AtomicInteger numDifferences) + { + // Get the matching rule use definitions from each of the schemas. + final Map matchingRuleUses1 = + getMatchingRuleUseMap(firstServerSchema); + final Map matchingRuleUses2 = + getMatchingRuleUseMap(secondServerSchema); + + + // Identify matching rule uses that exist in one server but not another. If + // any are found, then report them and remove them from the set. + Iterator> iterator = + matchingRuleUses1.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! matchingRuleUses2.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_MATCHING_RULE_USE.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + iterator = matchingRuleUses2.entrySet().iterator(); + while (iterator.hasNext()) + { + final Map.Entry e = iterator.next(); + final OID oid = e.getKey(); + if (! matchingRuleUses1.containsKey(oid)) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_MATCHING_RULE_USE.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences, + e.getValue().toString()); + iterator.remove(); + } + } + + + // Any remaining matching rule uses should exist in both servers. Compare + // them and see if there are any differences between them. + for (final OID oid : matchingRuleUses1.keySet()) + { + final MatchingRuleUseDefinition d1 = matchingRuleUses1.get(oid); + final MatchingRuleUseDefinition d2 = matchingRuleUses2.get(oid); + + final String identifier = compareNames( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USE.get(), + oid.toString(), d1.getNames(), d2.getNames(), numDifferences); + + compareStringArrayValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_APPLICABLE_ATTRIBUTE.get(), + d1.getApplicableAttributeTypes(), d2.getApplicableAttributeTypes(), + numDifferences); + + compareBooleanValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USE.get(), identifier, + INFO_COMPARE_SCHEMA_BOOLEAN_FIELD_NAME_OBSOLETE.get(), + d1.isObsolete(), d2.isObsolete(), numDifferences); + + if (! ignoreDescriptions) + { + compareStringValues( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USE.get(), identifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_DESCRIPTION.get(), + d1.getDescription(), d2.getDescription(), numDifferences); + } + + compareExtensions( + INFO_COMPARE_SCHEMA_ELEMENT_TYPE_MATCHING_RULE_USE.get(), + identifier, d1.getExtensions(), d2.getExtensions(), + numDifferences); + } + } + + + + /** + * Retrieves a map of the matching rule use definitions contained in the + * provided schema, indexed by OID. + * + * @param schema The schema from which to retrieve the matching rule uses. + * It must not be {@code null}. + * + * @return A map of the matching rule use definitions contained in the + * provided schema. + */ + @NotNull() + private Map getMatchingRuleUseMap( + @NotNull final Schema schema) + { + final Map matchingRuleUses = new TreeMap<>(); + for (final MatchingRuleUseDefinition d : schema.getMatchingRuleUses()) + { + if (includeBasedOnNameAndExtensions(d.getNames(), d.getExtensions())) + { + matchingRuleUses.put(new OID(StaticUtils.toLowerCase(d.getOID())), d); + } + } + + return matchingRuleUses; + } + + + + /** + * Indicates whether to include a schema element with the given name and set + * of extensions. + * + * @param names The set of names for the schema element. It must not + * be {@code null}, but may be empty. + * @param extensions The set of extensions for the schema element. It must + * not be {@code null}, but may be empty. + * + * @return {@code true} if an element with the given names and set of + * extensions should be included, or {@code false} if not. + */ + private boolean includeBasedOnNameAndExtensions( + @NotNull final String[] names, + @NotNull final Map extensions) + { + if (includeOrExcludeBasedOnName && (names.length > 0)) + { + boolean includeFound = false; + for (final String name : names) + { + final String lowerName = StaticUtils.toLowerCase(name); + for (final String excludePrefix : excludeNamePrefixes) + { + if (lowerName.startsWith(excludePrefix)) + { + return false; + } + } + + if (! includeNamePrefixes.isEmpty()) + { + for (final String includePrefix : includeNamePrefixes) + { + if (lowerName.startsWith(includePrefix)) + { + includeFound = true; + break; + } + } + } + } + + if ((! includeNamePrefixes.isEmpty()) && (! includeFound)) + { + return false; + } + } + + + if (includeOrExcludeBasedOnExtensions && (! extensions.isEmpty())) + { + boolean includeFound = false; + for (final Map.Entry e : extensions.entrySet()) + { + final String lowerName = StaticUtils.toLowerCase(e.getKey()); + final String[] values = e.getValue(); + final String[] lowerValues = new String[values.length]; + for (int i=0; i < values.length; i++) + { + lowerValues[i] = StaticUtils.toLowerCase(values[i]); + } + + final List excludeValues = + excludeExtensionValues.get(lowerName); + if (excludeValues != null) + { + for (final String lowerValue : lowerValues) + { + if (excludeValues.contains(lowerValue)) + { + return false; + } + } + } + + final List includeValues = + includeExtensionValues.get(lowerName); + if (includeValues != null) + { + for (final String lowerValue : lowerValues) + { + if (includeValues.contains(lowerValue)) + { + includeFound = true; + break; + } + } + } + } + + if ((! includeExtensionValues.isEmpty()) && (! includeFound)) + { + return false; + } + } + + + return true; + } + + + + /** + * Reports a difference between schema elements. + * + * @param message The message to display with information about + * the difference. It must not be {@code null}. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + * @param additionalStrings A set of additional strings that should also be + * displayed, in addition to the provided message. + * Each additional string will be presented on its + * own line without any wrapping. It must not be + * {@code null}, but may be empty. + */ + private void reportDifference(@NotNull final String message, + @NotNull final AtomicInteger numDifferences, + @NotNull final String... additionalStrings) + { + wrapErr(0, WRAP_COLUMN, message); + for (final String additionalString : additionalStrings) + { + err(additionalString); + } + err(); + numDifferences.incrementAndGet(); + } + + + + /** + * Identifies differences between string values for two schema elements. + * + * @param elementTypeName A name for the type of schema element being + * compared. It must not be {@code null}. + * @param elementIdentifier An identifier (e.g., the name or OID) for the + * schema element for which to make the + * determination. It must not be {@code null}. + * @param stringDescriptor A descriptor for the string values being + * compared. + * @param string1 The string value from the first schema element. + * It may be {@code null} if the element does not + * contain a value for the associated field. + * @param string2 The string value from the first second element. + * It may be {@code null} if the element does not + * contain a value for the associated field. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareStringValues(@NotNull final String elementTypeName, + @NotNull final String elementIdentifier, + @NotNull final String stringDescriptor, + @Nullable final String string1, + @Nullable final String string2, + @NotNull final AtomicInteger numDifferences) + { + if (string1 == null) + { + if (string2 != null) + { + reportDifference( + WARN_COMPARE_SCHEMA_STRING_MISSING_FROM_SERVER.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + elementTypeName, elementIdentifier, stringDescriptor, + string2, INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences); + } + } + else if (string2 == null) + { + reportDifference( + WARN_COMPARE_SCHEMA_STRING_MISSING_FROM_SERVER.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + elementTypeName, elementIdentifier, stringDescriptor, + string1, INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences); + } + else if (! string1.equalsIgnoreCase(string2)) + { + reportDifference( + WARN_COMPARE_SCHEMA_STRING_DIFFERENT_BETWEEN_SERVERS.get( + elementTypeName, elementIdentifier, stringDescriptor, string1, + string2), + numDifferences); + } + } + + + + /** + * Identifies differences between the sets of string arrays for two schema + * elements. + * + * @param elementTypeName A name for the type of schema element being + * compared. It must not be {@code null}. + * @param elementIdentifier An identifier (e.g., the name or OID) for the + * schema element for which to make the + * determination. It must not be {@code null}. + * @param stringDescriptor A descriptor for the string values being + * compared. + * @param array1 The array of values for the target field from + * the element in the first schema. It must not be + * {@code null}, but may be empty. + * @param array2 The array of values for the target field from + * the element in the second schema. It must not + * be {@code null}, but may be empty. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareStringArrayValues( + @NotNull final String elementTypeName, + @NotNull final String elementIdentifier, + @NotNull final String stringDescriptor, + @NotNull final String[] array1, + @NotNull final String[] array2, + @NotNull final AtomicInteger numDifferences) + { + if (array1.length == 0) + { + switch (array2.length) + { + case 0: + // The element doesn't have any names in either of the servers, so + // there is no difference. + break; + case 1: + // The element has names in the second server, but not in the first. + reportDifference( + WARN_COMPARE_SCHEMA_STRING_ARRAY_SINGLE_IN_ONLY_ONE_SERVER.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + elementTypeName, elementIdentifier, stringDescriptor, + array2[0], INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences); + break; + default: + reportDifference( + WARN_COMPARE_SCHEMA_STRING_ARRAY_MULTIPLE_IN_ONLY_ONE_SERVER.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + elementTypeName, elementIdentifier, stringDescriptor, + Arrays.toString(array2), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences); + break; + } + } + else if (array2.length == 0) + { + // The element has names in the first server, but not in the second. + if (array1.length == 1) + { + reportDifference( + WARN_COMPARE_SCHEMA_STRING_ARRAY_SINGLE_IN_ONLY_ONE_SERVER.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + elementTypeName, elementIdentifier, stringDescriptor, + array1[0], INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences); + } + else + { + reportDifference( + WARN_COMPARE_SCHEMA_STRING_ARRAY_MULTIPLE_IN_ONLY_ONE_SERVER.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + elementTypeName, elementIdentifier, stringDescriptor, + Arrays.toString(array1), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences); + } + } + else + { + // The element has names in both servers. See if there are any + // differences between them. + final Map n1 = getNameMap(array1); + final Map n2 = getNameMap(array2); + for (final Map.Entry e : n1.entrySet()) + { + final String lowerName = e.getKey(); + if (n2.remove(lowerName) == null) + { + reportDifference( + WARN_COMPARE_SCHEMA_STRING_ARRAY_VALUE_MISSING_FROM_SERVER.get( + elementTypeName, elementIdentifier, stringDescriptor, + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + e.getValue(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences); + } + } + + for (final String nameOnlyInServer2 : n2.values()) + { + reportDifference( + WARN_COMPARE_SCHEMA_STRING_ARRAY_VALUE_MISSING_FROM_SERVER.get( + elementTypeName, elementIdentifier, stringDescriptor, + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + nameOnlyInServer2, + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences); + } + } + } + + + + /** + * Identifies differences between the sets of names for two schema elements. + * + * @param elementTypeName A name for the type of schema element being + * compared. It must not be {@code null}. + * @param elementIdentifier An identifier (e.g., the name or OID) for the + * schema element for which to make the + * determination. It must not be {@code null}. + * @param names1 The set of names for the element from the first + * schema. It must not be {@code null}, but may be + * empty. + * @param names2 The set of names for the element from the second + * schema. It must not be {@code null}, but may be + * empty. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + * + * @return The identifier string that should be used to identify the + * associated schema element. If both sets of names are non-empty + * and have the same first element, then that name will be used as + * the identifier. Otherwise, the provided identifier will be used. + */ + @NotNull() + private String compareNames(@NotNull final String elementTypeName, + @NotNull final String elementIdentifier, + @NotNull final String[] names1, + @NotNull final String[] names2, + @NotNull final AtomicInteger numDifferences) + { + compareStringArrayValues(elementTypeName, elementIdentifier, + INFO_COMPARE_SCHEMA_STRING_DESCRIPTOR_NAME.get(), names1, names2, + numDifferences); + + + // Identify the best identifier to use for the schema element going forward. + if ((names1.length > 0) && (names2.length > 0) && + (names1[0].equalsIgnoreCase(names2[0]))) + { + return names1[0]; + } + else + { + return elementIdentifier; + } + } + + + + /** + * Identifies difference between boolean values for two schema elements. + * + * @param elementTypeName A name for the type of schema element being + * compared. It must not be {@code null}. + * @param elementIdentifier An identifier (e.g., the name or OID) for the + * schema element for which to make the + * determination. It must not be {@code null}. + * @param booleanFieldName The name of the Boolean field being compared. + * @param value1 The Boolean value from the first schema element. + * @param value2 The Boolean value from the second schema + * element. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareBooleanValues(@NotNull final String elementTypeName, + @NotNull final String elementIdentifier, + @NotNull final String booleanFieldName, + final boolean value1, + final boolean value2, + @NotNull final AtomicInteger numDifferences) + { + if (value1 != value2) + { + if (value1) + { + reportDifference( + WARN_COMPARE_SCHEMA_BOOLEAN_DIFFERENCE.get( + elementTypeName, elementIdentifier, booleanFieldName, + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences); + } + else + { + reportDifference( + WARN_COMPARE_SCHEMA_BOOLEAN_DIFFERENCE.get( + elementTypeName, elementIdentifier, booleanFieldName, + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences); + } + } + } + + + + /** + * Identifies differences between the sets of extensions for two schema + * elements. + * + * @param elementTypeName A name for the type of schema element being + * compared. It must not be {@code null}. + * @param elementIdentifier An identifier (e.g., the name or OID) for the + * schema element for which to make the + * determination. It must not be {@code null}. + * @param extensions1 The set of extensions for the element from the + * first schema. It must not be {@code null}, but + * may be empty. + * @param extensions2 The set of extensions for the element from the + * second schema. It must not be {@code null}, but + * may be empty. + * @param numDifferences A counter used to keep track of the number of + * differences found between the schemas. It must + * not be {@code null}. + */ + private void compareExtensions( + @NotNull final String elementTypeName, + @NotNull final String elementIdentifier, + @NotNull final Map extensions1, + @NotNull final Map extensions2, + @NotNull final AtomicInteger numDifferences) + { + if (ignoreExtensions) + { + return; + } + + + // Convert the extensions into a map of sets so that we can alter the + // contents of both the map and its sets. + final Map> e1 = + convertToUpdatableExtensionsMap(extensions1); + final Map> e2 = + convertToUpdatableExtensionsMap(extensions2); + + + // Iterate through the extensions and identify differences between them. + for (final Map.Entry> e : e1.entrySet()) + { + final String extensionName = e.getKey(); + final Set extension1Values = e.getValue(); + final Set extension2Values = e2.remove(extensionName); + if (extension2Values == null) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_EXTENSION.get( + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get(), + elementTypeName, elementIdentifier, extensionName, + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get()), + numDifferences); + } + else if (! extension1Values.equals(extension2Values)) + { + reportDifference( + WARN_COMPARE_SCHEMA_EXTENSION_DIFFERENCE.get( + elementTypeName, elementIdentifier, extensionName), + numDifferences); + } + } + + for (final String extensionName : e2.keySet()) + { + reportDifference( + WARN_COMPARE_SCHEMA_MISSING_EXTENSION.get( + INFO_COMPARE_SCHEMA_SECOND_SERVER_LABEL.get(), + elementTypeName, elementIdentifier, extensionName, + INFO_COMPARE_SCHEMA_FIRST_SERVER_LABEL.get()), + numDifferences); + } + } + + + + /** + * Converts the provided extensions map into an updatable map that associates + * each extension name key with a modifiable set of values rather than an + * array. In addition, all strings will be converted to lowercase for more + * efficient case-insensitive comparison. + * + * @param extensionsMap The map to be converted. It must not be + * {@code null}, but may be empty. + * + * @return A modifiable map that contains the information in the provided map + * in a form that is better suited for comparing extensions between + * two definitions. + */ + @NotNull() + private static Map> convertToUpdatableExtensionsMap( + @NotNull final Map extensionsMap) + { + final Map> convertedExtensionsMap = new TreeMap<>(); + for (final Map.Entry e : extensionsMap.entrySet()) + { + final String lowerExtensionName = StaticUtils.toLowerCase(e.getKey()); + final Set lowerExtensionValues = new TreeSet<>(); + for (final String extensionValue : e.getValue()) + { + lowerExtensionValues.add(StaticUtils.toLowerCase(extensionValue)); + } + + convertedExtensionsMap.put(lowerExtensionName, lowerExtensionValues); + } + + return convertedExtensionsMap; + } + + + + /** + * Retrieves a modifiable map containing the provided names. The key for each + * entry in the map will be the name in all lowercase, and the value will be + * the name in the case in which it is provided. + * + * @param names The names to include in the resulting map. It must not be + * {@code null}. + * + * @return A modifiable map containing the provided names. + */ + @NotNull() + private static Map getNameMap(@NotNull final String[] names) + { + final Map m = new TreeMap<>(); + for (final String name : names) + { + m.put(StaticUtils.toLowerCase(name), name); + } + + return m; + } + + + + /** + * Logs the provided message to standard error and sets it as the tool + * completion message. + * + * @param message The completion message. It must not be {@code null}. + */ + private void logCompletionError(@NotNull final String message) + { + completionMessageRef.compareAndSet(null, message); + wrapErr(0, WRAP_COLUMN, message); + } + + + + /** + * {@inheritDoc} + */ + @Override() + @NotNull() + public LinkedHashMap getExampleUsages() + { + final LinkedHashMap examples = new LinkedHashMap<>(); + + examples.put( + new String[] + { + "--firstHostname", "ds1.example.com", + "--firstPort", "636", + "--firstUseSSL", + "--firstBindDN", "cn=Directory Manager", + "--firstBindPasswordFile", "/path/to/password.txt", + "--secondHostname", "ds2.example.com", + "--secondPort", "636", + "--secondUseSSL", + "--secondBindDN", "cn=Directory Manager", + "--secondBindPasswordFile", "/path/to/password.txt" + }, + INFO_COMPARE_LDAP_SCHEMAS_EXAMPLE.get()); + + return examples; + } +} diff --git a/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/LauncherTestCase.java b/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/LauncherTestCase.java index 727d1121a..4e6fe8e2e 100644 --- a/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/LauncherTestCase.java +++ b/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/LauncherTestCase.java @@ -141,6 +141,7 @@ public Object[][] getValidToolNames() new Object[] { "authrate" }, new Object[] { "base64" }, new Object[] { "collect-support-data" }, + new Object[] { "compare-ldap-schemas" }, new Object[] { "deliver-one-time-password" }, new Object[] { "deliver-password-reset-token" }, new Object[] { "dump-dns" }, diff --git a/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/CompareLDAPSchemasTestCase.java b/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/CompareLDAPSchemasTestCase.java new file mode 100644 index 000000000..8c90c8045 --- /dev/null +++ b/tests/unit/src/com/unboundid/ldap/sdk/unboundidds/tools/CompareLDAPSchemasTestCase.java @@ -0,0 +1,8467 @@ +/* + * Copyright 2024 Ping Identity Corporation + * All Rights Reserved. + */ +/* + * Copyright 2024 Ping Identity Corporation + * + * 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. + */ +/* + * Copyright (C) 2024 Ping Identity Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (GPLv2 only) + * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +package com.unboundid.ldap.sdk.unboundidds.tools; + + + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.testng.annotations.Test; + +import com.unboundid.ldap.listener.InMemoryDirectoryServer; +import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; +import com.unboundid.ldap.sdk.Attribute; +import com.unboundid.ldap.sdk.DN; +import com.unboundid.ldap.sdk.Entry; +import com.unboundid.ldap.sdk.LDAPSDKTestCase; +import com.unboundid.ldap.sdk.OperationType; +import com.unboundid.ldap.sdk.ReadOnlyEntry; +import com.unboundid.ldap.sdk.ResultCode; +import com.unboundid.ldap.sdk.schema.AttributeSyntaxDefinition; +import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; +import com.unboundid.ldap.sdk.schema.AttributeUsage; +import com.unboundid.ldap.sdk.schema.DITContentRuleDefinition; +import com.unboundid.ldap.sdk.schema.DITStructureRuleDefinition; +import com.unboundid.ldap.sdk.schema.MatchingRuleDefinition; +import com.unboundid.ldap.sdk.schema.MatchingRuleUseDefinition; +import com.unboundid.ldap.sdk.schema.NameFormDefinition; +import com.unboundid.ldap.sdk.schema.ObjectClassDefinition; +import com.unboundid.ldap.sdk.schema.ObjectClassType; +import com.unboundid.ldap.sdk.schema.Schema; +import com.unboundid.util.StaticUtils; + + + +/** + * This class provides a set of test cases for the {@code compare-ldap-schemas} + * tool. + */ +public final class CompareLDAPSchemasTestCase + extends LDAPSDKTestCase +{ + /** + * A precomputed entry with the default content for custom schema. + */ + private static final ReadOnlyEntry DEFAULT_CUSTOM_SCHEMA_ENTRY; + static + { + ReadOnlyEntry schemaEntry = null; + try + { + final Entry e = + Schema.getDefaultStandardSchema().getSchemaEntry().duplicate(); + e.setDN(new DN(e.getRDN(), new DN("dc=example,dc=com"))); + schemaEntry = new ReadOnlyEntry(e); + } + catch (final Exception e) + { + throw new RuntimeException(e); + } + finally + { + DEFAULT_CUSTOM_SCHEMA_ENTRY = schemaEntry; + } + } + + + + /** + * Tests the behavior when comparing two servers with identical schemas when + * that schema is discovered rather than explicitly specified. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNoDifferencesDiscoveringSchema() + throws Exception + { + final InMemoryDirectoryServerConfig dsConfig = + new InMemoryDirectoryServerConfig("dc=example,dc=com"); + dsConfig.addAdditionalBindCredentials("cn=Directory Manager", "password"); + + final InMemoryDirectoryServer ds1 = new InMemoryDirectoryServer(dsConfig); + final InMemoryDirectoryServer ds2 = new InMemoryDirectoryServer(dsConfig); + try + { + ds1.startListening(); + ds2.startListening(); + + assertToolResultCodeIs(ds1, ds2, false, ResultCode.SUCCESS); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers with identical schemas when + * that schema entry is explicitly specified. + *

    + * Also, to get a little additional coverage, use the getExtendedSchemaInfo + * argument in one of the requests. The in-memory directory server doesn't + * support the associated control, but the request makes it non-critical, so + * the server should ignore it. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNoDifferencesSpecifiedSchemaEntry() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema(); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--getExtendedSchemaInfo"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * malformed attribute syntax definition. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeSyntaxMalformed() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, "malformed")); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has an + * attribute syntax definition that the other doesn't have. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeSyntaxMissing() + throws Exception + { + final AttributeSyntaxDefinition def1 = + new AttributeSyntaxDefinition("1.2.3.4", "Test", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which an attribute syntax + * exists in both servers, but has a description in one server and is missing + * a description in the other. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeSyntaxMissingDescription() + throws Exception + { + final AttributeSyntaxDefinition def1 = + new AttributeSyntaxDefinition("1.2.3.4", "Has Description", null); + final AttributeSyntaxDefinition def2 = + new AttributeSyntaxDefinition("1.2.3.4", null, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which an attribute syntax + * exists in both servers, but has a different description in each server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeSyntaxDifferentDescriptions() + throws Exception + { + final AttributeSyntaxDefinition def1 = + new AttributeSyntaxDefinition("1.2.3.4", "Description 1", null); + final AttributeSyntaxDefinition def2 = + new AttributeSyntaxDefinition("1.2.3.4", "Description 2", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which an attribute syntax + * exists in both servers, but has an extension in one server and does not + * have any extensions in the other server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeSyntaxMissingAnyExtension() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final AttributeSyntaxDefinition def1 = + new AttributeSyntaxDefinition("1.2.3.4", "Test", ext1); + final AttributeSyntaxDefinition def2 = + new AttributeSyntaxDefinition("1.2.3.4", "Test", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which an attribute syntax + * exists in both servers, but has two extensions in one server, but only one + * of them in the second. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeSyntaxMissingSomeExtension() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }, + "X-TEST-2", new String[] { "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }); + + final AttributeSyntaxDefinition def1 = + new AttributeSyntaxDefinition("1.2.3.4", "Test", ext1); + final AttributeSyntaxDefinition def2 = + new AttributeSyntaxDefinition("1.2.3.4", "Test", ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which an attribute syntax + * exists in both servers, but has an extension in each server, but when one + * server has two values for that extension, while the other only has one of + * those values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeSyntaxMissingSomeExtensionValues() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1", "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final AttributeSyntaxDefinition def1 = + new AttributeSyntaxDefinition("1.2.3.4", "Test", ext1); + final AttributeSyntaxDefinition def2 = + new AttributeSyntaxDefinition("1.2.3.4", "Test", ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_SYNTAX, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * malformed matching rule definition. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleMalformed() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, "malformed")); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * matching rule definition that the other doesn't have. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleMissing() + throws Exception + { + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule, but one of them has a name while the other doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleOnlyOneHasName() + throws Exception + { + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", null); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + null, "test-description", "1.2.3.5", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule, but they have different names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleDifferentNames() + throws Exception + { + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name-1", "test-description", "1.2.3.5", null); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + "test-name-2", "test-description", "1.2.3.5", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule, but one of them has multiple names, while the other only has + * one of those names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleMissingOneOfMultipleNames() + throws Exception + { + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "1.2.3.5", null); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + new String[] { "test-name-1" }, "test-description", false, "1.2.3.5", + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule, but they have different syntax OIDs. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleDifferentSyntaxOIDs() + throws Exception + { + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", null); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.6", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule, but one is obsolete while the other is not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleDifferentObsolete() + throws Exception + { + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "1.2.3.5", null); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + true, "1.2.3.5", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which a matching rule + * exists in both servers, but has a description in one server and is missing + * a description in the other. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleMissingDescription() + throws Exception + { + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", null); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + "test-name", null, "1.2.3.5", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which a matching rule + * exists in both servers, but has a different description in each server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleDifferentDescriptions() + throws Exception + { + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description-1", "1.2.3.5", null); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description-2", "1.2.3.5", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which a matching rule + * exists in both servers, but has an extension in one server and does not + * have any extensions in the other server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleMissingAnyExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", ext1); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which a matching rule + * exists in both servers, but has two extensions in one server, but only one + * of them in the second. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleMissingSomeExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }, + "X-TEST-2", new String[] { "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }); + + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", ext1); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which a matching rule + * exists in both servers, but has an extension in each server, but when one + * server has two values for that extension, while the other only has one of + * those values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleMissingSomeExtensionValues() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1", "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final MatchingRuleDefinition def1 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", ext1); + final MatchingRuleDefinition def2 = new MatchingRuleDefinition("1.2.3.4", + "test-name", "test-description", "1.2.3.5", ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * malformed attribute type definition. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMalformed() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, "malformed")); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has an + * attribute type definition that the other doesn't have. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissing() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + "test-name", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but one of them has a name while the other doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeOnlyOneHasName() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + "test-name", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + null, "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentNames() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + "test-name-2", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but one of them has multiple names, while the other only + * has one of those names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingOneOfMultipleNames() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, null, "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1" }, "test-description", + false, null, "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but one of them has a superior type, while the other does + * not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingSuperiorType() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, null, "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different superior types. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentSuperiorTypes() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior-1", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior-2", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but one of them has a syntax OID, while the other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingSyntaxOID() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", null, true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different syntax OIDs. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentSyntaxOIDs() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.26", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but one of them has an equality matching rule, while the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingEqualityMatchingRule() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", null, "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different equality matching rules. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentEqualityMatchingRules() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseExactMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but one of them has an ordering matching rule, while the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingOrderingMatchingRule() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", null, + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different ordering matching rules. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentOrderingMatchingRules() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseExactOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but one of them has a substring matching rule, while the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingSubstringMatchingRule() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + null, "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different substring matching rules. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentSubstringMatchingRules() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseExactSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different single-value settings. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentSingleValue() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", false, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different usages. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentUsages() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.DIRECTORY_OPERATION, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different NO-USER-MODIFICATION settings. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentNoUserModification() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, true, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different obsolete settings. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentCollective() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + true, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but they have different obsolete settings. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentObsolete() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + true, "test-superior", "caseIgnoreMatch", "caseIgnoreOrderingMatch", + "caseIgnoreSubstringsMatch", "1.3.6.1.4.1.1466.115.121.1.15", true, + false, false, AttributeUsage.USER_APPLICATIONS, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but has a description in one server and is missing a + * description in the other. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingDescription() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", null, "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but has a different description in each server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeDifferentDescriptions() + throws Exception + { + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description-1", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description-2", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but has an extension in one server and does not have any + * extensions in the other server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingAnyExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, ext1); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but has two extensions in one server, but only one of them + * in the second. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingSomeExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }, + "X-TEST-2", new String[] { "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }); + + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, ext1); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * attribute type, but has an extension in each server, but when one server + * has two values for that extension, while hte other has only one of those + * values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testAttributeTypeMissingSomeExtensionValues() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1", "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final AttributeTypeDefinition def1 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, ext1); + final AttributeTypeDefinition def2 = new AttributeTypeDefinition("1.2.3.4", + "test-name-1", "test-description", "caseIgnoreMatch", + "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch", + "1.3.6.1.4.1.1466.115.121.1.15", true, ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * malformed object class definition. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMalformed() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, "malformed")); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has an + * object class definition that the other doesn't have. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissing() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + "test-name", "test-description", "top", ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, but one of them has a name while the other doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassOnlyOneHasName() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + "test-name", "test-description", "top", ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + null, "test-description", "top", ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, but they have different names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassDifferentNames() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + "test-name-1", "test-description", "top", ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + "test-name-2", "test-description", "top", ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, but one of them has multiple names, while the other only has + * one of those names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingOneOfMultipleNames() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, but one of them has a superior class while the other does + * not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingSuperiorClass() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, null, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where each has a single superior class, but those classes are + * different. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassDifferentSuperiorClass() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "untypedObject" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where the first has two superior object classes while the + * second only has one of them. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassOneMissingSuperiorClassValue() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top", "untypedObject" }, + ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where the first server has a required attribute while the + * second does not have any. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingRequiredAttribute() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + null, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where the first server has a required attribute while the + * second does not have one of those values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingRequiredAttributeValue() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where the first server has an optional attribute while the + * second does not have any. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingOptionalAttribute() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where the first server has an optional attribute while the + * second does not have one of those values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingOptionalAttributeValue() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where the first server has an object class type while the + * second does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingObjectClassType() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, null, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where they have different object class types. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassDifferentObjectClassType() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.AUXILIARY, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where the servers have different obsolete values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassDifferentObsolete() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + true, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where one of the servers has a description while the other + * does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingDescription() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, null, + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, where one of the servers has a description while the other + * does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassDifferentDescriptions() + throws Exception + { + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description-1", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description-2", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, but has an extension in one server and does not have any + * extensions in the other server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingAnyExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + ext1); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, but has two extensions in one server, but only one of them in + * the second. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingSomeExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }, + "X-TEST-2", new String[] { "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }); + + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + ext1); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have an + * object class, but has an extension in each server, but when one server has + * two values for that extension, while hte other has only one of those + * values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testObjectClassMissingSomeExtensionValues() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1", "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final ObjectClassDefinition def1 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + ext1); + final ObjectClassDefinition def2 = new ObjectClassDefinition("1.2.3.4", + new String[] { "test-name-1", "test-name-2" }, "test-description", + false, new String[] { "top" }, ObjectClassType.STRUCTURAL, + new String[] { "required-1", "required-2" }, + new String[] { "optional-1", "optional-2" }, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_OBJECT_CLASS, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * malformed DIT content rule definition. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMalformed() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, "malformed")); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a DIT + * content rule definition that the other doesn't have. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissing() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of the has a name while the other + * doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleOnlyOneHasName() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + null, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but they have different names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleDifferentNames() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr-1" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr-2" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has multiple names, while the + * other only has one of those names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingOneOfMultipleNames() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr-1", "test-dcr-2" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr-1" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has required attributes while + * the other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingAnyRequiredAttributes() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + null, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has multiple required + * attributes while the other only has one of them. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingOneOfMultipleRequiredAttributes() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has optional attributes while + * the other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingAnyOptionalAttributes() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + null, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has multiple optional + * attributes while the other is missing one of them. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingOneOfMultipleOptionalAttributes() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has prohibited attributes + * while the other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingAnyProhibitedAttributes() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has multiple prohibited + * attributes while the other is missing one of them. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingOneOfMultipleProhibitedAttributes() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has allowed auxiliary object + * classes while the other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingAnyAuxiliaryClasses() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + null, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has multiple allowed auxiliary + * object classes while the other is missing one of them. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingOneOfMultipleAuxiliaryClasses() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but one of them has a description while the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingDescription() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + null, + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but they have different descriptions. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleDifferentDescriptions() + throws Exception + { + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description-1", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description-2", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but has an extension in one server and does + * not have any extensions in the other server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingAnyExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + ext1); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule definition, but has two extensions in one server, but only + * one of those extensions in the other. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingSomeExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }, + "X-TEST-2", new String[] { "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }); + + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + ext1); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT content rule, but has an extension in each server, but when one server + * has two values for that extension, while the other has only one of those + * values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITContentRuleMissingSomeExtensionValues() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1", "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final DITContentRuleDefinition def1 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + ext1); + final DITContentRuleDefinition def2 = new DITContentRuleDefinition( + "1.2.3.4", + new String[] { "test-dcr" }, + "test-description", + false, + new String[] { "test-auxiliary-class-1", "test-auxiliary-class-2" }, + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + new String[] { "prohibited-attribute-1", "prohibited-attribute-2" }, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_CONTENT_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * malformed DIT structure rule definition. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMalformed() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, "malformed")); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a DIT + * structure rule definition that the other doesn't have. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMissing() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but one of them has a name while the other + * doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleOnlyOneHasName() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + null, + "test-description", + false, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but they have different names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleDifferentNames() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr-1" }, + "test-description", + false, + "test-name-form", + null, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr-2" }, + "test-description", + false, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but one of them has multiple names, while + * the other only has one of those names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMissingOneOfMultipleNames() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr-1", "test-dsr-2" }, + "test-description", + false, + "test-name-form", + null, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr-1" }, + "test-description", + false, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but they have different name form IDs. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleDifferentNameFormID() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form-1", + null, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form-2", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but one of them has a superior rule ID + * while the other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMissingAnySuperiorRuleIDs() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 2, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + new int[] { 1 }, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 2, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but one of them has multiple superior rule + * IDs while the other only has one of them. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMissingSomeSuperiorRuleIDs() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 3, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + new int[] { 1, 2 }, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 3, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + new int[] { 1 }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but they have different obsolete values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleDifferentObsolete() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + true, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but one of them has a description while the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMissingDescription() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + null, + false, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but they have different descriptions. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleDifferentDescriptions() + throws Exception + { + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description-1", + false, + "test-name-form", + null, + null); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description-2", + false, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but one of them has an extension and the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMissingAnyExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + ext1); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but has two extensions in one server, but + * only one of those extensions in the other. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMissingSomeExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }, + "X-TEST-2", new String[] { "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }); + + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + ext1); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * DIT structure rule definition, but one server has two values for a given + * extension while the other only has one of those values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testDITStructureRuleMissingSomeExtensionValues() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1", "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final DITStructureRuleDefinition def1 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + ext1); + final DITStructureRuleDefinition def2 = new DITStructureRuleDefinition( + 1, + new String[] { "test-dsr" }, + "test-description", + false, + "test-name-form", + null, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_DIT_STRUCTURE_RULE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * malformed name form definition. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMalformed() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, "malformed")); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * name form definition that the other doesn't have. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissing() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but one of them has a name while the other doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormOnlyOneHasName() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + null, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but they have different names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormDifferentNames() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form-1" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form-2" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but one of them has multiple names, while the other + * only has one of those names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissingOneOfMultipleNames() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form-1", "test-name-form-2" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form-1" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but they have different structural object classes. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormDifferentStructuralClass() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class-1", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class-2", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, where both of them have required attributes, but one + * of them has one that the other doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissingOneOfMultipleRequiredAttributes() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but one of them has a set of optional attributes + * while the other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissingAnyOptionalAttributes() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + null, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, where both of them have optional attributes, but one + * of them has one that the other doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissingOneOfMultipleOptionalAttributes() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but they have different obsolete values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormDifferentObsolete() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + true, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but where one of them has a description while the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissingDescription() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + null, + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but where they have different descriptions. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormDifferentDescriptions() + throws Exception + { + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description-1", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description-2", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but one of them has an extension and the other does + * not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissingAnyExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + ext1); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but has two extensions in one server, but only one of + * those extensions in the other. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissingSomeExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }, + "X-TEST-2", new String[] { "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }); + + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + ext1); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * name form definition, but one server has two values for a given extension + * while the other only has one of those values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testNameFormMissingSomeExtensionValues() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1", "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final NameFormDefinition def1 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + ext1); + final NameFormDefinition def2 = new NameFormDefinition( + "1.2.3.4", + new String[] { "test-name-form" }, + "test-description", + false, + "test-structural-class", + new String[] { "required-attribute-1", "required-attribute-2" }, + new String[] { "optional-attribute-1", "optional-attribute-2" }, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_NAME_FORM, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * malformed matching rule use definition. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseMalformed() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, "malformed")); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which one server has a + * matching rule use definition that the other doesn't have. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseMissing() + throws Exception + { + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but one of them has a name while the other + * doesn't. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseOnlyOneHasName() + throws Exception + { + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + null, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but they have different names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseDifferentNames() + throws Exception + { + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use-1" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use-2" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but one of them has multiple names, while the + * other only has one of those names. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseMissingOneOfMultipleNames() + throws Exception + { + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-mru-1", "test-mru-2" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-mru-1" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but one of them has an applicable attribute + * type that the other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseMissingOneOfMultipleApplicableTypes() + throws Exception + { + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but they have different obsolete values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseDifferentObsolete() + throws Exception + { + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + true, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but one of them has a description that the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseMissingDescription() + throws Exception + { + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + null, + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but they have different descriptions. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseDifferentDescription() + throws Exception + { + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description-1", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description-2", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreDescriptions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but one of them has an extension and the + * other does not. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseMissingAnyExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + ext1); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but has two extensions in one server, but + * only one of those extensions in the other. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseMissingSomeExtensions() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }, + "X-TEST-2", new String[] { "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST-1", new String[] { "value-1" }); + + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + ext1); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which both servers have a + * matching rule use definition, but one server has two values for a given + * extension while the other only has one of those values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testMatchingRuleUseMissingSomeExtensionValues() + throws Exception + { + final Map ext1 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1", "value-2" }); + final Map ext2 = StaticUtils.mapOf( + "X-TEST", new String[] { "value-1" }); + + final MatchingRuleUseDefinition def1 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + ext1); + final MatchingRuleUseDefinition def2 = new MatchingRuleUseDefinition( + "1.2.3.4", + new String[] { "test-matching-rule-use" }, + "test-description", + false, + new String[] { "test-applicable-type-1", "test-applicable-type-2" }, + ext2); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def1.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_MATCHING_RULE_USE, def2.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--ignoreExtensions"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when attempting to run the tool with an invalid + * schemaElementType argument value. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testInvalidSchemaElementType() + throws Exception + { + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema(); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema(); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.PARAM_ERROR, + "--schemaElementType", "attribute-syntaxes", + "--schemaElementType", "matching-rules", + "--schemaElementType", "attribute-types", + "--schemaElementType", "object-classes", + "--schemaElementType", "dit-content-rules", + "--schemaElementType", "dit-structure-rules", + "--schemaElementType", "name-forms", + "--schemaElementType", "matching-rule-uses", + "--schemaElementType", "invalid"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when including or excluding schema elements based on + * name prefixes. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testIncludeOrExcludeBasedOnNamePrefix() + throws Exception + { + final AttributeTypeDefinition at1 = new AttributeTypeDefinition( + "1.2.3.4", "p1-name", null, null, null, null, null, false, null); + final AttributeTypeDefinition at2a = new AttributeTypeDefinition( + "1.2.3.5", "p2-name-a", null, null, null, null, null, false, null); + final AttributeTypeDefinition at2b = new AttributeTypeDefinition( + "1.2.3.5", "p2-name-b", null, null, null, null, null, false, null); + final AttributeTypeDefinition at3a = new AttributeTypeDefinition( + "1.2.3.6", "p3-name-a", null, null, null, null, null, false, null); + final AttributeTypeDefinition at3b = new AttributeTypeDefinition( + "1.2.3.6", "p3-name-b", null, null, null, null, null, false, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, + at1.toString(), + at2a.toString(), + at3a.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, + at1.toString(), + at2b.toString(), + at3b.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--includeElementsWithNameMatchingPrefix", "p1-"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--includeElementsWithNameMatchingPrefix", "p2-"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--includeElementsWithNameMatchingPrefix", "p1-", + "--includeElementsWithNameMatchingPrefix", "p2-"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--excludeElementsWithNameMatchingPrefix", "p1-", + "--excludeElementsWithNameMatchingPrefix", "p2-", + "--excludeElementsWithNameMatchingPrefix", "p3-"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--excludeElementsWithNameMatchingPrefix", "p2-", + "--excludeElementsWithNameMatchingPrefix", "p3-"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--excludeElementsWithNameMatchingPrefix", "p2-"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--excludeElementsWithNameMatchingPrefix", "p3-"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when including schema elements based on extension + * values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testIncludeBasedOnExtensionValue() + throws Exception + { + final Map includeWithoutConflictsMap = StaticUtils.mapOf( + "X-INCLUDE", new String[] { "include-without-conflicts" }); + final Map includeWithConflictsMap = StaticUtils.mapOf( + "X-INCLUDE", new String[] { "include-with-conflicts" }); + + final AttributeTypeDefinition at1 = new AttributeTypeDefinition( + "1.2.3.4", "test-name-1", null, null, null, null, null, false, + includeWithoutConflictsMap); + + final AttributeTypeDefinition at2a = new AttributeTypeDefinition( + "1.2.3.5", "test-name-2a", null, null, null, null, null, false, + includeWithConflictsMap); + final AttributeTypeDefinition at2b = new AttributeTypeDefinition( + "1.2.3.5", "test-name-2b", null, null, null, null, null, false, + includeWithConflictsMap); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, + at1.toString(), + at2a.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, + at1.toString(), + at2b.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--includeElementsWithExtensionValue", + "X-INCLUDE=include-without-conflicts"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--includeElementsWithExtensionValue", + "X-INCLUDE=include-with-conflicts"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--includeElementsWithExtensionValue", + "X-INCLUDE=include-with-conflicts", + "--includeElementsWithExtensionValue", + "X-INCLUDE=include-without-conflicts"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.PARAM_ERROR, + "--includeElementsWithExtensionValue", + "X-MISSING-EQUALS"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.PARAM_ERROR, + "--includeElementsWithExtensionValue", + "=empty-extension-name"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.PARAM_ERROR, + "--includeElementsWithExtensionValue", + "X-EMPTY-EXTENSION-VALUE="); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when excluding schema elements based on extension + * values. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testExcludeBasedOnExtensionValue() + throws Exception + { + final Map excludeWithoutConflictsMap = StaticUtils.mapOf( + "X-EXCLUDE", new String[] { "exclude-without-conflicts" }); + final Map excludeWithConflictsMap = StaticUtils.mapOf( + "X-EXCLUDE", new String[] { "exclude-with-conflicts" }); + + final AttributeTypeDefinition at1 = new AttributeTypeDefinition( + "1.2.3.4", "test-name-1", null, null, null, null, null, false, + excludeWithoutConflictsMap); + + final AttributeTypeDefinition at2a = new AttributeTypeDefinition( + "1.2.3.5", "test-name-2a", null, null, null, null, null, false, + excludeWithConflictsMap); + final AttributeTypeDefinition at2b = new AttributeTypeDefinition( + "1.2.3.5", "test-name-2b", null, null, null, null, null, false, + excludeWithConflictsMap); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, + at1.toString(), + at2a.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, + at1.toString(), + at2b.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.COMPARE_FALSE, + "--excludeElementsWithExtensionValue", + "X-EXCLUDE=exclude-without-conflicts"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--excludeElementsWithExtensionValue", + "X-EXCLUDE=exclude-with-conflicts"); + + assertToolResultCodeIs(ds1, ds2, true, ResultCode.SUCCESS, + "--excludeElementsWithExtensionValue", + "X-EXCLUDE=exclude-with-conflicts", + "--excludeElementsWithExtensionValue", + "X-EXCLUDE=exclude-without-conflicts"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when comparing two servers in which there are a + * combination of malformed schema elements and other schema elements that + * differ between servers. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testWithMalformedElementsAndDifferences() + throws Exception + { + final AttributeTypeDefinition at1a = new AttributeTypeDefinition( + "1.2.3.4", "test-name-1a", null, null, null, null, null, false, null); + final AttributeTypeDefinition at1b = new AttributeTypeDefinition( + "1.2.3.4", null, null, null, null, null, null, false, null); + final AttributeTypeDefinition at2a = new AttributeTypeDefinition( + "1.2.3.5", "test-name-2a", null, null, null, null, null, false, null); + final AttributeTypeDefinition at2b = new AttributeTypeDefinition( + "1.2.3.5", "test-name-2b", null, null, null, null, null, false, null); + + final InMemoryDirectoryServer ds1 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, + "malformed", + at1a.toString(), + at2a.toString())); + final InMemoryDirectoryServer ds2 = getTestDSInstanceWithAdditionalSchema( + new Attribute(Schema.ATTR_ATTRIBUTE_TYPE, + at1b.toString(), + at2b.toString())); + + try + { + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX); + + assertToolResultCodeIs(ds1, ds2, true, + ResultCode.INVALID_ATTRIBUTE_SYNTAX, + "--excludeElementsWithNameMatchingPrefix", "test-name-2"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when trying to compare schema between two servers when + * once of those servers isn't online. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testCompareSchemaOneServerOffline() + throws Exception + { + final InMemoryDirectoryServerConfig dsConfig = + new InMemoryDirectoryServerConfig("dc=example,dc=com"); + dsConfig.addAdditionalBindCredentials("cn=Directory Manager", "password"); + + final InMemoryDirectoryServer ds1 = new InMemoryDirectoryServer(dsConfig); + final InMemoryDirectoryServer ds2 = new InMemoryDirectoryServer(dsConfig); + try + { + ds1.startListening(); + ds2.startListening(); + + final int ds1Port = ds1.getListenPort(); + final int ds2Port = ds2.getListenPort(); + + ds2.shutDown(true); + + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final CompareLDAPSchemas tool = new CompareLDAPSchemas(out, out); + final ResultCode resultCode = tool.runTool( + "--firstHostname", "127.0.0.1", + "--firstPort", String.valueOf(ds1Port), + "--firstBindDN", "cn=Directory Manager", + "--firstBindPassword", "password", + "--secondHostname", "127.0.0.1", + "--secondPort", String.valueOf(ds2Port), + "--secondBindDN", "cn=Directory Manager", + "--secondBindPassword", "password"); + + assertEquals(resultCode, ResultCode.CONNECT_ERROR, + StaticUtils.toUTF8String(out.toByteArray())); + + assertNotNull(tool.getToolCompletionMessage()); + assertNotNull(tool.getExampleUsages()); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when trying to compare schema between two servers when + * an error occurs while trying to authenticate to the server. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testCompareSchemaAuthenticationError() + throws Exception + { + final InMemoryDirectoryServerConfig dsConfig = + new InMemoryDirectoryServerConfig("dc=example,dc=com"); + dsConfig.addAdditionalBindCredentials("cn=Directory Manager", + "not-the-expected-password"); + + final InMemoryDirectoryServer ds1 = new InMemoryDirectoryServer(dsConfig); + final InMemoryDirectoryServer ds2 = new InMemoryDirectoryServer(dsConfig); + try + { + ds1.startListening(); + ds2.startListening(); + + assertToolResultCodeIs(ds1, ds2, false, ResultCode.INVALID_CREDENTIALS); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when trying to compare schema between two servers when + * an error occurs while attempting to retrieve the root DSE. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testCompareSchemaCannotRetrieveRootDSE() + throws Exception + { + final InMemoryDirectoryServerConfig dsConfig = + new InMemoryDirectoryServerConfig("dc=example,dc=com"); + dsConfig.addAdditionalBindCredentials("cn=Directory Manager", "password"); + dsConfig.setAllowedOperationTypes(OperationType.BIND); + + + final InMemoryDirectoryServer ds1 = new InMemoryDirectoryServer(dsConfig); + final InMemoryDirectoryServer ds2 = new InMemoryDirectoryServer(dsConfig); + try + { + ds1.startListening(); + ds2.startListening(); + + assertToolResultCodeIs(ds1, ds2, false, ResultCode.UNWILLING_TO_PERFORM); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when trying to compare schema between two servers when + * the root DSE does not include a subschemaSubentry attribute. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testCompareSchemaRootDSEMissingSubschemaSubentryAttribute() + throws Exception + { + final InMemoryDirectoryServer testDS = getTestDS(); + final Entry rootDSEEntry = testDS.getRootDSE().duplicate(); + rootDSEEntry.removeAttribute("subschemaSubentry"); + + + final InMemoryDirectoryServerConfig dsConfig = + new InMemoryDirectoryServerConfig("dc=example,dc=com"); + dsConfig.addAdditionalBindCredentials("cn=Directory Manager", "password"); + dsConfig.setRootDSEEntry(rootDSEEntry); + + + final InMemoryDirectoryServer ds1 = new InMemoryDirectoryServer(dsConfig); + final InMemoryDirectoryServer ds2 = new InMemoryDirectoryServer(dsConfig); + try + { + ds1.startListening(); + ds2.startListening(); + + assertToolResultCodeIs(ds1, ds2, false, ResultCode.LOCAL_ERROR); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when trying to compare schema between two servers when + * an error occurs while attempting to retrieve the subschema subentry. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testCompareSchemaCannotRetrieveSchemaEntry() + throws Exception + { + final InMemoryDirectoryServerConfig dsConfig = + new InMemoryDirectoryServerConfig("dc=example,dc=com"); + dsConfig.addAdditionalBindCredentials("cn=Directory Manager", "password"); + dsConfig.setAllowedOperationTypes(OperationType.BIND); + + + final InMemoryDirectoryServer ds1 = new InMemoryDirectoryServer(dsConfig); + final InMemoryDirectoryServer ds2 = new InMemoryDirectoryServer(dsConfig); + try + { + ds1.startListening(); + ds2.startListening(); + + assertToolResultCodeIs(ds1, ds2, false, ResultCode.UNWILLING_TO_PERFORM, + "--firstSchemaEntryDN", "cn=schema", + "--secondSchemaEntryDN", "cn=schema"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + /** + * Tests the behavior when trying to compare schema between two servers when + * the specified schema entry does not exist. + * + * @throws Exception If an unexpected problem occurs. + */ + @Test() + public void testCompareSchemaNoSuchSchemaEntry() + throws Exception + { + final InMemoryDirectoryServerConfig dsConfig = + new InMemoryDirectoryServerConfig("dc=example,dc=com"); + dsConfig.addAdditionalBindCredentials("cn=Directory Manager", "password"); + + final InMemoryDirectoryServer ds1 = new InMemoryDirectoryServer(dsConfig); + final InMemoryDirectoryServer ds2 = new InMemoryDirectoryServer(dsConfig); + try + { + ds1.startListening(); + ds2.startListening(); + + assertToolResultCodeIs(ds1, ds2, false, ResultCode.NO_SUCH_OBJECT, + "--firstSchemaEntryDN", "cn=nonexistent,dc=example,dc=com"); + + assertToolResultCodeIs(ds1, ds2, false, ResultCode.NO_SUCH_OBJECT, + "--secondSchemaEntryDN", "cn=nonexistent,dc=example,dc=com"); + } + finally + { + ds1.shutDown(true); + ds2.shutDown(true); + } + } + + + + // getToolCompletionMessage + // getExampleUses + + + + /** + * Retrieves an in-memory directory server instance that contains a custom + * entry with a representation of a default schema, which may also include + * additional schema attributes. + * + * @param extraSchemaAttributes A set of additional attributes to include in + * the schema. It must not be {@code null}, + * but may be empty. + * + * @return The in-memory directory server instance that was created. + * + * @throws Exception If an unexpected problem occurs. + */ + private static InMemoryDirectoryServer getTestDSInstanceWithAdditionalSchema( + final Attribute... extraSchemaAttributes) + throws Exception + { + final InMemoryDirectoryServerConfig dsConfig = + new InMemoryDirectoryServerConfig("dc=example,dc=com"); + dsConfig.addAdditionalBindCredentials("cn=Directory Manager", "password"); + + final InMemoryDirectoryServer ds = new InMemoryDirectoryServer(dsConfig); + ds.add( + "dn: dc=example,dc=com", + "objectClass: top", + "objectClass: domain", + "dc: example"); + + final Entry customSchemaEntry = DEFAULT_CUSTOM_SCHEMA_ENTRY.duplicate(); + for (final Attribute a : extraSchemaAttributes) + { + customSchemaEntry.addAttribute(a); + } + ds.add(customSchemaEntry); + + ds.startListening(); + return ds; + } + + + + /** + * Ensures that invoking the tool against the provided two servers yields the + * expected result. + * + * @param ds1 The first server to compare. It must not be + * {@code null}. + * @param ds2 The second server to compare. It must not be + * {@code null}. + * @param useCustomSchemaEntry Indicates whether to read the schema from a + * custom entry rather than having the tool + * discover the server's default schema. + * @param expectedResultCode The result code that is expected when + * invoking the tool. It must not be + * {@code null}. + * @param extraArgs The extra arguments to provide when invoking + * the {@code compare-ldap-schemas} tool + * (excluding those used to connect, + * authenticate, or specify the schema entry + * DN). It must not be {@code null}, but may be + * empty. + */ + private void assertToolResultCodeIs(final InMemoryDirectoryServer ds1, + final InMemoryDirectoryServer ds2, + final boolean useCustomSchemaEntry, + final ResultCode expectedResultCode, + final String... extraArgs) + { + final List extraArgList = new ArrayList<>(); + if (useCustomSchemaEntry) + { + extraArgList.add("--firstSchemaEntryDN"); + extraArgList.add(DEFAULT_CUSTOM_SCHEMA_ENTRY.getDN()); + extraArgList.add("--secondSchemaEntryDN"); + extraArgList.add(DEFAULT_CUSTOM_SCHEMA_ENTRY.getDN()); + } + + if (extraArgs.length > 0) + { + extraArgList.addAll(Arrays.asList(extraArgs)); + } + + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final ResultCode rc1 = runTool(ds1, ds2, out, extraArgList); + if (rc1 != expectedResultCode) + { + fail("Got result code " + rc1 + " instead of expected result code " + + expectedResultCode + " when invoking the tool with extra args " + + extraArgList + " against the servers in the provided order. The " + + "tool output is:" + StaticUtils.EOL + StaticUtils.EOL + + StaticUtils.toUTF8String(out.toByteArray())); + } + + out.reset(); + final ResultCode rc2 = runTool(ds2, ds1, out, extraArgList); + if (rc2 != expectedResultCode) + { + fail("Got result code " + rc2 + " instead of expected result code " + + expectedResultCode + " when invoking the tool with extra args " + + extraArgList + " against the servers in the reverse order. The " + + "tool output is:" + StaticUtils.EOL + StaticUtils.EOL + + StaticUtils.toUTF8String(out.toByteArray())); + } + } + + + + /** + * Runs the {@code compare-ldap-schemas} tool against the provided servers + * with the given arguments. + * + * @param ds1 The first server instance to use. It must not be + * {@code null}. + * @param ds2 The second server instance to use. It must not be + * {@code null}. + * @param out The output stream to use for both standard output and + * standard error. + * @param extraArgs The extra arguments to provide when invoking the + * {@code compare-ldap-schemas} tool (excluding those used + * to connect and authenticate). It must not be + * {@code null}, but may be empty. + * + * @return The result code obtained when running the tool. + */ + private static ResultCode runTool(final InMemoryDirectoryServer ds1, + final InMemoryDirectoryServer ds2, + final OutputStream out, + final List extraArgs) + { + final List argList = new ArrayList<>(Arrays.asList( + "--firstHostname", "127.0.0.1", + "--firstPort", String.valueOf(ds1.getListenPort()), + "--firstBindDN", "cn=Directory Manager", + "--firstBindPassword", "password", + "--secondHostname", "127.0.0.1", + "--secondPort", String.valueOf(ds2.getListenPort()), + "--secondBindDN", "cn=Directory Manager", + "--secondBindPassword", "password")); + argList.addAll(extraArgs); + + final String[] argArray = StaticUtils.toArray(argList, String.class); + + return CompareLDAPSchemas.main(out, out, argArray); + } +}