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

ludovicp
02.38.2008 8420e42dfb20a5074de8453a24749c36c115ea08
Fix to defect 1805: Added options to LDIFdiff to ignore specific attributes or entries when comparing LDIF files.
--ignoreattrs (-a) <FILE>
--ignoreentries (-e) <FILE>
Contribution from Gautam Gopalakrishnan, Sun Microsystems, Inc.
4 files added
3 files modified
519 ■■■■ changed files
opends/src/messages/messages/tools.properties 12 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDIFDiff.java 128 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-ignore-attributes.ldif 41 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-ignore-entries.ldif 35 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/resource/ldif-diff/ignore-attributes 2 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/resource/ldif-diff/ignore-entries 4 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDIFDiffTestCase.java 297 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/tools.properties
@@ -2359,5 +2359,13 @@
 that the provided trust store exists and that you have read access rights to it
SEVERE_ERR_CANNOT_READ_KEYSTORE_1611=Cannot access key store '%s'.  Verify \
 that the provided key store exists and that you have read access rights to it
INFO_LDIFDIFF_DESCRIPTION_IGNORE_ATTRS_1612=File containing a list of attributes \
 to ignore when computing the difference
INFO_LDIFDIFF_DESCRIPTION_IGNORE_ENTRIES_1613=File containing a list of entries (DN) \
 to ignore when computing the difference
SEVERE_ERR_LDIFDIFF_CANNOT_READ_FILE_IGNORE_ENTRIES_1614=An error occurred while attempting \
 to read the file '%s' containing the list of ignored entries: %s
SEVERE_ERR_LDIFDIFF_CANNOT_READ_FILE_IGNORE_ATTRIBS_1615=An error occurred while attempting \
 to read the file '%s' containing the list of ignored attributes: %s
INFO_LDIFDIFF_CANNOT_PARSE_STRING_AS_DN_1616=The string '%s' from file '%s' could \
 not be parsed as a dn
opends/src/server/org/opends/server/tools/LDIFDiff.java
@@ -27,15 +27,18 @@
package org.opends.server.tools;
import org.opends.messages.Message;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.TreeMap;
import org.opends.server.core.DirectoryServer;
@@ -45,6 +48,7 @@
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.ExistingFileBehavior;
import org.opends.server.types.LDIFImportConfig;
@@ -166,6 +170,8 @@
    StringArgument  outputLDIF;
    StringArgument  sourceLDIF;
    StringArgument  targetLDIF;
    StringArgument  ignoreAttrsFile;
    StringArgument  ignoreEntriesFile;
    Message toolDescription = INFO_LDIFDIFF_TOOL_DESCRIPTION.get();
@@ -191,6 +197,18 @@
              INFO_LDIFDIFF_DESCRIPTION_OUTPUT_LDIF.get());
      argParser.addArgument(outputLDIF);
      ignoreAttrsFile = new StringArgument(
              "ignoreattrs", 'a', "ignoreAttrs", false,
              false, true, INFO_FILE_PLACEHOLDER.get(), null, null,
              INFO_LDIFDIFF_DESCRIPTION_IGNORE_ATTRS.get());
      argParser.addArgument(ignoreAttrsFile);
      ignoreEntriesFile = new StringArgument(
              "ignoreentries", 'e', "ignoreEntries", false,
              false, true, INFO_FILE_PLACEHOLDER.get(), null, null,
              INFO_LDIFDIFF_DESCRIPTION_IGNORE_ENTRIES.get());
      argParser.addArgument(ignoreEntriesFile);
      overwriteExisting =
           new BooleanArgument(
                   "overwriteexisting", 'O',
@@ -314,6 +332,82 @@
      }
    }
    // Read in ignored entries and attributes if any
    BufferedReader ignReader = null;
    Collection<DN> ignoreEntries = new HashSet<DN>();
    Collection<String> ignoreAttrs   = new HashSet<String>();
    if (ignoreAttrsFile.getValue() != null)
    {
      try
      {
        ignReader = new BufferedReader(
          new FileReader(ignoreAttrsFile.getValue()));
        String line = null;
        while ((line = ignReader.readLine()) != null)
        {
          ignoreAttrs.add(line.toLowerCase());
        }
        ignReader.close();
      }
      catch (Exception e)
      {
        Message message = ERR_LDIFDIFF_CANNOT_READ_FILE_IGNORE_ATTRIBS.get(
                ignoreAttrsFile.getValue(),
                String.valueOf(e));
        err.println(message);
        return 1;
      }
      finally
      {
        try
        {
          ignReader.close();
        }
        catch (Exception e) {}
      }
    }
    if (ignoreEntriesFile.getValue() != null)
    {
      try
      {
        ignReader = new BufferedReader(
          new FileReader(ignoreEntriesFile.getValue()));
        String line = null;
        while ((line = ignReader.readLine()) != null)
        {
          try
          {
            DN dn = DN.decode(line);
            ignoreEntries.add(dn);
          }
          catch (DirectoryException e)
          {
            Message message = INFO_LDIFDIFF_CANNOT_PARSE_STRING_AS_DN.get(
                    line, ignoreEntriesFile.getValue());
            err.println(message);
          }
        }
        ignReader.close();
      }
      catch (Exception e)
      {
        Message message = ERR_LDIFDIFF_CANNOT_READ_FILE_IGNORE_ENTRIES.get(
                ignoreEntriesFile.getValue(),
                String.valueOf(e));
        err.println(message);
        return 1;
      }
      finally
      {
        try
        {
          ignReader.close();
        }
        catch (Exception e) {}
      }
    }
    // Open the source LDIF file and read it into a tree map.
    LDIFReader reader;
@@ -342,7 +436,10 @@
          break;
        }
        sourceMap.put(entry.getDN(), entry);
        if (! ignoreEntries.contains(entry.getDN()))
        {
          sourceMap.put(entry.getDN(), entry);
        }
      }
    }
    catch (Exception e)
@@ -388,7 +485,10 @@
          break;
        }
        targetMap.put(entry.getDN(), entry);
        if (! ignoreEntries.contains(entry.getDN()))
        {
          targetMap.put(entry.getDN(), entry);
        }
      }
    }
    catch (Exception e)
@@ -550,7 +650,7 @@
          {
            // The DNs are the same, so check to see if the entries are the
            // same or have been modified.
            if (writeModify(writer, sourceEntry, targetEntry,
            if (writeModify(writer, sourceEntry, targetEntry, ignoreAttrs,
                            singleValueChanges.isPresent()))
            {
              differenceFound = true;
@@ -678,6 +778,8 @@
   *                             written.
   * @param  sourceEntry         The source form of the entry.
   * @param  targetEntry         The target form of the entry.
   * @param  ignoreAttrs         Attributes that are ignored while calculating
   *                             the differences.
   * @param  singleValueChanges  Indicates whether each attribute-level change
   *                             should be written in a separate modification
   *                             per attribute value.
@@ -689,7 +791,7 @@
   *                       change record.
   */
  private static boolean writeModify(LDIFWriter writer, Entry sourceEntry,
                                     Entry targetEntry,
                                     Entry targetEntry, Collection ignoreAttrs,
                                     boolean singleValueChanges)
          throws IOException
  {
@@ -854,6 +956,19 @@
      }
    }
    // Remove ignored attributes
    if (! ignoreAttrs.isEmpty())
    {
      ListIterator<Modification> modIter = modifications.listIterator();
      while (modIter.hasNext())
      {
        String name = modIter.next().getAttribute().getName().toLowerCase();
        if (ignoreAttrs.contains(name))
        {
            modIter.remove();
        }
      }
    }
    // Write the modification change record.
    if (modifications.isEmpty())
@@ -902,4 +1017,3 @@
    }
  }
}
opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-ignore-attributes.ldif
New file
@@ -0,0 +1,41 @@
dn: dc=example,dc=com
changetype: modify
add: o
o: Example Corp.
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: cn=Test User,ou=People,dc=example,dc=com
changetype: add
objectClass: person
objectClass: organizationalPerson
objectClass: top
objectClass: inetOrgPerson
cn: Test User
sn: User
uid: test.user
userPassword: password
givenName: Test
dn: uid=test.user,ou=People,dc=example,dc=com
changetype: delete
# objectClass: person
# objectClass: organizationalPerson
# objectClass: top
# objectClass: inetOrgPerson
# cn: Test User
# sn: User
# uid: test.user
# userPassword: password
# givenName: Test
opends/tests/unit-tests-testng/resource/ldif-diff/diff-multipleentries-ignore-entries.ldif
New file
@@ -0,0 +1,35 @@
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: cn=Test User,ou=People,dc=example,dc=com
changetype: add
objectClass: person
objectClass: organizationalPerson
objectClass: top
objectClass: inetOrgPerson
cn: Test User
sn: User
uid: test.user
userPassword: password
givenName: Test
opends/tests/unit-tests-testng/resource/ldif-diff/ignore-attributes
New file
@@ -0,0 +1,2 @@
description
objectcLASs
opends/tests/unit-tests-testng/resource/ldif-diff/ignore-entries
New file
@@ -0,0 +1,4 @@
OU=PEOpLE,Dc=exaMPLE,DC=COM
uid=test.user,ou=People,dc=example,dc=com
a b c
ou=Groups, dc=example, dc=com
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/LDIFDiffTestCase.java
@@ -77,6 +77,27 @@
  }
  /**
   * Calculates the checksum of a file
   */
  private long calcChecksum(String filename) throws Exception
  {
    return calcChecksum(new File(filename));
  }
  private long calcChecksum(File file) throws Exception
  {
    long checksum = 0L;
    BufferedReader reader = new BufferedReader(new FileReader(file));
    String line = null;
    while ((line =reader.readLine()) != null)
    {
      checksum += line.hashCode();
    }
    reader.close();
    return checksum;
  }
  /**
   * Tests the LDIFDiff tool with an argument that will simply cause it to
@@ -234,8 +255,6 @@
  }
  /**
   * 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
@@ -285,29 +304,7 @@
    }
    assertEquals(LDIFDiff.mainDiff(args, true, System.out, System.err), 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);
    assertEquals(calcChecksum(outputFile), calcChecksum(normalDiffFile));
    outputFile.delete();
  }
@@ -364,29 +361,7 @@
    }
    assertEquals(LDIFDiff.mainDiff(args, true, System.out, System.err), 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);
    assertEquals(calcChecksum(outputFile), calcChecksum(singleValueDiffFile));
    outputFile.delete();
  }
@@ -470,31 +445,7 @@
    };
    assertEquals(LDIFDiff.mainDiff(args, true, System.out, System.err), 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);
    assertEquals(calcChecksum(newDiffFile), calcChecksum(noDiffsFile));
    diffOutputFile.delete();
    newTargetFile.delete();
@@ -582,35 +533,185 @@
    };
    assertEquals(LDIFDiff.mainDiff(args, true, System.out, System.err), 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);
    assertEquals(calcChecksum(newDiffFile), calcChecksum(noDiffsFile));
    diffOutputFile.delete();
    newTargetFile.delete();
    newDiffFile.delete();
  }
  /**
   * 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 file with attributes to be ignored</LI>
   *   <LI>The path to the diff file</LI>
   * </OL>
   */
  @DataProvider(name = "ignoreattributesdata")
  public Object[][] getIATestData()
  {
    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[][]
    {
      // Make changes to multiple entries in the target->source direction.
      new Object[] { ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "ignore-attributes",
                     ldifRoot + "diff-multipleentries-ignore-attributes.ldif" },
      new Object[] { ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "does-not-exist",
                     ldifRoot + "diff-multipleentries-ignore-attributes.ldif" }
    };
  }
  /**
   * 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.
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "ignoreattributesdata")
  public void testVerifyIgnoreAttributes(String sourceFile, String targetFile,
                               String ignoreAttributesFile,
                               String normalDiffFile)
         throws Exception
  {
    File outputFile = File.createTempFile("difftest", "ldif");
    outputFile.deleteOnExit();
    String[] args =
    {
      "-s", sourceFile,
      "-t", targetFile,
      "-a", ignoreAttributesFile,
      "-o", outputFile.getAbsolutePath(),
      "-O"
    };
    if (ignoreAttributesFile.endsWith("/does-not-exist"))
    {
      // We expect this to fail, so just make sure that it does.
      assertEquals(LDIFDiff.mainDiff(args, true, System.out, System.err), 1);
      return;
    }
    assertEquals(LDIFDiff.mainDiff(args, true, System.out, System.err), 0);
    assertEquals(calcChecksum(outputFile), calcChecksum(normalDiffFile));
    outputFile.delete();
  }
  /**
   * 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 file with entries to be ignored</LI>
   *   <LI>The path to the diff file</LI>
   * </OL>
   */
  @DataProvider(name = "ignoreentriesdata")
  public Object[][] getIETestData()
  {
    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[][]
    {
      // Make changes to multiple entries in the target->source direction.
      new Object[] { ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "ignore-entries",
                     ldifRoot + "diff-multipleentries-ignore-entries.ldif" },
      new Object[] { ldifRoot + "source-multipleentries.ldif",
                     ldifRoot + "target-multipleentries.ldif",
                     ldifRoot + "does-not-exist",
                     ldifRoot + "diff-multipleentries-ignore-entries.ldif" }
    };
  }
  /**
   * 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.
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "ignoreentriesdata")
  public void testVerifyIgnoreEntries(String sourceFile, String targetFile,
                               String ignoreEntriesFile,
                               String normalDiffFile)
         throws Exception
  {
    File outputFile = File.createTempFile("difftest", "ldif");
    outputFile.deleteOnExit();
    String[] args =
    {
      "-s", sourceFile,
      "-t", targetFile,
      "-e", ignoreEntriesFile,
      "-o", outputFile.getAbsolutePath(),
      "-O"
    };
    if (ignoreEntriesFile.endsWith("/does-not-exist"))
    {
      // We expect this to fail, so just make sure that it does.
      assertEquals(LDIFDiff.mainDiff(args, true, System.out, System.err), 1);
      return;
    }
    assertEquals(LDIFDiff.mainDiff(args, true, System.out, System.err), 0);
    assertEquals(calcChecksum(outputFile), calcChecksum(normalDiffFile));
    outputFile.delete();
  }
}