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

neil_a_wilson
13.37.2007 d79ffa0d51c8de927346b74bb413d1f1455d4028
Fix a bug in the LDIFDiff tool that could cause it to miss added or deleted
entries under certain conditions. Also, add a number of test cases to cover
the LDIFDiff tool.
22 files added
3 files modified
1490 ■■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java 16 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/tools/LDIFDiff.java 130 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/tools/LDIFModify.java 109 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-emptytosingle.ldif 7 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-reverse-singlevalue.ldif 76 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-reverse.ldif 58 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-singlevalue.ldif 76 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries.ldif 58 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipletosingle-reverse-singlevalue.ldif 60 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipletosingle-reverse.ldif 42 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipletosingle.ldif 29 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-nochanges.ldif 1 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singleentry-reverse.ldif 5 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singleentry.ldif 5 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singletoempty.ldif 6 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singletomultiple-reverse.ldif 29 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singletomultiple-singlevalue.ldif 60 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singletomultiple.ldif 42 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/source-empty.ldif patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/source-multipleentries.ldif 26 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/source-singleentry.ldif 5 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/target-empty.ldif patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/target-multipleentries.ldif 32 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/target-singleentry.ldif 6 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDIFDiffTestCase.java 612 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -869,6 +869,22 @@
  /**
   * Retrieves the path to the configuration file used to initialize the
   * Directory Server.
   *
   * @return  The path to the configuration file used to initialize the
   *          Directory Server.
   */
  public static String getConfigFile()
  {
    assert debugEnter(CLASS_NAME, "getConfigFile");
    return directoryServer.configFile;
  }
  /**
   * Starts up the Directory Server.  It must have already been bootstrapped
   * and cannot be running.
   *
opendj-sdk/opends/src/server/org/opends/server/tools/LDIFDiff.java
@@ -103,7 +103,7 @@
   */
  public static void main(String[] args)
  {
    int exitCode = mainDiff(args);
    int exitCode = mainDiff(args, false);
    if (exitCode != 0)
    {
      System.exit(exitCode);
@@ -116,13 +116,17 @@
   * Parses the provided command line arguments and performs the appropriate
   * LDIF diff operation.
   *
   * @param  args  The command line arguments provided to this program.
   * @param  args               The command line arguments provided to this
   *                            program.
   * @param  serverInitialized  Indicates whether the Directory Server has
   *                            already been initialized (and therefore should
   *                            not be initialized a second time).
   *
   * @return  The return code for this operation.  A value of zero indicates
   *          that all processing completed successfully.  A nonzero value
   *          indicates that some problem occurred during processing.
   */
  public static int mainDiff(String[] args)
  public static int mainDiff(String[] args, boolean serverInitialized)
  {
    BooleanArgument overwriteExisting;
    BooleanArgument showUsage;
@@ -215,57 +219,60 @@
    }
    // Bootstrap the Directory Server configuration for use as a client.
    DirectoryServer directoryServer = DirectoryServer.getInstance();
    directoryServer.bootstrapClient();
    // If we're to use the configuration then initialize it, along with the
    // schema.
    boolean checkSchema = configFile.isPresent();
    if (checkSchema)
    if (! serverInitialized)
    {
      try
      {
        directoryServer.initializeJMX();
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LDIFDIFF_CANNOT_INITIALIZE_JMX;
        String message = getMessage(msgID,
                                    String.valueOf(configFile.getValue()),
                                    e.getMessage());
        System.err.println(message);
        return 1;
      }
      // Bootstrap the Directory Server configuration for use as a client.
      DirectoryServer directoryServer = DirectoryServer.getInstance();
      directoryServer.bootstrapClient();
      try
      {
        directoryServer.initializeConfiguration(configClass.getValue(),
                                                configFile.getValue());
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LDIFDIFF_CANNOT_INITIALIZE_CONFIG;
        String message = getMessage(msgID,
                                    String.valueOf(configFile.getValue()),
                                    e.getMessage());
        System.err.println(message);
        return 1;
      }
      try
      // If we're to use the configuration then initialize it, along with the
      // schema.
      if (checkSchema)
      {
        directoryServer.initializeSchema();
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LDIFDIFF_CANNOT_INITIALIZE_SCHEMA;
        String message = getMessage(msgID,
                                    String.valueOf(configFile.getValue()),
                                    e.getMessage());
        System.err.println(message);
        return 1;
        try
        {
          directoryServer.initializeJMX();
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_LDIFDIFF_CANNOT_INITIALIZE_JMX;
          String message = getMessage(msgID,
                                      String.valueOf(configFile.getValue()),
                                      e.getMessage());
          System.err.println(message);
          return 1;
        }
        try
        {
          directoryServer.initializeConfiguration(configClass.getValue(),
                                                  configFile.getValue());
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_LDIFDIFF_CANNOT_INITIALIZE_CONFIG;
          String message = getMessage(msgID,
                                      String.valueOf(configFile.getValue()),
                                      e.getMessage());
          System.err.println(message);
          return 1;
        }
        try
        {
          directoryServer.initializeSchema();
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_LDIFDIFF_CANNOT_INITIALIZE_SCHEMA;
          String message = getMessage(msgID,
                                      String.valueOf(configFile.getValue()),
                                      e.getMessage());
          System.err.println(message);
          return 1;
        }
      }
    }
@@ -427,7 +434,7 @@
        Iterator<DN> sourceIterator = sourceMap.keySet().iterator();
        while (sourceIterator.hasNext())
        {
          writeDelete(writer, targetMap.get(sourceIterator.next()));
          writeDelete(writer, sourceMap.get(sourceIterator.next()));
        }
        return 0;
      }
@@ -461,6 +468,18 @@
            }
            else
            {
              // There are no more source entries, so if there are more target
              // entries then they're all adds.
              writeAdd(writer, targetEntry);
              while (targetIterator.hasNext())
              {
                targetDN    = targetIterator.next();
                targetEntry = targetMap.get(targetDN);
                writeAdd(writer, targetEntry);
                differenceFound = true;
              }
              break;
            }
          }
@@ -477,6 +496,17 @@
            }
            else
            {
              // There are no more target entries so all of the remaining source
              // entries are deletes.
              writeDelete(writer, sourceEntry);
              differenceFound = true;
              while (sourceIterator.hasNext())
              {
                sourceDN = sourceIterator.next();
                sourceEntry = sourceMap.get(sourceDN);
                writeDelete(writer, sourceEntry);
              }
              break;
            }
          }
opendj-sdk/opends/src/server/org/opends/server/tools/LDIFModify.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -394,7 +394,7 @@
   */
  public static void main(String[] args)
  {
    int returnCode = ldifModifyMain(args);
    int returnCode = ldifModifyMain(args, false);
    if (returnCode != 0)
    {
      System.exit(returnCode);
@@ -407,12 +407,16 @@
   * Processes the command-line arguments and makes the appropriate updates to
   * the LDIF file.
   *
   * @param  args  The command-line arguments provided to the client.
   * @param  args               The command line arguments provided to this
   *                            program.
   * @param  serverInitialized  Indicates whether the Directory Server has
   *                            already been initialized (and therefore should
   *                            not be initialized a second time).
   *
   * @return  A value of zero if everything completed properly, or nonzero if
   *          any problem(s) occurred.
   */
  public static int ldifModifyMain(String[] args)
  public static int ldifModifyMain(String[] args, boolean serverInitialized)
  {
    // Prepare the argument parser.
    BooleanArgument showUsage;
@@ -498,57 +502,60 @@
    }
    // Bootstrap the Directory Server configuration for use as a client.
    DirectoryServer directoryServer = DirectoryServer.getInstance();
    directoryServer.bootstrapClient();
    // If we're to use the configuration then initialize it, along with the
    // schema.
    boolean checkSchema = configFile.isPresent();
    if (checkSchema)
    if (! serverInitialized)
    {
      try
      {
        directoryServer.initializeJMX();
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_JMX;
        String message = getMessage(msgID,
                                    String.valueOf(configFile.getValue()),
                                    e.getMessage());
        System.err.println(message);
        return 1;
      }
      // Bootstrap the Directory Server configuration for use as a client.
      DirectoryServer directoryServer = DirectoryServer.getInstance();
      directoryServer.bootstrapClient();
      try
      {
        directoryServer.initializeConfiguration(configClass.getValue(),
                                                configFile.getValue());
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_CONFIG;
        String message = getMessage(msgID,
                                    String.valueOf(configFile.getValue()),
                                    e.getMessage());
        System.err.println(message);
        return 1;
      }
      try
      // If we're to use the configuration then initialize it, along with the
      // schema.
      boolean checkSchema = configFile.isPresent();
      if (checkSchema)
      {
        directoryServer.initializeSchema();
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_SCHEMA;
        String message = getMessage(msgID,
                                    String.valueOf(configFile.getValue()),
                                    e.getMessage());
        System.err.println(message);
        return 1;
        try
        {
          directoryServer.initializeJMX();
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_JMX;
          String message = getMessage(msgID,
                                      String.valueOf(configFile.getValue()),
                                      e.getMessage());
          System.err.println(message);
          return 1;
        }
        try
        {
          directoryServer.initializeConfiguration(configClass.getValue(),
                                                  configFile.getValue());
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_CONFIG;
          String message = getMessage(msgID,
                                      String.valueOf(configFile.getValue()),
                                      e.getMessage());
          System.err.println(message);
          return 1;
        }
        try
        {
          directoryServer.initializeSchema();
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_LDIFMODIFY_CANNOT_INITIALIZE_SCHEMA;
          String message = getMessage(msgID,
                                      String.valueOf(configFile.getValue()),
                                      e.getMessage());
          System.err.println(message);
          return 1;
        }
      }
    }
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-emptytosingle.ldif
New file
@@ -0,0 +1,7 @@
dn: dc=example,dc=com
changetype: add
objectClass: top
objectClass: domain
dc: example
description: test
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-reverse-singlevalue.ldif
New file
@@ -0,0 +1,76 @@
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: organization
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: dcObject
dn: dc=example,dc=com
changetype: modify
add: objectClass
objectClass: domain
dn: dc=example,dc=com
changetype: modify
delete: o
o: Example Corp.
dn: dc=example,dc=com
changetype: modify
delete: description
description: description 1
dn: dc=example,dc=com
changetype: modify
delete: description
description: description 2
dn: dc=example,dc=com
changetype: modify
delete: description
description: description 3
dn: ou=Applications,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: Applications
dn: ou=Groups,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: Groups
dn: ou=People,dc=example,dc=com
changetype: modify
delete: description
description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
changetype: delete
# objectClass: inetOrgPerson
# objectClass: person
# objectClass: top
# objectClass: organizationalPerson
# cn: Test User
# givenName: Test
# sn: User
# uid: test.user
# userPassword: password
dn: uid=test.user,ou=People,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: person
objectClass: top
objectClass: organizationalPerson
cn: Test User
givenName: Test
sn: User
uid: test.user
userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-reverse.ldif
New file
@@ -0,0 +1,58 @@
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: organization
objectClass: dcObject
-
add: objectClass
objectClass: domain
-
delete: o
o: Example Corp.
-
delete: description
description: description 1
description: description 2
description: description 3
dn: ou=Applications,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: Applications
dn: ou=Groups,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: Groups
dn: ou=People,dc=example,dc=com
changetype: modify
delete: description
description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
changetype: delete
# objectClass: inetOrgPerson
# objectClass: person
# objectClass: top
# objectClass: organizationalPerson
# cn: Test User
# givenName: Test
# sn: User
# uid: test.user
# userPassword: password
dn: uid=test.user,ou=People,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: person
objectClass: top
objectClass: organizationalPerson
cn: Test User
givenName: Test
sn: User
uid: test.user
userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-singlevalue.ldif
New file
@@ -0,0 +1,76 @@
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: domain
dn: dc=example,dc=com
changetype: modify
add: objectClass
objectClass: organization
dn: dc=example,dc=com
changetype: modify
add: objectClass
objectClass: dcObject
dn: dc=example,dc=com
changetype: modify
add: o
o: Example Corp.
dn: dc=example,dc=com
changetype: modify
add: description
description: description 1
dn: dc=example,dc=com
changetype: modify
add: description
description: description 2
dn: dc=example,dc=com
changetype: modify
add: description
description: description 3
dn: ou=Applications,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: Applications
dn: ou=Groups,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: Groups
dn: ou=People,dc=example,dc=com
changetype: modify
add: description
description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: person
objectClass: top
objectClass: organizationalPerson
cn: Test User
givenName: Test
sn: User
uid: test.user
userPassword: password
dn: uid=test.user,ou=People,dc=example,dc=com
changetype: delete
# objectClass: inetOrgPerson
# objectClass: person
# objectClass: top
# objectClass: organizationalPerson
# cn: Test User
# givenName: Test
# sn: User
# uid: test.user
# userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries.ldif
New file
@@ -0,0 +1,58 @@
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: domain
-
add: objectClass
objectClass: organization
objectClass: dcObject
-
add: o
o: Example Corp.
-
add: description
description: description 1
description: description 2
description: description 3
dn: ou=Applications,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: Applications
dn: ou=Groups,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: Groups
dn: ou=People,dc=example,dc=com
changetype: modify
add: description
description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: person
objectClass: top
objectClass: organizationalPerson
cn: Test User
givenName: Test
sn: User
uid: test.user
userPassword: password
dn: uid=test.user,ou=People,dc=example,dc=com
changetype: delete
# objectClass: inetOrgPerson
# objectClass: person
# objectClass: top
# objectClass: organizationalPerson
# cn: Test User
# givenName: Test
# sn: User
# uid: test.user
# userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipletosingle-reverse-singlevalue.ldif
New file
@@ -0,0 +1,60 @@
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: organization
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: dcObject
dn: dc=example,dc=com
changetype: modify
add: objectClass
objectClass: domain
dn: dc=example,dc=com
changetype: modify
delete: o
o: Example Corp.
dn: dc=example,dc=com
changetype: modify
delete: description
description: description 1
dn: dc=example,dc=com
changetype: modify
delete: description
description: description 2
dn: dc=example,dc=com
changetype: modify
delete: description
description: description 3
dn: ou=Applications,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: Applications
dn: ou=People,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: People
# description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
changetype: delete
# objectClass: inetOrgPerson
# objectClass: person
# objectClass: top
# objectClass: organizationalPerson
# cn: Test User
# givenName: Test
# sn: User
# uid: test.user
# userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipletosingle-reverse.ldif
New file
@@ -0,0 +1,42 @@
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: organization
objectClass: dcObject
-
add: objectClass
objectClass: domain
-
delete: o
o: Example Corp.
-
delete: description
description: description 1
description: description 2
description: description 3
dn: ou=Applications,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: Applications
dn: ou=People,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: People
# description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
changetype: delete
# objectClass: inetOrgPerson
# objectClass: person
# objectClass: top
# objectClass: organizationalPerson
# cn: Test User
# givenName: Test
# sn: User
# uid: test.user
# userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipletosingle.ldif
New file
@@ -0,0 +1,29 @@
dn: dc=example,dc=com
changetype: modify
add: description
description: test
dn: ou=Groups,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: Groups
dn: ou=People,dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: organizationalUnit
# ou: People
dn: uid=test.user,ou=People,dc=example,dc=com
changetype: delete
# objectClass: inetOrgPerson
# objectClass: person
# objectClass: top
# objectClass: organizationalPerson
# cn: Test User
# givenName: Test
# sn: User
# uid: test.user
# userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-nochanges.ldif
New file
@@ -0,0 +1 @@
# No differences were detected between the source and target LDIF files.
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singleentry-reverse.ldif
New file
@@ -0,0 +1,5 @@
dn: dc=example,dc=com
changetype: modify
delete: description
description: test
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singleentry.ldif
New file
@@ -0,0 +1,5 @@
dn: dc=example,dc=com
changetype: modify
add: description
description: test
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singletoempty.ldif
New file
@@ -0,0 +1,6 @@
dn: dc=example,dc=com
changetype: delete
# objectClass: top
# objectClass: domain
# dc: example
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singletomultiple-reverse.ldif
New file
@@ -0,0 +1,29 @@
dn: dc=example,dc=com
changetype: modify
delete: description
description: test
dn: ou=Groups,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: Groups
dn: ou=People,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: People
dn: uid=test.user,ou=People,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: person
objectClass: top
objectClass: organizationalPerson
cn: Test User
givenName: Test
sn: User
uid: test.user
userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singletomultiple-singlevalue.ldif
New file
@@ -0,0 +1,60 @@
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: domain
dn: dc=example,dc=com
changetype: modify
add: objectClass
objectClass: organization
dn: dc=example,dc=com
changetype: modify
add: objectClass
objectClass: dcObject
dn: dc=example,dc=com
changetype: modify
add: o
o: Example Corp.
dn: dc=example,dc=com
changetype: modify
add: description
description: description 1
dn: dc=example,dc=com
changetype: modify
add: description
description: description 2
dn: dc=example,dc=com
changetype: modify
add: description
description: description 3
dn: ou=Applications,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: Applications
dn: ou=People,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: People
description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: person
objectClass: top
objectClass: organizationalPerson
cn: Test User
givenName: Test
sn: User
uid: test.user
userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/diff-singletomultiple.ldif
New file
@@ -0,0 +1,42 @@
dn: dc=example,dc=com
changetype: modify
delete: objectClass
objectClass: domain
-
add: objectClass
objectClass: organization
objectClass: dcObject
-
add: o
o: Example Corp.
-
add: description
description: description 1
description: description 2
description: description 3
dn: ou=Applications,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: Applications
dn: ou=People,dc=example,dc=com
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: People
description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
objectClass: person
objectClass: top
objectClass: organizationalPerson
cn: Test User
givenName: Test
sn: User
uid: test.user
userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/source-empty.ldif
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/source-multipleentries.ldif
New file
@@ -0,0 +1,26 @@
dn: dc=example,dc=com
objectClass: top
objectClass: domain
dc: example
dn: ou=Groups,dc=example,dc=com
objectClass: top
objectClass: organizationalUnit
ou: Groups
dn: ou=People,dc=example,dc=com
objectClass: top
objectClass: organizationalUnit
ou: People
dn: uid=test.user,ou=People,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: test.user
givenName: Test
sn: User
cn: Test User
userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/source-singleentry.ldif
New file
@@ -0,0 +1,5 @@
dn: dc=example,dc=com
objectClass: top
objectClass: domain
dc: example
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/target-empty.ldif
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/target-multipleentries.ldif
New file
@@ -0,0 +1,32 @@
dn: dc=example,dc=com
objectClass: top
objectClass: organization
objectClass: dcObject
dc: example
o: Example Corp.
description: description 1
description: description 2
description: description 3
dn: ou=Applications,dc=example,dc=com
objectClass: top
objectClass: organizationalUnit
ou: Applications
dn: ou=People,dc=example,dc=com
objectClass: top
objectClass: organizationalUnit
ou: People
description: This is where you put the people
dn: cn=Test User,ou=People,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: test.user
givenName: Test
sn: User
cn: Test User
userPassword: password
opendj-sdk/opends/tests/unit-tests-testng/resource/ldif-diff/target-singleentry.ldif
New file
@@ -0,0 +1,6 @@
dn: dc=example,dc=com
objectClass: top
objectClass: domain
dc: example
description: test
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDIFDiffTestCase.java
New file
@@ -0,0 +1,612 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.util.Base64;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.testng.Assert.*;
/**
 * A set of test cases for the LDIFDiff tool.
 */
public class LDIFDiffTestCase
       extends ToolsTestCase
{
  // The path to the file that will be used if there are no differences between
  // the source and target LDIF data sets.
  private String noDiffsFile =
       System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT) + File.separator +
       "tests" + File.separator + "unit-tests-testng" + File.separator +
       "resource" + File.separator + "ldif-diff" + File.separator +
       "diff-nochanges.ldif";
  /**
   * Make sure that the server is running, since we need it for schema
   * handling.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @BeforeClass()
  public void startServer()
         throws Exception
  {
    TestCaseUtils.startServer();
  }
  /**
   * Tests the LDIFDiff tool with an argument that will simply cause it to
   * display usage information.
   */
  @Test()
  public void testUsage()
  {
    String[] args =
    {
      "--help"
    };
    assertEquals(LDIFDiff.mainDiff(args, true), 0);
  }
  /**
   * Tests the LDIFDiff tool with an invalid set of arguments.
   */
  @Test()
  public void testInvalidArguments()
  {
    String[] args =
    {
      "--invalid"
    };
    assertFalse(LDIFDiff.mainDiff(args, true) == 0);
  }
  /**
   * Retrieves the names of the files that should be used when testing the
   * ldif-diff tool.  Each element of the outer array should be an array
   * containing the following elements:
   * <OL>
   *   <LI>The path to the source LDIF file</LI>
   *   <LI>The path to the target LDIF file</LI>
   *   <LI>The path to the diff file, or {@code null} if the diff is supposed
   *       to fail</LI>
   * </OL>
   */
  @DataProvider(name = "testdata")
  public Object[][] getTestData()
  {
    String buildRoot = System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT);
    String ldifRoot  = buildRoot + File.separator + "tests" + File.separator +
                       "unit-tests-testng" + File.separator + "resource" +
                       File.separator + "ldif-diff" + File.separator;
    return new Object[][]
    {
      // Both files are empty.
      new Object[] { ldifRoot + "source-empty.ldif",
                     ldifRoot + "target-empty.ldif",
                     noDiffsFile, noDiffsFile },
      // Both files are the single-entry source.
      new Object[] { ldifRoot + "source-singleentry.ldif",
                     ldifRoot + "source-singleentry.ldif",
                     noDiffsFile, noDiffsFile },
      // Both files are the single-entry target.
      new Object[] { ldifRoot + "target-singleentry.ldif",
                     ldifRoot + "target-singleentry.ldif",
                     noDiffsFile, noDiffsFile },
      // Both files are the multiple-entry source.
      new Object[] { ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "source-multipleentries.ldif",
                     noDiffsFile, noDiffsFile },
      // Both files are the multiple-entry target.
      new Object[] { ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "target-multipleentries.ldif",
                     noDiffsFile, noDiffsFile },
      // The source is empty but the target has a single entry.
      new Object[] { ldifRoot + "source-empty.ldif",
                     ldifRoot + "target-singleentry.ldif",
                     ldifRoot + "diff-emptytosingle.ldif",
                     ldifRoot + "diff-emptytosingle.ldif" },
      // The source has a single entry but the target is empty.
      new Object[] { ldifRoot + "source-singleentry.ldif",
                     ldifRoot + "target-empty.ldif",
                     ldifRoot + "diff-singletoempty.ldif",
                     ldifRoot + "diff-singletoempty.ldif" },
      // Make a change to only a single entry in the source->target direction.
      new Object[] { ldifRoot + "source-singleentry.ldif",
                     ldifRoot + "target-singleentry.ldif",
                     ldifRoot + "diff-singleentry.ldif",
                     ldifRoot + "diff-singleentry.ldif" },
      // Make a change to only a single entry in the target->source direction.
      new Object[] { ldifRoot + "target-singleentry.ldif",
                     ldifRoot + "source-singleentry.ldif",
                     ldifRoot + "diff-singleentry-reverse.ldif",
                     ldifRoot + "diff-singleentry-reverse.ldif" },
      // Make changes to multiple entries in the source->target direction.
      new Object[] { ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "diff-multipleentries.ldif",
                     ldifRoot + "diff-multipleentries-singlevalue.ldif" },
      // Make changes to multiple entries in the target->source direction.
      new Object[] { ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "diff-multipleentries-reverse.ldif",
                     ldifRoot +
                          "diff-multipleentries-reverse-singlevalue.ldif" },
      // Go from one entry to multiple in the source->target direction.
      new Object[] { ldifRoot + "source-singleentry.ldif",
                     ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "diff-singletomultiple.ldif",
                     ldifRoot + "diff-singletomultiple-singlevalue.ldif" },
      // Go from one entry to multiple in the target->source direction.
      new Object[] { ldifRoot + "target-singleentry.ldif",
                     ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "diff-singletomultiple-reverse.ldif",
                     ldifRoot + "diff-singletomultiple-reverse.ldif" },
      // Go from multiple entries to one in the source->target direction.
      new Object[] { ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "target-singleentry.ldif",
                     ldifRoot + "diff-multipletosingle.ldif",
                     ldifRoot + "diff-multipletosingle.ldif" },
      // Go from multiple entries to one in the target->source direction.
      new Object[] { ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "source-singleentry.ldif",
                     ldifRoot + "diff-multipletosingle-reverse.ldif",
                     ldifRoot +
                          "diff-multipletosingle-reverse-singlevalue.ldif" },
      // The source file doesn't exist.
      new Object[] { ldifRoot + "source-notfound.ldif",
                     ldifRoot + "target-singleentry.ldif",
                     null, null },
      // The target file doesn't exist.
      new Object[] { ldifRoot + "source-singleentry.ldif",
                     ldifRoot + "target-notfound.ldif",
                     null, null }
    };
  }
  /**
   * Tests the LDIFDiff tool with the provided information to ensure that the
   * normal mode of operation works as expected.  This is a bit tricky because
   * the attributes and values will be written in an indeterminite order, so we
   * can't just use string equality.  We'll have to use a crude checksum
   * mechanism to test whether they are equal.  Combined with other methods in
   * this class, this should be good enough.
   *
   * @param  sourceFile           The path to the file containing the source
   *                              data set.
   * @param  targetFile           The path to the file containing the target
   *                              data set.
   * @param  normalDiffFile       The path to the file containing the expected
   *                              diff in "normal" form (at most one record per
   *                              entry), or {@code null} if the diff is
   *                              supposed to fail.
   * @param  singleValueDiffFile  The path to the file containing the expected
   *                              diff in "single-value" form, where each
   *                              attribute-level change results in a separate
   *                              entry per attribute value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testVerifyNormal(String sourceFile, String targetFile,
                               String normalDiffFile,
                               String singleValueDiffFile)
         throws Exception
  {
    File outputFile = File.createTempFile("difftest", "ldif");
    outputFile.deleteOnExit();
    String[] args =
    {
      "-s", sourceFile,
      "-t", targetFile,
      "-o", outputFile.getAbsolutePath(),
      "-O"
    };
    if (normalDiffFile == null)
    {
      // We expect this to fail, so just make sure that it does.
      assertFalse(LDIFDiff.mainDiff(args, true) == 0);
      outputFile.delete();
      return;
    }
    assertEquals(LDIFDiff.mainDiff(args, true), 0);
    long outputChecksum = 0L;
    BufferedReader reader = new BufferedReader(new FileReader(outputFile));
    String line = reader.readLine();
    while (line != null)
    {
      outputChecksum += line.hashCode();
      line = reader.readLine();
    }
    reader.close();
    long expectedChecksum = 0L;
    reader = new BufferedReader(new FileReader(normalDiffFile));
    line = reader.readLine();
    while (line != null)
    {
      expectedChecksum += line.hashCode();
      line = reader.readLine();
    }
    reader.close();
    assertEquals(outputChecksum, expectedChecksum);
    outputFile.delete();
  }
  /**
   * Tests the LDIFDiff tool with the provided information to ensure that the
   * single value changes mode of operation works as expected.  This is a bit
   * tricky because the attributes and values will be written in an
   * indeterminite order, so we can't just use string equality.  We'll have to
   * use a crude checksum mechanism to test whether they are equal.  Combined
   * with other methods in this class, this should be good enough.
   *
   * @param  sourceFile           The path to the file containing the source
   *                              data set.
   * @param  targetFile           The path to the file containing the target
   *                              data set.
   * @param  normalDiffFile       The path to the file containing the expected
   *                              diff in "normal" form (at most one record per
   *                              entry), or {@code null} if the diff is
   *                              supposed to fail.
   * @param  singleValueDiffFile  The path to the file containing the expected
   *                              diff in "single-value" form, where each
   *                              attribute-level change results in a separate
   *                              entry per attribute value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testVerifySingleValue(String sourceFile, String targetFile,
                                    String normalDiffFile,
                                    String singleValueDiffFile)
         throws Exception
  {
    File outputFile = File.createTempFile("difftest", "ldif");
    outputFile.deleteOnExit();
    String[] args =
    {
      "-s", sourceFile,
      "-t", targetFile,
      "-o", outputFile.getAbsolutePath(),
      "-O",
      "-S"
    };
    if (singleValueDiffFile == null)
    {
      // We expect this to fail, so just make sure that it does.
      assertFalse(LDIFDiff.mainDiff(args, true) == 0);
      outputFile.delete();
      return;
    }
    assertEquals(LDIFDiff.mainDiff(args, true), 0);
    long outputChecksum = 0L;
    BufferedReader reader = new BufferedReader(new FileReader(outputFile));
    String line = reader.readLine();
    while (line != null)
    {
      outputChecksum += line.hashCode();
      line = reader.readLine();
    }
    reader.close();
    long expectedChecksum = 0L;
    reader = new BufferedReader(new FileReader(singleValueDiffFile));
    line = reader.readLine();
    while (line != null)
    {
      expectedChecksum += line.hashCode();
      line = reader.readLine();
    }
    reader.close();
    assertEquals(outputChecksum, expectedChecksum);
    outputFile.delete();
  }
  /**
   * Tests the LDIFDiff tool by first identifying the differences between the
   * source and the target and then using the LDIFModify tool to apply the
   * identified changes to the source LDIF and verify that it matches the
   * target.
   *
   * @param  sourceFile           The path to the file containing the source
   *                              data set.
   * @param  targetFile           The path to the file containing the target
   *                              data set.
   * @param  normalDiffFile       The path to the file containing the expected
   *                              diff in "normal" form (at most one record per
   *                              entry), or {@code null} if the diff is
   *                              supposed to fail.
   * @param  singleValueDiffFile  The path to the file containing the expected
   *                              diff in "single-value" form, where each
   *                              attribute-level change results in a separate
   *                              entry per attribute value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testReconstructNormal(String sourceFile, String targetFile,
                                    String normalDiffFile,
                                    String singleValueDiffFile)
         throws Exception
  {
    // If the command is expected to fail, or if there aren't any differences,
    // then bail out now.
    if ((normalDiffFile == null) || normalDiffFile.equals(noDiffsFile))
    {
      return;
    }
    // Generate the diff file.
    File diffOutputFile = File.createTempFile("difftest", "ldif");
    diffOutputFile.deleteOnExit();
    String[] args =
    {
      "-s", sourceFile,
      "-t", targetFile,
      "-o", diffOutputFile.getAbsolutePath()
    };
    assertEquals(LDIFDiff.mainDiff(args, true), 0);
    // Use LDIFModify to generate a new target file.
    File newTargetFile = File.createTempFile("difftest", "newtarget.ldif");
    newTargetFile.deleteOnExit();
    args = new String[]
    {
      "-c", DirectoryServer.getInstance().getConfigFile(),
      "-s", sourceFile,
      "-m", diffOutputFile.getAbsolutePath(),
      "-t", newTargetFile.getAbsolutePath()
    };
    assertEquals(LDIFModify.ldifModifyMain(args, true), 0);
    // Use LDIFDiff again to verify that there are effectively no differences
    // between the original target and the new target.
    File newDiffFile = File.createTempFile("difftest", "newdiff.ldif");
    newDiffFile.deleteOnExit();
    args = new String[]
    {
      "-s", targetFile,
      "-t", newTargetFile.getAbsolutePath(),
      "-o", newDiffFile.getAbsolutePath()
    };
    assertEquals(LDIFDiff.mainDiff(args, true), 0);
    // Read the contents of the new diff file and make sure it matches the
    // contents of the "no changes" diff file.
    long newDiffChecksum = 0L;
    BufferedReader reader = new BufferedReader(new FileReader(newDiffFile));
    String line = reader.readLine();
    while (line != null)
    {
      newDiffChecksum += line.hashCode();
      line = reader.readLine();
    }
    reader.close();
    long expectedChecksum = 0L;
    reader = new BufferedReader(new FileReader(noDiffsFile));
    line = reader.readLine();
    while (line != null)
    {
      expectedChecksum += line.hashCode();
      line = reader.readLine();
    }
    reader.close();
    assertEquals(newDiffChecksum, expectedChecksum);
    diffOutputFile.delete();
    newTargetFile.delete();
    newDiffFile.delete();
  }
  /**
   * Tests the LDIFDiff tool by first identifying the differences between the
   * source and the target (using the single-value format) and then using the
   * LDIFModify tool to apply the identified changes to the source LDIF and
   * verify that it matches the target.
   *
   * @param  sourceFile           The path to the file containing the source
   *                              data set.
   * @param  targetFile           The path to the file containing the target
   *                              data set.
   * @param  normalDiffFile       The path to the file containing the expected
   *                              diff in "normal" form (at most one record per
   *                              entry), or {@code null} if the diff is
   *                              supposed to fail.
   * @param  singleValueDiffFile  The path to the file containing the expected
   *                              diff in "single-value" form, where each
   *                              attribute-level change results in a separate
   *                              entry per attribute value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testReconstructSingleValue(String sourceFile, String targetFile,
                                         String normalDiffFile,
                                         String singleValueDiffFile)
         throws Exception
  {
    // If the command is expected to fail, or if there aren't any differences,
    // then bail out now.
    if ((normalDiffFile == null) || singleValueDiffFile.equals(noDiffsFile))
    {
      return;
    }
    // Generate the diff file.
    File diffOutputFile = File.createTempFile("difftest", "ldif");
    diffOutputFile.deleteOnExit();
    String[] args =
    {
      "-s", sourceFile,
      "-t", targetFile,
      "-o", diffOutputFile.getAbsolutePath(),
      "-S"
    };
    assertEquals(LDIFDiff.mainDiff(args, true), 0);
    // Use LDIFModify to generate a new target file.
    File newTargetFile = File.createTempFile("difftest", "newtarget.ldif");
    newTargetFile.deleteOnExit();
    args = new String[]
    {
      "-c", DirectoryServer.getInstance().getConfigFile(),
      "-s", sourceFile,
      "-m", diffOutputFile.getAbsolutePath(),
      "-t", newTargetFile.getAbsolutePath()
    };
    assertEquals(LDIFModify.ldifModifyMain(args, true), 0);
    // Use LDIFDiff again to verify that there are effectively no differences
    // between the original target and the new target.
    File newDiffFile = File.createTempFile("difftest", "newdiff.ldif");
    newDiffFile.deleteOnExit();
    args = new String[]
    {
      "-s", targetFile,
      "-t", newTargetFile.getAbsolutePath(),
      "-o", newDiffFile.getAbsolutePath()
    };
    assertEquals(LDIFDiff.mainDiff(args, true), 0);
    // Read the contents of the new diff file and make sure it matches the
    // contents of the "no changes" diff file.
    long newDiffChecksum = 0L;
    BufferedReader reader = new BufferedReader(new FileReader(newDiffFile));
    String line = reader.readLine();
    while (line != null)
    {
      newDiffChecksum += line.hashCode();
      line = reader.readLine();
    }
    reader.close();
    long expectedChecksum = 0L;
    reader = new BufferedReader(new FileReader(noDiffsFile));
    line = reader.readLine();
    while (line != null)
    {
      expectedChecksum += line.hashCode();
      line = reader.readLine();
    }
    reader.close();
    assertEquals(newDiffChecksum, expectedChecksum);
    diffOutputFile.delete();
    newTargetFile.delete();
    newDiffFile.delete();
  }
}