db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From krist...@apache.org
Subject svn commit: r1330751 - in /db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit: DerbyDistribution.java ReleaseRepository.java
Date Thu, 26 Apr 2012 10:20:59 GMT
Author: kristwaa
Date: Thu Apr 26 10:20:58 2012
New Revision: 1330751

URL: http://svn.apache.org/viewvc?rev=1330751&view=rev
Log:
DERBY-5475: Formalize use of old Derby distributions in tests

Added a very simple repository for Derby releases. It is compatible with
the existing property used to control where the tests look for old
releases (i.e. the upgrade and the compatibility test):
  derbyTesting.oldReleasePath
Added two new classes in the junit test framework directory:
 o ReleaseRepository
   The repository, from which you can obtain a list of available Derby
   distributions that exist on the local machine.
 o DerbyDistribution
   Represents an on-disk, JAR-based Derby distribution.

The initial repository is very simple, I expect that its functionality may
be somewhat extended as tests start using it.

Patch file: derby-5475-3a-repository.diff

Added:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DerbyDistribution.java
  (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/ReleaseRepository.java
  (with props)

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DerbyDistribution.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DerbyDistribution.java?rev=1330751&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DerbyDistribution.java
(added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DerbyDistribution.java
Thu Apr 26 10:20:58 2012
@@ -0,0 +1,321 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.junit.DerbyDistribution
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.derbyTesting.junit;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests;
+
+/**
+ * Holds information required to run a Derby distribution and make choices
+ * based on the version of the Derby distribution.
+ * <p>
+ * <em>Implementation note</em>: For simplicity distributions off the classes
+ * directory has been forbidden. The main reason for this is that it is
+ * sometimes a hard requirement that you must include only a single JAR from a
+ * distribution on the classpath. One such example is the compatibility test,
+ * where you need the testing code from one distribution and the client driver
+ * from another. While it is possible to support such a configuration in many
+ * scenarios, it complicates things quite a bit. Generating the JARs when
+ * testing on trunk seems like an acceptable price to pay.
+ */
+public class DerbyDistribution
+        implements Comparable {
+
+    private static File[] EMPTY_FILE_ARRAY = new File[] {};
+    public static final String JAR_RUN = "derbyrun.jar";
+    public static final String JAR_CLIENT = "derbyclient.jar";
+    public static final String JAR_ENGINE = "derby.jar";
+    public static final String JAR_NET = "derbynet.jar";
+    public static final String JAR_TESTING = "derbyTesting.jar";
+    private static final String[] REQUIRED_JARS = {
+        JAR_ENGINE, JAR_NET, JAR_CLIENT
+    };
+
+    /** The version of the Derby distribution, i.e. 10.8.1.2. */
+    private final DerbyVersion version;
+    /** Path to derbyrun.jar (may be {@code null}). */
+    private final String derbyRunJarPath;
+    /** Path to derbyclient.jar. */
+    private final String derbyClientJarPath;
+    /** Path to derbyengine.jar. */
+    private final String derbyEngineJarPath;
+    /** Path to derbynet.jar. */
+    private final String derbyNetJarPath;
+    /**
+     * Production classpath, i.e. all JAR files found except for
+     * derbyTesting.jar.
+     */
+    private final String productionClasspath;
+    /** Testing classpath, i.e. path to derbyTesting.jar. */
+    private final String testingClasspath;
+
+    /**
+     * @throws IOException if obtaining the canonical path of a file fails
+     * @throws NullPointerException if version is {@code null}
+     * @see #getInstance
+     */
+    private DerbyDistribution(DerbyVersion version,
+                              File[] productionJars, File[] testingJars)
+            throws IOException {
+        if (version == null) {
+            throw new NullPointerException("version is null");
+        }
+        this.version = version;
+        this.productionClasspath = constructJarClasspath(productionJars);
+        this.testingClasspath = constructJarClasspath(testingJars);
+        File root = productionJars[0].getParentFile();
+        this.derbyRunJarPath = getPath(root, JAR_RUN);
+        this.derbyClientJarPath = getPath(root, JAR_CLIENT);
+        this.derbyEngineJarPath = getPath(root, JAR_ENGINE);
+        this.derbyNetJarPath = getPath(root, JAR_NET);
+    }
+
+    /** Returns the absolute path to the JAR if it exists, otherwise null. */
+    private String getPath(File root, String jar) {
+        File f = new File(root, jar);
+        if (PrivilegedFileOpsForTests.exists(f)) {
+            return f.getAbsolutePath();
+        } else {
+            return null;
+        }
+    }
+
+    /** Tells if this distribution has a {@code derbyrun.jar}. */
+    public boolean hasDerbyRunJar() {
+        return derbyRunJarPath != null;
+    }
+
+    /**
+     * Returns the path to {@code derbyrun.jar}.
+     *
+     * @return A path, or {@code null} if this distribution doesn't come with
+     *      {@code derbyrun.jar}.
+     * @see #hasDerbyRunJar()
+     */
+    public String getDerbyRunJarPath() {
+        return derbyRunJarPath;
+    }
+
+    /** Returns the path to {@code derbyclient.jar}. */
+    public String getDerbyClientJarPath() {
+        return derbyClientJarPath;
+    }
+
+    /** Returns the path to {@code derby.jar}. */
+    public String getDerbyEngineJarPath() {
+        return derbyEngineJarPath;
+    }
+
+    /** Returns the path to {@code derbynet.jar}. */
+    public String getDerbyNetJarPath() {
+        return derbyEngineJarPath;
+    }
+
+    /** Returns a classpath with the network server production JARs. */
+    public String getServerClasspath() {
+        return
+            this.derbyNetJarPath + File.pathSeparator + this.derbyEngineJarPath;
+    }
+
+    /** Returns a classpath with all production JARs. */
+    public String getProductionClasspath() {
+        return productionClasspath;
+    }
+
+    /** Returns a classpath with all testing JARs. */
+    public String getTestingClasspath() {
+        return testingClasspath;
+    }
+
+    /** Returns a classpath with all production and testing JARs. */
+    public String getFullClassPath() {
+        return productionClasspath + File.pathSeparatorChar + testingClasspath;
+    }
+
+    /** Returns the version of this distribution. */
+    public DerbyVersion getVersion() {
+        return version;
+    }
+
+    /**
+     * Orders this distribution and the other distribution based on the version.
+     * <p>
+     * <em>Implementation note</em>: Remove this method when we can use
+     * Java SE 5.0 features.
+     *
+     * @param o the other distribution
+     * @return {@code 1} if this version is newer, {@code 0} if both
+     *      distributions have the same version, and {@code -1} if the other
+     *      version is newer.
+     * @see #compareTo(org.apache.derbyTesting.junit.DerbyDistribution) 
+     */
+    public int compareTo(Object o) {
+        return compareTo((DerbyDistribution)o);
+    }
+
+    /**
+     * Orders this distribution and the other distribution based on the version.
+     *
+     * @param o the other distribution
+     * @return {@code 1} if this version is newer, {@code 0} if both
+     *      distributions have the same version, and {@code -1} if the other
+     *      version is newer.
+     */
+    public int compareTo(DerbyDistribution o) {
+        return version.compareTo(o.version);
+    }
+
+    private static boolean hasRequiredJars(List jars) {
+        for (int i=0; i < REQUIRED_JARS.length; i++) {
+            boolean hasJar = false;
+            for (Iterator jarIter = jars.iterator(); jarIter.hasNext(); ) {
+                File jar = (File)jarIter.next();
+                if (jar.getName().equalsIgnoreCase(REQUIRED_JARS[i])) {
+                    hasJar = true;
+                    break;
+                }
+            }
+            if (!hasJar) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Helper method extracting Derby production JARs from a directory.
+     *
+     * @param libDir directory
+     * @return A list of JARs (possibly empty).
+     */
+    private static File[] getProductionJars(File libDir) {
+        File[] pJars = libDir.listFiles(new FilenameFilter() {
+
+            public boolean accept(File dir, String name) {
+                return name.toUpperCase().endsWith(".JAR") &&
+                        !isTestingJar(name);
+            }
+        });
+        if (pJars == null) {
+            return EMPTY_FILE_ARRAY;
+        } else {
+            return pJars;
+        }
+    }
+
+    /**
+     * Helper method extracting Derby testing JARs from a directory.
+     *
+     * @param libDir directory
+     * @return A list of JARs (possibly empty).
+     */
+    private static File[] getTestingJars(File libDir) {
+        File[] tJars = libDir.listFiles(new FilenameFilter() {
+
+            public boolean accept(File dir, String name) {
+                return isTestingJar(name);
+            }
+        });
+        if (tJars == null) {
+            return EMPTY_FILE_ARRAY;
+        } else {
+            return tJars;
+        }
+    }
+
+    public static File[] getJars(File libDir) {
+        File[] jars = libDir.listFiles(new FilenameFilter() {
+
+            public boolean accept(File dir, String name) {
+                return name.toUpperCase().endsWith(".JAR");
+            }
+        });
+        return jars;
+    }
+
+    /**
+     * Tells if the given file is a Derby testing JAR.
+     *
+     * @param name name of the file
+     * @return {@code true} if a testing JAR, {@code false} otherwise
+     */
+    private static boolean isTestingJar(String name) {
+        return name.toUpperCase().endsWith(JAR_TESTING.toUpperCase());
+    }
+
+    /**
+     * Merges a list of JAR files into a classpath string.
+     *
+     * @param jars JAR files to merge
+     * @return A classpath string.
+     * @throws IOException if obtaining the canonical path of a file fails
+     */
+    private static String constructJarClasspath(File[] jars)
+            throws IOException {
+        StringBuffer sb = new StringBuffer(512);
+        for (int i=0; i < jars.length; i++) {
+            sb.append(jars[i].getCanonicalPath());
+            sb.append(File.pathSeparatorChar);
+        }
+        if (jars.length > 0) {
+            sb.deleteCharAt(sb.length() -1);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns an instance based on the given library directory and version.
+     * <p>
+     * This method is capable of understanding the difference of JAR based
+     * distribution and a distribution running off the classes-directory.
+     *
+     * @param dir the base directory for the distribution (either the classes
+     *      directory or a directory holding the Derby JAR files)
+     * @param version the version of the distribution
+     * @return A representation of the distribution, or {@code null} if
+     *      the specified directory is determined to be invalid.
+     * @throws IOException if obtaining the required information fails
+     * @throws IllegalArgumentException if {@code version} is {@code null}
+     */
+    public static DerbyDistribution getInstance(File dir,
+                                                DerbyVersion version)
+            throws IOException {
+        File[] productionJars = getProductionJars(dir);
+        File[] testingJars = getTestingJars(dir);
+        List tmpJars = new ArrayList();
+        tmpJars.addAll(Arrays.asList(productionJars));
+        tmpJars.addAll(Arrays.asList(testingJars));
+        if (hasRequiredJars(tmpJars)) {
+            return new DerbyDistribution(version, productionJars, testingJars);
+        }
+        // Invalid distribution, ignore it.
+        BaseTestCase.println("Distribution deemed invalid (note that running " +
+                "off classes isn't supported): " + dir.getAbsolutePath());
+        return null;
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/DerbyDistribution.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/ReleaseRepository.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/ReleaseRepository.java?rev=1330751&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/ReleaseRepository.java
(added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/ReleaseRepository.java
Thu Apr 26 10:20:58 2012
@@ -0,0 +1,259 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.junit.ReleaseRepository
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.derbyTesting.junit;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests;
+
+/**
+ * A repository for Derby releases.
+ * <p>
+ * The releases are used by tests, for instance by the upgrade and compatibility
+ * tests, to verify characteristics and behavior across Derby releases.
+ * <p>
+ * This particular repository is rather dumb - it is up to the user to keep the
+ * repository content updated. The repository layout is based on the layout of
+ * the SVN repository for releases at
+ * {@code https://svn.apache.org/repos/asf/db/derby/jars}. This means there will
+ * be a directory for each release, where the directory name is the release
+ * version. Inside this directory, all the distribution JARs can be found.
+ * <p>
+ * The repository location defaults to {@code $HOME/.derbyTestingReleases} on
+ * UNIX-like systems, and to {@code %UserProfile%\.derbyTestingReleases} on
+ * Windows (in Java, both of these maps to the system property 'user.home').
+ * The location can be overridden by specifying the system property
+ * {@code derbyTesting.oldReleasePath}.
+ * <p>
+ * If the default location doesn't exist, and the system property
+ * {@code derbyTesting.oldReleasePath} is unspecified, it is up to the tests
+ * using the release repository to decide if this condition fails the test or
+ * not. If the system property is set to a non-existing directory an exception
+ * will be thrown when instantiating the repository.
+ * <p>
+ * The repository is lazily initialized, as there's no reason to incur the
+ * initialization cost when running tests that don't require the repository.
+ * The disk is inspected only when the repository is instantiated, any updates
+ * to the on-disk repository after the repository has been instantiated will
+ * not take effect.
+ * <p>
+ * <em>Implementation note</em>: This code should be runnable with J2ME, which
+ * means that it needs to be compatible with J2SE 1.4 for the time being.
+ */
+public class ReleaseRepository {
+
+    /**
+     * The property used to override the location of the repository. The name
+     * is used for compatibility reasons.
+     */
+    private static final String OVERRIDE_HOME_PROP =
+            "derbyTesting.oldReleasePath";
+    private static final File DEFAULT_HOME;
+    static {
+        String home = BaseTestCase.getSystemProperty("user.home");
+        DEFAULT_HOME = new File(home, ".derbyTestingReleases");
+    }
+
+    /** The repository instance. */
+    private static ReleaseRepository repos;
+
+    /**
+     * Returns the release repository object.
+     * <p>
+     * The release repository will be built from a default directory, or
+     * from the directory specified by the system property
+     * {@code derbyTesting.oldReleasePath}.
+     *
+     * @return The release repository object.
+     */
+    public static synchronized ReleaseRepository getInstance()
+            throws IOException {
+        if (repos == null) {
+            File location = DEFAULT_HOME;
+            String overrideLoc = BaseTestCase.getSystemProperty(
+                    OVERRIDE_HOME_PROP);
+            if (overrideLoc != null) {
+                location = new File(overrideLoc);
+                if (!PrivilegedFileOpsForTests.exists(location)) {
+                    throw new IOException("the specified Derby release " +
+                        "repository doesn't exist: " + location.getPath());
+                }
+            }
+            repos = new ReleaseRepository(location);
+            repos.buildDistributionList();
+        }
+        return repos;
+    }
+
+    /** The repository location (on disk). */
+    private final File reposLocation;
+    /**
+     * List of distributions found in the repository. If {@code null}, the
+     * repository hasn't been initialized.
+     */
+    private List dists;
+
+    /**
+     * Creates a new, empty repository.
+     *
+     * @param reposLocation the location of the repository contents
+     * @see #buildDistributionList()
+     */
+    private ReleaseRepository(File reposLocation) {
+        this.reposLocation = reposLocation;
+    }
+
+    /**
+     * Returns the list of distributions in the repository.
+     *
+     * @return A sorted list of Derby distributions, with the newest
+     *      distribution at index zero, or an empty list if there are no
+     *      distributions in the repository.
+     */
+    public DerbyDistribution[] getDistributions()
+            throws IOException {
+        DerbyDistribution[] clone = new DerbyDistribution[dists.size()];
+        dists.toArray(clone);
+        return clone;
+    }
+
+    private void buildDistributionList()
+            throws IOException {
+        if (dists != null) {
+            throw new IllegalStateException("repository already initialized");
+        }
+
+        File[] tmpCandDists = reposLocation.listFiles(new FileFilter() {
+
+            public boolean accept(File pathname) {
+                if (!pathname.isDirectory()) {
+                    return false;
+                }
+                String name = pathname.getName();
+                // Stay away from regexp for now (JSR169).
+                // Allow only digits and three dots ("10.8.1.2")
+                int dots = 0;
+                for (int i=0; i < name.length(); i++) {
+                    char ch = name.charAt(i);
+                    if (ch == '.') {
+                        dots++;
+                    } else if (!Character.isDigit(ch)) {
+                        return false;
+                    }
+                }
+                return dots == 3;
+            }
+        });
+        if (tmpCandDists == null) {
+            tmpCandDists = new File[0];
+        }
+        traceit("{ReleaseRepository} " + tmpCandDists.length +
+                " candidate releases at " + reposLocation);
+
+        dists = new ArrayList(tmpCandDists.length);
+        for (int i=0; i < tmpCandDists.length; i++) {
+            File dir = tmpCandDists[i];
+            // We extract the version from the directory name.
+            // We can also extract it by running sysinfo if that turns out to
+            // be necessary.
+            // From the check in the FileFilter we know we'll get four
+            // components when splitting on dot.
+            String[] comp = Utilities.split(dir.getName(), '.');
+            DerbyVersion version;
+            try {
+                version = new DerbyVersion(
+                        Integer.parseInt(comp[0]),
+                        Integer.parseInt(comp[1]),
+                        Integer.parseInt(comp[2]),
+                        Integer.parseInt(comp[3]));
+            } catch (NumberFormatException nfe) {
+                traceit("skipped distribution, invalid version: " +
+                        dir.getAbsolutePath());
+                continue;
+            }
+            DerbyDistribution dist = DerbyDistribution.getInstance(
+                    dir, version);
+            // TODO: 10.0.1.2 is considered invalid because it doesn't have a
+            //       a client JAR. Accept, ignore, or warn all the time?
+            if (dist == null) {
+                traceit("skipped invalid distribution: " +
+                        dir.getAbsolutePath());
+            } else {
+                dists.add(dist);
+            }
+        }
+        filterDistributions(dists);
+        Collections.sort(dists);
+        dists = Collections.unmodifiableList(dists);
+    }
+
+    /**
+     * Filters out distributions that cannot be run in the current environment
+     * for some reason.
+     * <p>
+     * The reason for getting filtered out is typically due to lacking
+     * functionality or a bug in a specific Derby distribution.
+     *
+     * @param dists the list of distributions to filter (modified in-place)
+     */
+    private void filterDistributions(List dists) {
+        // Specific version we want to filter out in some situations.
+        DerbyVersion jsr169Support = DerbyVersion._10_1;
+        DerbyVersion noPhoneMEBoot = DerbyVersion._10_3_1_4;
+
+        for (int i=dists.size() -1; i >= 0; i--) {
+            DerbyDistribution dist = (DerbyDistribution)dists.get(i);
+            DerbyVersion distVersion = dist.getVersion();
+            // JSR169 support was only added with 10.1, so don't
+            // run 10.0 to later upgrade if that's what our jvm is supporting.
+            if (JDBC.vmSupportsJSR169() &&
+                    distVersion.lessThan(jsr169Support)) {
+                println("skipping " + distVersion.toString() + " on JSR169");
+                dists.remove(i);
+                continue;
+            }
+            // Derby 10.3.1.4 does not boot on the phoneME advanced platform,
+            // (see DERBY-3176) so don't run upgrade tests in this combination.
+            if (BaseTestCase.isPhoneME() &&
+                    noPhoneMEBoot.equals(distVersion)) {
+                println("skipping " + noPhoneMEBoot.toString() +
+                        " on CVM/phoneme");
+                dists.remove(i);
+                continue;
+            }
+        }
+    }
+
+    /** Prints a trace message if tracing is enabled. */
+    private static void traceit(String msg) {
+        BaseTestCase.traceit(msg);
+    }
+
+    /** Prints a debug message if debugging is enabled. */
+    private static void println(String msg) {
+        BaseTestCase.println(msg);
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/ReleaseRepository.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message