TestCaseUtils.java revision d25372dc8e65a9ed019a88fdf659ca61313f1b31
/*
* 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
* 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
*
*
* Copyright 2006-2008 Sun Microsystems, Inc.
*/
/**
* This class defines some utility functions which can be used by test
* cases.
*/
public final class TestCaseUtils {
/**
* The name of the system property that specifies the server build root.
*/
public static final String PROPERTY_BUILD_ROOT =
"org.opends.server.BuildRoot";
/**
* The name of the system property that specifies an existing OpenDS
* installation root (inside or outside of the source tree).
*/
public static final String PROPERTY_INSTALLED_ROOT =
"org.opends.server.InstalledRoot";
/**
* The name of the system property that specifies an LDIF file
* with changes compare to the default config.ldif.
*/
public static final String PROPERTY_CONFIG_CHANGE_FILE =
"org.opends.server.ConfigChangeFile";
/**
* The name of the system property that specifies the ldap port.
* Set this property when running the server if you want to use a given
* port number, otherwise a port is chosen randomly at test startup time.
*/
public static final String PROPERTY_LDAP_PORT =
"org.opends.server.LdapPort";
/**
* The name of the system property that specifies the admin port.
* Set this prtoperty when running the server if you want to use a given
* port number, otherwise a port is choosed randomly at test startup time.
*/
public static final String PROPERTY_ADMIN_PORT =
"org.opends.server.AdminPort";
/**
* If this System property is set to true, then the classes/ directory
* will be copied into the server package setup for the tests. This allows
* the server tools (e.g. ldapsearch) to be used on a live server, but it
* takes a while to copy all of the files, so we don't do it by default.
*/
public static final String PROPERTY_COPY_CLASSES_TO_TEST_PKG =
"org.opends.test.copyClassesToTestPackage";
/**
* The string representation of the DN that will be used as the base entry for
* the test backend. This must not be changed, as there are a number of test
* cases that depend on this specific value of "o=test".
*/
/**
* The backend if for the test backend
*/
/**
* The string representation of the OpenDMK jar file location
* that will be used as base to determine if snmp is included or not
*/
public static final String PROPERTY_OPENDMK_LOCATION =
"org.opends.server.snmp.opendmk";
/**
* The test text writer for the Debug Logger
*/
public static TestTextWriter DEBUG_TEXT_WRITER =
new TestTextWriter();
/**
* The test text writer for the Debug Logger
*/
public static TestTextWriter ERROR_TEXT_WRITER =
new TestTextWriter();
/**
* The test text writer for the Debug Logger
*/
public static TestTextWriter ACCESS_TEXT_WRITER =
new TestTextWriter();
/**
* Indicates whether the server has already been started. The value of this
* constant must not be altered by anything outside the
* <CODE>startServer</CODE> method.
*/
public static boolean SERVER_STARTED = false;
/**
* The LDAP port the server is bound to on start.
*/
private static int serverLdapPort;
/**
* The Administration port the server is bound to on start.
*/
private static int serverAdminPort;
/**
* The JMX port the server is bound to on start.
*/
private static int serverJmxPort;
/**
* The LDAPS port the server is bound to on start.
*/
private static int serverLdapsPort;
/**
* Incremented by one each time the server has restarted.
*/
private static int serverRestarts = 0;
/**
* Starts the Directory Server so that it will be available for use while
* running the unit tests. This will only actually start the server once, so
* subsequent attempts to start it will be ignored because it will already be
* available.
*
* @throws IOException If a problem occurs while interacting with the
* filesystem to prepare the test package root.
*
* @throws InitializationException If a problem occurs while starting the
* server.
*
* @throws ConfigException If there is a problem with the server
* configuration.
*/
public static void startServer()
{
try {
if (SERVER_STARTED)
{
return;
}
// Get the build root and use it to create a test package directory.
if (testInstallRoot.exists())
{
}
if (testInstanceRoot.exists())
{
}
// Retrieves the location of a typical installation directory to use as a
// source to build our test instance.
//db_verify is second jeb backend used by the jeb verify test cases
//db_rebuild is the third jeb backend used by the jeb rebuild test cases
//db_unindexed is the forth backend used by the unindexed search privilege
//test cases
"config", "db", "import-tmp", "db_verify",
"ldif", "locks", "logs", "db_rebuild",
"db_unindexed", "db_index_test",
"db_import_test"};
for (String s : installSubDirectories)
{
}
for (String s : instanceSubDirectories)
{
}
// Copy the configuration, schema, and MakeLDIF resources into the
// appropriate place under the test package.
// Snmp resource
"resource");
"snmp");
{
}
if (installedRoot != null)
{
// Get the instance location
}
else
{
// Update the install.loc file
+ "instance.loc");
w.close();
if (opendmkJar.exists())
{
}
{
try
{
} catch (Exception e) {}
}
// Make the shell scripts in the bin directory executable, if possible.
{
try
{
{
{
}
}
} catch (Exception e) {}
}
}
// Find some free ports for the listeners and write them to the
// config-chamges.ldif file.
{
}
else
{
}
{
}
else
{
}
+ "config-changes.ldif";
new File(configChangeFile)));
{
}
// Create a configuration for the server.
config.setForceDaemonThreads(true);
ACCESS_TEXT_WRITER, false));
// Save config.ldif for when we restart the server
SERVER_STARTED = true;
initializeTestBackend(true);
} catch (IOException e) {
throw e;
} catch (NumberFormatException e) {
throw e;
} catch (InitializationException e) {
throw e;
} catch (ConfigException e) {
throw e;
} catch (DirectoryException e) {
throw e;
}
}
/**
* Similar to startServer, but it will restart the server each time it is
* called. Since this is somewhat expensive, it should be called under
* two circumstances. Either in an @AfterClass method for a test that
* makes lots of configuration changes to the server, or in a @BeforeClass
* method for a test that is very sensitive to running in a clean server.
*
* @throws IOException If a problem occurs while interacting with the
* filesystem to prepare the test package root.
*
* @throws InitializationException If a problem occurs while starting the
* server.
*
* @throws ConfigException If there is a problem with the server
* configuration.
*/
public static synchronized void restartServer()
{
if (!SERVER_STARTED) {
startServer();
return;
}
try {
// We need it to be recreated and reregistered
if (memoryBackend != null)
{
}
initializeTestBackend(true);
// This generates too much noise, so it's disabled by default.
// outputLogContentsIfError("Potential problem during in-core restart. You be the judge.");
// Keep track of these so we can report how long they took in the test summary
} catch (Exception e) {
throw e;
}
}
}
}
}
private static void clearJEBackends() throws Exception
{
if (backend instanceof BackendImpl) {
}
}
}
public static void clearDataBackends() throws Exception
{
if (memoryBackend != null)
}
private static File getTestConfigDir()
{
}
public static File getBuildRoot()
{
}
private static void backupServerConfigLdif() throws IOException
{
}
private static void restoreServerConfigLdif() throws IOException {
// Sometimes this fails because config.ldif is in use, so we wait
// and try it again.
try {
} catch (IOException e) {
sleep(1000);
}
}
/**
* Bring the server to a quiescent state. This includes waiting for all
* operations to complete. This can be used in a @BeforeMethod setup method
* to make sure that the server has finished processing all operations
* from previous tests.
*/
public static void quiesceServer()
{
}
/**
* This can be made public if quiesceServer becomes too heavy-weight in
* some circumstance.
*/
private static void waitForOpsToComplete()
{
try {
final long NO_TIMEOUT = -1;
} catch (Exception e) {
// Ignore it, maybe the server hasn't been started.
}
}
/**
* Binds to the given socket port on the local host.
* @return the bounded Server socket.
*
* @throws IOException in case of underlying exception.
* @throws SocketException in case of underlying exception.
*/
throws IOException
{
serverLdapSocket = new ServerSocket();
serverLdapSocket.setReuseAddress(true);
return serverLdapSocket;
}
/**
* Find and binds to a free server socket port on the local host.
* @return the bounded Server socket.
*
* @throws IOException in case of underlying exception.
* @throws SocketException in case of underlying exception.
*/
{
serverLdapSocket = new ServerSocket();
serverLdapSocket.setReuseAddress(true);
return serverLdapSocket;
}
/**
* Shut down the server, if it has been started.
* @param reason The reason for the shutdown.
*/
{
}
/**
* Shut down the server, if it has been started.
* @param reason The reason for the shutdown.
*/
{
if (SERVER_STARTED)
{
SERVER_STARTED = false;
}
}
/**
* Initializes a memory-based backend that may be used to perform operations
* while testing the server. This will ensure that the memory backend is
* created in the server if it does not yet exist, and that it is empty. Note
* that the base DN for the test backend will always be "o=test", and it must
* not be changed. It is acceptable for test cases using this backend to
* hard-code their sample data to use this base DN, although they may still
* reference the <CODE>TEST_ROOT_DN_STRING</CODE> constant if they wish.
*
* @param createBaseEntry Indicate whether to automatically create the base
* entry and add it to the backend.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void initializeTestBackend(boolean createBaseEntry)
{
startServer();
// Retrieve backend. Warning: it is important to perform this each time,
// because a test may have disabled then enabled the backend (i.e a test
// performing an import task). As it is a memory backend, when the backend
// is re-enabled, a new backend object is in fact created and old reference
// to memory backend must be invalidated. So to prevent this problem, we
// retrieve the memory backend reference each time before cleaning it.
if (memoryBackend == null)
{
memoryBackend = new MemoryBackend();
}
if (createBaseEntry)
{
}
}
/**
* Clears all the entries from the JE backend determined by the
* be id passed into the method.
* @param createBaseEntry Indicate whether to automatically create the base
* entry and add it to the backend.
*
* @param beID The be id to clear.
*
* @param dn The suffix of the backend to create if the the createBaseEntry
* boolean is true.
*
* @throws Exception If an unexpected problem occurs.
*/
throws Exception
{
if (rootContainer != null) {
{
}
if (createBaseEntry)
{
}
}
}
/**
* This was used to track down which test was trashing the indexes.
* We left it here because it might be useful again.
*/
public static void printUntrustedIndexes()
{
try {
return;
}
{
if (dbContainer instanceof Index) {
}
}
}
}
} catch (Exception e) {
}
}
/**
* Create a temporary directory with the specified prefix.
*
* @param prefix
* The directory prefix.
* @return The temporary directory.
* @throws IOException
* If the temporary directory could not be created.
*/
throws IOException {
if (!tempDirectory.delete()) {
throw new IOException("Unable to delete temporary file: "
+ tempDirectory);
}
if (!tempDirectory.mkdir()) {
throw new IOException("Unable to create temporary directory: "
+ tempDirectory);
}
return tempDirectory;
}
/**
* Copy a directory and its contents.
*
* @param src
* The name of the directory to copy.
* @param dst
* The name of the destination directory.
* @throws IOException
* If the directory could not be copied.
*/
if (src.isDirectory()) {
// Create the destination directory if it does not exist.
}
// Recursively copy sub-directories and files.
}
} else {
}
}
/**
* Delete a directory and its contents.
*
* @param dir
* The name of the directory to delete.
* @throws IOException
* If the directory could not be deleted.
*/
if (dir.isDirectory()) {
// Recursively delete sub-directories and files.
}
}
}
/**
* Copy a file.
*
* @param src
* The name of the source file.
* @param dst
* The name of the destination file.
* @throws IOException
* If the file could not be copied.
*/
// Transfer bytes from in to out
byte[] buf = new byte[8192];
int len;
}
}
// Transfer bytes from in to out
byte[] buf = new byte[8192];
int len;
}
}
/**
* Get the LDAP port the test environment Directory Server instance is
* running on.
*
* @return The port number.
*/
public static int getServerLdapPort()
{
return serverLdapPort;
}
/**
* Get the Admin port the test environment Directory Server instance is
* running on.
*
* @return The port number.
*/
public static int getServerAdminPort()
{
return serverAdminPort;
}
/**
* Get the JMX port the test environment Directory Server instance is
* running on.
*
* @return The port number.
*/
public static int getServerJmxPort()
{
return serverJmxPort;
}
/**
* Get the LDAPS port the test environment Directory Server instance is
* running on.
*
* @return The port number.
*/
public static int getServerLdapsPort()
{
return serverLdapsPort;
}
/**
* Get the number of times the server has done an incore restart during
* the unit tests.
*
* @return the number of server restarts.
*/
public static int getNumServerRestarts()
{
return serverRestarts;
}
/**
* Method for getting a file from the test resources directory.
*
* @return The directory as a File
*/
{
}
/**
* Prevent instantiation.
*/
private TestCaseUtils() {
// No implementation.
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//
// Various methods for converting LDIF Strings to Entries
//
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
/**
* Returns a modifiable List of entries parsed from the provided LDIF.
* It's best to call this after the server has been initialized so
* that schema checking happens.
* <p>
* Also take a look at the makeLdif method below since this makes
* expressing LDIF a little bit cleaner.
*
* @param ldif of the entries to parse.
* @return a List of EntryS parsed from the ldif string.
* @see #makeLdif
*/
}
return entries;
}
/**
* This is used as a convenience when and LDIF string only includes a single
* entry. It's best to call this after the server has been initialized so
* that schema checking happens.
* <p>
* Also take a look at the makeLdif method below since this makes
* expressing LDIF a little bit cleaner.
*
* @return the first Entry parsed from the ldif String
* @see #makeLdif
*/
}
/**
* This method provides the minor convenience of not having to specify the
* newline character at the end of every line of LDIF in test code.
* This is an admittedly small advantage, but it does make things a little
* easier and less error prone. For example, this
*
<pre>
private static final String JOHN_SMITH_LDIF = TestCaseUtils.makeLdif(
"dn: cn=John Smith,dc=example,dc=com",
"objectclass: inetorgperson",
"cn: John Smith",
"sn: Smith",
"givenname: John");
</pre>
is a <bold>little</bold> easier to work with than
<pre>
private static final String JOHN_SMITH_LDIF =
"dn: cn=John Smith,dc=example,dc=com\n" +
"objectclass: inetorgperson\n" +
"cn: John Smith\n" +
"sn: Smith\n" +
"givenname: John\n";
</pre>
*
* @return the concatenation of each line followed by a newline character
*/
}
// Append an extra line so we can append LDIF Strings.
}
/**
* This is a convenience method that constructs an Entry from the specified
* lines of LDIF. Here's a sample usage
*
<pre>
Entry john = TestCaseUtils.makeEntry(
"dn: cn=John Smith,dc=example,dc=com",
"objectclass: inetorgperson",
"cn: John Smith",
"sn: Smith",
"givenname: John");
</pre>
* @see #makeLdif
*/
}
/**
* This is a convenience method that constructs an List of EntryS from the
* specified lines of LDIF. Here's a sample usage
*
<pre>
List<Entry> smiths = TestCaseUtils.makeEntries(
"dn: cn=John Smith,dc=example,dc=com",
"objectclass: inetorgperson",
"cn: John Smith",
"sn: Smith",
"givenname: John",
"",
"dn: cn=Jane Smith,dc=example,dc=com",
"objectclass: inetorgperson",
"cn: Jane Smith",
"sn: Smith",
"givenname: Jane");
</pre>
* @see #makeLdif
*/
}
/**
* Adds the provided entry to the Directory Server using an internal
* operation.
*
* @param entry The entry to be added.
*
* @throws Exception If an unexpected problem occurs.
*/
throws Exception
{
}
/**
* Deletes the provided entry from the Directory Server using an
* internal operation.
*
* @param entry The entry to be added.
*
* @throws Exception If an unexpected problem occurs.
*/
throws Exception
{
}
{
// Check that the user can bind.
try {
ASN1Reader r = new ASN1Reader(s);
ASN1Writer w = new ASN1Writer(s);
r.setIOTimeout(3000);
new ASN1OctetString(dn),
3,
new ASN1OctetString(pw));
return true;
}
} catch (Exception t) {
t.printStackTrace();
} finally {
if (s != null) {
s.close();
}
}
return false;
}
/**
* Adds the provided entry to the Directory Server using an internal
* operation.
*
* @param lines The lines that make up the entry to be added.
*
* @throws Exception If an unexpected problem occurs.
*/
throws Exception
{
.getErrorMessage().toString());
}
/**
* Adds the provided set of entries to the Directory Server using internal
* operations.
*
* @param entries The entries to be added.
*
* @throws Exception If an unexpected problem occurs.
*/
throws Exception
{
{
}
}
/**
* Adds the provided set of entries to the Directory Server using internal
* operations.
*
* @param lines The lines defining the entries to add. If there are
* multiple entries, then they should be separated by blank
* lines.
*
* @throws Exception If an unexpected problem occurs.
*/
throws Exception
{
{
}
}
/**
* Applies a set of modifications to the server as described in the provided
* set of lines (using LDIF change form). The changes will be applied over
* LDAP using the ldapmodify tool using the "cn=Directory Manager" account.
*
* @param lines The set of lines including the changes to make to the
* server.
*
* @return The result code from applying the set of modifications. if it is
* nonzero, then there was a failure of some kind.
*
* @throws Exception If an unexpected problem occurs.
*/
throws Exception
{
if (! SERVER_STARTED)
{
startServer();
}
{
"--noPropertiesFile",
"-h", "127.0.0.1",
"-D", "cn=Directory Manager",
"-w", "password",
"-a",
"-f", path
};
{
"--noPropertiesFile",
"-h", "127.0.0.1",
"-Z", "-X",
"-D", "cn=Directory Manager",
"-w", "password",
"-a",
"-f", path
};
if (useAdminPort) {
} else {
}
}
/**
* Creates a temporary text file with the specified contents. It will be
* marked for automatic deletion when the JVM exits.
*
* @return The absolute path to the file that was created.
*
* @throws Exception If an unexpected problem occurs.
*/
throws Exception
{
f.deleteOnExit();
FileWriter w = new FileWriter(f);
{
}
w.close();
return f.getAbsolutePath();
}
/** Convenience method so we don't have to catch InterruptedException everywhere. */
try {
} catch (InterruptedException e) {
// Ignore it.
}
}
/**
* Return a Map constructed via alternating key and value pairs.
*/
}
return map;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// The set of loggers for which the console logger has been disabled.
/** The original System.err print stream. Use this if you absolutely
* must write something to System.err. */
/** The original System.out print stream. Use this if you absolutely
* must write something to System.out. */
/** System.err is redirected to here so that we can only print it out
* if a test fails. */
/** System.out is redirected to here so that we can only print it out
* if a test fails. */
public synchronized static void suppressOutput() {
{
while (loggerNames.hasMoreElements())
{
{
if (h instanceof ConsoleHandler)
{
logger.removeHandler(h);
break;
}
}
}
}
}
/**
* @return everything written to System.out since the last time
* clearSystemOutContents was called.
*/
public synchronized static String getSystemOutContents() {
return redirectedSystemOut.toString();
}
/**
* @return everything written to System.err since the last time
* clearSystemErrContents was called.
*/
public synchronized static String getSystemErrContents() {
return redirectedSystemErr.toString();
}
/**
* clear everything written to System.out since the last time
* clearSystemOutContents was called.
*/
public synchronized static void clearSystemOutContents() {
}
/**
* clear everything written to System.err since the last time
* clearSystemErrContents was called.
*/
public synchronized static void clearSystemErrContents() {
}
/**
* clear everything written to the Access, Error, or Debug loggers
*/
public synchronized static void clearLoggersContents() {
}
/**
* Append the contents of the Access Log, Error Log, Debug Loggers,
* System.out, System.err to the specified buffer.
*/
{
{
{
}
}
{
{
}
}
{
{
}
}
}
}
}
public synchronized static void unsupressOutput() {
{
l.addHandler(h);
}
}
/**
* Read the contents of a file and return it as a String.
*/
throws IOException {
}
/**
* Read the contents of a file and return it as a String.
*/
throws IOException {
}
/**
* Returns the contents of file as a List of the lines as defined by
* java.io.BufferedReader#readLine() (i.e. the line terminator is not
* included). An ArrayList is explicitly returned, so that callers know that
* random access is not expensive.
*/
throws IOException {
new BufferedReader(
new InputStreamReader(
new DataInputStream(
new FileInputStream(file))));
}
return lines;
}
/**
* Read the contents of a file and return it as a String.
*/
throws IOException {
byte[] bytes;
return bytes;
}
/**
* @param close - if true, close when finished reading.
* @return input stream content.
*/
throws IOException {
try {
byte[] buf = new byte[1024];
int bytesRead;
} // end of while ((read(buf) != -1)
}
finally {
try {
}
// ignore these
}
} // end of if (is != null)
}
}
return bytes;
}
/**
* Store the contents of a String in a file.
*/
throws IOException {
}
/**
* Store the contents of a String in a file.
*/
throws IOException {
}
/**
* Store the contents of a String in a file.
*/
throws IOException {
try {
} finally {
try {
}
// ignore these
}
}
}
/**
* Invokes the dsconfig tool with the provided set of arguments. Note that
* the address, port, bind DN (cn=Directory Manager), and password will always
* be provided, so they should not be included in the argument list. The
* given arguments should include only the subcommand and its associated
* options, along with any other global options that may not be included by
* default.
* <BR><BR>
* An assertion will be used to ensure that the dsconfig invocation is
* successful. If running dsconfig returns a non-zero result, then an
* assertion error will be thrown.
*
* @param args The set of arguments that should be provided when invoking
* the dsconfig tool
*/
{
try {
} catch (Exception e) {
}
}
/**
* Gets the root configuration associated with the active server
* instance. This root configuration can then be used to access and
* modify the server's configuration using that administration
* framework's strongly typed API.
* <p>
* Note: were possible the {@link #dsconfig(String...)} method
* should be used in preference to this method in order to perform
* end-to-end testing.
*
* @return Returns the root configuration associated with the active
* server instance.
* @throws Exception
* If the management context could not be initialized
* against the active server instance.
*/
{
"127.0.0.1",
"cn=Directory Manager",
"password");
return context.getRootConfiguration();
}
/**
* Return a String representation of all of the current threads.
* @return a dump of all Threads on the server
*/
public static String threadStacksToString()
{
// Re-arrange all of the elements by thread ID so that there is some logical
// order.
{
}
{
if (stackElements != null)
{
{
if (stackElements[j].isNativeMethod())
{
}
else
{
}
}
}
}
}
}