ace-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r788992 [23/25] - in /incubator/ace/trunk: gateway/ gateway/src/ gateway/src/net/ gateway/src/net/luminis/ gateway/src/net/luminis/liq/ gateway/src/net/luminis/liq/bootstrap/ gateway/src/net/luminis/liq/bootstrap/multigateway/ gateway/src/n...
Date Sat, 27 Jun 2009 15:53:26 GMT
Added: incubator/ace/trunk/test/src/net/luminis/liq/test/bundlestop/Activator.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/bundlestop/Activator.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/bundlestop/Activator.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/bundlestop/Activator.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,39 @@
+package net.luminis.liq.test.bundlestop;
+
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.dependencymanager.DependencyActivatorBase;
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+import org.osgi.service.log.LogService;
+
+/**
+ * This bundle stops the systembundle whenever the deploymentadmin is done deploying.
+ */
+public class Activator extends DependencyActivatorBase {
+    @SuppressWarnings("unchecked")
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        String[] topics = new String[] {EventConstants.EVENT_TOPIC, "org/osgi/service/deployment/COMPLETE"};
+        Dictionary properties = new Hashtable();
+        properties.put(EventConstants.EVENT_TOPIC, topics);
+
+        SystemBundleStopper stopper = new SystemBundleStopper();
+        context.addBundleListener(stopper);
+        manager.add(createService()
+            .setInterface(EventHandler.class.getName(), properties)
+            .setImplementation(stopper)
+            .add(createServiceDependency()
+                .setService(LogService.class)
+                .setRequired(false)));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+}
+

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/bundlestop/SystemBundleStopper.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/bundlestop/SystemBundleStopper.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/bundlestop/SystemBundleStopper.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/bundlestop/SystemBundleStopper.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,50 @@
+package net.luminis.liq.test.bundlestop;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+public class SystemBundleStopper implements EventHandler, BundleListener {
+
+    private BundleContext m_context;
+    private boolean m_deploymentPackageIsInstalled = false;
+    private boolean m_isFrameWorkStarted = false;
+
+    /**
+     * This service only listens for completed events. If it gets one,
+     * the systembundle should be stopped.
+     */
+    public synchronized void handleEvent(Event arg0) {
+        if (m_isFrameWorkStarted || (m_context.getBundle(0).getState() == Bundle.ACTIVE)) {
+            stopSystemBundle();
+        } else {
+            m_deploymentPackageIsInstalled = true;
+        }
+    }
+
+    public synchronized void bundleChanged(BundleEvent event) {
+        if ((event.getBundle().getBundleId() == 0) && (event.getType() == BundleEvent.STARTED)) {
+            if (m_deploymentPackageIsInstalled) {
+                stopSystemBundle();
+            } else {
+                m_isFrameWorkStarted  = true;
+            }
+        }
+    }
+
+    public void stopSystemBundle() {
+        try {
+            m_context.getBundle(0).stop();
+        }
+        catch (BundleException e) {
+            System.err.println("Error stopping systembundle. Performing an un-clean exit now.");
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/deployment/Activator.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/deployment/Activator.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/deployment/Activator.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/deployment/Activator.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,29 @@
+package net.luminis.liq.test.deployment;
+
+import net.luminis.test.osgi.dm.TestActivatorBase;
+
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.deploymentadmin.DeploymentAdmin;
+import org.osgi.service.http.HttpService;
+
+public class Activator extends TestActivatorBase {
+    @SuppressWarnings("unchecked")
+    private Class[] m_classes = new Class[] { DeploymentIntegrationTest.class };
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Class[] getTestClasses() {
+        return m_classes;
+    }
+
+    @Override
+    protected void initServices(BundleContext context, DependencyManager manager) {
+        manager.add(createService()
+            .setImplementation(DeploymentIntegrationTest.class)
+            .add(createServiceDependency().setService(HttpService.class).setRequired(true))
+            .add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
+            .add(createServiceDependency().setService(DeploymentAdmin.class).setRequired(true)));
+    }
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/deployment/DeploymentIntegrationTest.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/deployment/DeploymentIntegrationTest.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/deployment/DeploymentIntegrationTest.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/deployment/DeploymentIntegrationTest.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,361 @@
+package net.luminis.liq.test.deployment;
+
+import static net.luminis.liq.test.utils.TestUtils.INTEGRATION;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import net.luminis.liq.deployment.provider.ArtifactData;
+import net.luminis.liq.deployment.provider.impl.ArtifactDataImpl;
+import net.luminis.liq.discovery.property.constants.DiscoveryConstants;
+import net.luminis.liq.http.listener.constants.HttpConstants;
+import net.luminis.liq.identification.property.constants.IdentificationConstants;
+import net.luminis.liq.scheduler.constants.SchedulerConstants;
+import net.luminis.liq.test.utils.deployment.BundleStreamGenerator;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.deploymentadmin.DeploymentAdmin;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.deploymentadmin.DeploymentPackage;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class DeploymentIntegrationTest implements BundleListener, EventHandler {
+
+    public static final String HOST = "localhost";
+    public static final int PORT = 8080;
+    public static final String GWID = "gw-id";
+    public static final long POLL_INTERVAL = 1000;
+    private static Object instance;
+    private volatile ConfigurationAdmin m_config;
+    private volatile DeploymentAdmin m_deployment;
+    private volatile BundleContext m_context;
+    private volatile File m_tempDir;
+    private final Semaphore m_semaphore = new Semaphore(0);
+    Map<Integer, List<Bundle>> m_events = new HashMap<Integer, List<Bundle>>();
+    private ServiceRegistration m_deploymentAdminProxyRegistration;
+
+    public DeploymentIntegrationTest() throws IOException {
+        synchronized (DeploymentIntegrationTest.class) {
+            if (instance == null) {
+                instance = this;
+            }
+        }
+    }
+
+    @BeforeTest(alwaysRun = true)
+    public void setUp() throws IOException {
+        m_tempDir = File.createTempFile("test", "");
+        m_tempDir.delete();
+        m_tempDir.mkdir();
+    }
+
+    @AfterTest(alwaysRun = true)
+    public void tearDown() {
+        deleteDirOrFile(m_tempDir);
+    }
+
+    private void deleteDirOrFile(File root) {
+        if (root.isDirectory()) {
+            for (File file : root.listFiles()) {
+                deleteDirOrFile(file);
+            }
+        }
+        root.delete();
+    }
+
+    @Factory
+    public Object[] createInstance() {
+        synchronized (DeploymentIntegrationTest.class) {
+            return new Object[] { instance };
+        }
+    }
+
+    @Test(groups = { INTEGRATION })
+    public void deployVersionSeries() throws Exception {
+        Bundle[] start = m_context.getBundles();
+
+        // Test deploy initial version 1.0.0 with 3 bundles in version 1.0.0
+        String[] versions = new String[] { "bundle1", "bundle2", "bundle3" };
+        generateBundles(createVersion("1.0.0"), versions, 0, versions.length, "1.0.0");
+        executeTest();
+        // start + versions bundles may be present
+        assertState(start, m_context.getBundles(), versions);
+        assert m_events.get(BundleEvent.STARTED).size() == versions.length : "Received unexpected amount of starting events.";
+        assert m_events.get(BundleEvent.STOPPED) == null : "Received unexpected amount of stopping events";
+        m_events.clear();
+
+        // Test correct presence of deployment packages in deployment admin
+        assert m_deployment.listDeploymentPackages().length == 1 : "Deployment admin reports unexpected number of deployment packages";
+        assert m_deployment.getDeploymentPackage(GWID) != null : "Deployment admin did not return the expected deployment package";
+        Bundle[] bundles = m_context.getBundles();
+        Bundle bundle = null;
+        for (int i = 0; i < bundles.length; i++) {
+            if("bundle1".equals(bundles[i].getSymbolicName())) {
+                bundle = bundles[i];
+                break;
+            }
+        }
+        assert m_deployment.getDeploymentPackage(bundle) != null : "Deployment admin did not return the expected deployment package";
+
+        // Test deploy a version 1.1.0 on top of the previous 1.0.0 with one new bundle and one updated to version 1.1.0 (i.e., two fix-package bundles)
+        versions = new String[] { "bundle1", "bundle2", "bundle3", "bundle4" };
+        File version = createVersion("1.1.0");
+        generateBundle(new File(version, "0.jar"), versions[0], "1.1.0");
+        generateBundles(version, versions, 1, versions.length, "1.0.0");
+        executeTest();
+        // start + versions bundles may be present
+        assertState(start, m_context.getBundles(), versions);
+        assert m_events.get(BundleEvent.UPDATED).size() == 1 : "Received unexpected amount of updated events.";
+        assert m_events.get(BundleEvent.UPDATED).get(0).getSymbolicName().equals(versions[0]) : "Received unexpected update event.";
+        assert m_events.get(BundleEvent.STOPPED).size() == versions.length - 1 : "Received unexpected amount of stopped events.";
+        assert m_events.get(BundleEvent.STARTED).size() == versions.length : "Received unexpected amount of started events: expected " + versions.length + ", received " + m_events.get(BundleEvent.STARTED).size() + ".";
+        m_events.clear();
+
+        // Test to deploy an empty version 2.0.0, but break the stream which should cancel the deployment
+        createVersion("2.0.0");
+        executeTestWithFailingStream();
+        m_events.clear();
+
+        // Test to deploy an empty version 2.0.0 which should remove all the previously installed bundles
+        executeTest();
+
+        // only start bundles may be present
+        assertState(start, m_context.getBundles(), new String[0]);
+        assert m_events.get(BundleEvent.INSTALLED) == null : "Received unexpected amount of installed events.";
+        assert m_events.get(BundleEvent.STARTED) == null : "Received unexpected amount of starting events.";
+        assert m_events.get(BundleEvent.UNINSTALLED).size() == versions.length : "Received unexpected amount of uninstalled events: " + m_events.get(BundleEvent.UNINSTALLED).size() + " instead of " + versions.length;
+        assert m_events.get(BundleEvent.STOPPED).size() == versions.length : "Received unexpected amount of stopped events: " + m_events.get(BundleEvent.STOPPED).size() + " instead of " + versions.length;
+        m_events.clear();
+
+    }
+
+    public void bundleChanged(BundleEvent event) {
+        synchronized (m_events) {
+            if (!m_events.containsKey(Integer.valueOf(event.getType()))) {
+                m_events.put(Integer.valueOf(event.getType()), new ArrayList<Bundle>());
+            }
+            m_events.get(Integer.valueOf(event.getType())).add(event.getBundle());
+        }
+    }
+
+    public void handleEvent(Event event) {
+        System.out.println("Event: " + event);
+        m_semaphore.release();
+    }
+
+    private void generateBundles(File dir, String[] versions, int off, int len, String version) throws Exception {
+        for (int i = off; i < len; i++) {
+            generateBundle(new File(dir, i + ".jar"), versions[i], version);
+        }
+    }
+
+    private void assertState(Bundle[] start, Bundle[] current, String[] versions) {
+        assert (start.length + versions.length) == current.length : "System has " + (((start.length + versions.length) < current.length) ? "more" : "less") + " bundes then expected: expected " + (start.length + versions.length) + ", found " + current.length;
+        for (int i = 0; i < start.length; i++) {
+            assert current[i].getSymbolicName().equals(start[i].getSymbolicName()) : "Bundle names do not match: " + current[i].getSymbolicName() + " v.s. " + start[i];
+        }
+        List<String> index = Arrays.asList(versions);
+        for (int i = start.length; i < current.length; i++) {
+            assert index.contains(current[i].getSymbolicName()) : "Bundle names do not match: " + current[i].getSymbolicName();
+        }
+    }
+
+    private File createVersion(String version) {
+        File versionFile = new File(new File(m_tempDir, GWID), version);
+        versionFile.mkdirs();
+        return versionFile;
+    }
+
+    @SuppressWarnings("serial")
+    private void executeTest() throws IOException, InterruptedException {
+        m_context.addBundleListener(this);
+        ServiceRegistration reg = m_context.registerService(EventHandler.class.getName(), this, new Properties() {
+            {
+                put(EventConstants.EVENT_TOPIC, "org/osgi/service/deployment/COMPLETE");
+                put(EventConstants.EVENT_FILTER, "(successful=true)");
+            }
+        });
+        configureGateway();
+        configureServer();
+        assert m_semaphore.tryAcquire(8, TimeUnit.SECONDS) : "Timed out while waiting for deployment to complete.";
+        unconfigureServer();
+        unconfigureGateway();
+        reg.unregister();
+        m_context.removeBundleListener(this);
+    }
+
+    private void executeTestWithFailingStream() throws IOException, InterruptedException {
+        m_context.addBundleListener(this);
+        registerDeploymentAdminProxy(new FailingDeploymentAdmin(m_deployment, 50));
+        configureGateway();
+        configureServer();
+        assert m_semaphore.tryAcquire(8, TimeUnit.SECONDS) : "Timed out while waiting for deployment to abort.";
+        unconfigureServer();
+        unconfigureGateway();
+        unregisterDeploymentAdminProxy();
+        m_context.removeBundleListener(this);
+    }
+
+    /**
+     * Input stream wrapper that creates an input stream that breaks after N bytes. When it
+     * breaks, it will throw an IO exception and sends a notification to the semaphore that
+     * allows the overall test to continue.
+     */
+    private class BrokenInputStream extends InputStream {
+        private final InputStream m_normalStream;
+        private int m_bytesUntilBreakdown;
+        private boolean m_isBroken;
+
+        public BrokenInputStream(InputStream normalStream, int bytesUntilBreakdown) {
+            m_normalStream = normalStream;
+            m_bytesUntilBreakdown = bytesUntilBreakdown;
+        }
+
+        private synchronized void breakStream() throws IOException {
+            if (!m_isBroken) {
+                m_isBroken = true;
+
+                // release the semaphore to continue the test
+                m_semaphore.release();
+            }
+            throw new IOException("Stream broken.");
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (m_bytesUntilBreakdown-- < 1) {
+                breakStream();
+            }
+            return m_normalStream.read();
+        }
+
+        @Override
+        public void close() throws IOException {
+            m_normalStream.close();
+            breakStream();
+        }
+
+    }
+
+    /**
+     * Wrapper around the deployment admin that will fail once, after N bytes.
+     */
+    private class FailingDeploymentAdmin implements DeploymentAdmin {
+        private final DeploymentAdmin m_deploymentAdmin;
+        private boolean m_wasBroken;
+        private final int m_failAfterBytes;
+
+        public FailingDeploymentAdmin(DeploymentAdmin deploymentAdmin, int failAfterBytes) {
+            m_deploymentAdmin = deploymentAdmin;
+            m_failAfterBytes = failAfterBytes;
+        }
+
+        public boolean cancel() {
+            return m_deploymentAdmin.cancel();
+        }
+
+        public DeploymentPackage getDeploymentPackage(String symbName) {
+            return m_deploymentAdmin.getDeploymentPackage(symbName);
+        }
+
+        public DeploymentPackage getDeploymentPackage(Bundle bundle) {
+            return m_deploymentAdmin.getDeploymentPackage(bundle);
+        }
+
+        public DeploymentPackage installDeploymentPackage(InputStream in) throws DeploymentException {
+            synchronized (this) {
+                if (!m_wasBroken) {
+                    m_wasBroken = true;
+                    in = new BrokenInputStream(in, m_failAfterBytes);
+                }
+            }
+            return m_deploymentAdmin.installDeploymentPackage(in);
+        }
+
+        public DeploymentPackage[] listDeploymentPackages() {
+            return m_deploymentAdmin.listDeploymentPackages();
+        }
+    }
+
+    private void configureGateway() throws IOException {
+        // configure discovery bundle
+        setProperty(DiscoveryConstants.DISCOVERY_PID, new Object[][] { { DiscoveryConstants.DISCOVERY_URL_KEY, "http://" + HOST + ":" + PORT } });
+        // configure identification bundle
+        setProperty(IdentificationConstants.IDENTIFICATION_PID, new Object[][] { { IdentificationConstants.IDENTIFICATION_GATEWAYID_KEY, GWID } });
+        // configure scheduler
+        setProperty(SchedulerConstants.SCHEDULER_PID, new Object[][] {
+                                                                     { "net.luminis.liq.gateway.auditlog.task.AuditLogSyncTask", POLL_INTERVAL },
+                                                                     { "net.luminis.liq.deployment.task.DeploymentUpdateTask", POLL_INTERVAL }
+                                                                   });
+    }
+
+    private void unconfigureGateway() throws IOException {
+        m_config.getConfiguration(DiscoveryConstants.DISCOVERY_PID, null).delete();
+        m_config.getConfiguration(IdentificationConstants.IDENTIFICATION_PID, null).delete();
+        m_config.getConfiguration(SchedulerConstants.SCHEDULER_PID, null).delete();
+    }
+
+    private void unconfigureServer() throws IOException {
+        m_config.getConfiguration("net.luminis.liq.deployment.servlet", null).delete();
+        m_config.getConfiguration("net.luminis.liq.deployment.provider.filebased", null).delete();
+    }
+
+    private void configureServer() throws IOException {
+        // configure data bundle
+        setProperty(net.luminis.liq.deployment.servlet.Activator.PID, new Object[][] { { HttpConstants.ENDPOINT, "/deployment" } });
+        // configure file based backend
+        setProperty(net.luminis.liq.deployment.provider.filebased.Activator.PID, new Object[][] { { "BaseDirectoryName", m_tempDir.getAbsolutePath() } });
+    }
+
+    @SuppressWarnings("unchecked")
+    private void setProperty(String pid, Object[][] props) throws IOException {
+        Configuration configuration = m_config.getConfiguration(pid, null);
+        Dictionary dictionary = configuration.getProperties();
+        if (dictionary == null) {
+            dictionary = new Hashtable();
+        }
+        for (Object[] pair : props) {
+            dictionary.put(pair[0], pair[1]);
+        }
+        configuration.update(dictionary);
+    }
+
+    private ArtifactData generateBundle(File file, String symbolicName, String version) throws Exception {
+        ArtifactData bundle = new ArtifactDataImpl(file.getName(), symbolicName, version, file.toURI().toURL(), false);
+        BundleStreamGenerator.generateBundle(bundle);
+        return bundle;
+    }
+
+    private void registerDeploymentAdminProxy(DeploymentAdmin proxy) {
+        Properties props = new Properties();
+        props.put(org.osgi.framework.Constants.SERVICE_RANKING, 1);
+        m_deploymentAdminProxyRegistration = m_context.registerService(DeploymentAdmin.class.getName(), proxy, props);
+    }
+
+    private void unregisterDeploymentAdminProxy() {
+        m_deploymentAdminProxyRegistration.unregister();
+    }
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/Activator.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/Activator.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/Activator.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/Activator.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,29 @@
+package net.luminis.liq.test.http.listener;
+
+import net.luminis.test.osgi.dm.TestActivatorBase;
+
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * Activator for the integration test.
+ */
+public class Activator extends TestActivatorBase {
+
+    @Override
+    protected void initServices(BundleContext context, DependencyManager manager) {
+        manager.add(createService()
+            .setImplementation(new ServletConfiguratorIntegrationTest(manager))
+            .add(createServiceDependency()
+                .setService(LogService.class)
+                .setRequired(false)));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Class[] getTestClasses() {
+        return new Class[] { ServletConfiguratorIntegrationTest.class };
+    }
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/EchoServlet.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/EchoServlet.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/EchoServlet.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/EchoServlet.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,34 @@
+package net.luminis.liq.test.http.listener;
+
+import java.io.IOException;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class EchoServlet extends HttpServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
+        ServletOutputStream output = null;
+        try {
+            output = response.getOutputStream();
+            output.println(request.getQueryString());
+        }
+        catch (IOException e) {
+            // not much we can do, the test will fail anyway
+        } finally {
+            if (output != null) {
+                try {
+                    output.close();
+                }
+                catch (IOException e) {
+                    // not much we can do, the test will fail anyway
+                }
+            }
+        }
+    }
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/MockHttpService.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/MockHttpService.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/MockHttpService.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/MockHttpService.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,43 @@
+package net.luminis.liq.test.http.listener;
+
+import java.util.Dictionary;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+
+public class MockHttpService implements HttpService {
+
+    private boolean m_registerCalled = false;
+    private boolean m_unregisterCalled = false;
+
+    public HttpContext createDefaultHttpContext() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void registerResources(String arg0, String arg1, HttpContext arg2) throws NamespaceException {
+        // TODO Auto-generated method stub
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public void registerServlet(String arg0, Servlet arg1, Dictionary arg2, HttpContext arg3) throws ServletException, NamespaceException {
+        m_registerCalled = true;
+    }
+
+    public void unregister(String arg0) {
+        m_unregisterCalled = true;
+    }
+
+    public boolean isRegisterCalled() {
+        return m_registerCalled;
+    }
+
+    public boolean isUnregisterCalled() {
+        return m_unregisterCalled;
+    }
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/ServletConfiguratorIntegrationTest.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/ServletConfiguratorIntegrationTest.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/ServletConfiguratorIntegrationTest.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/http/listener/ServletConfiguratorIntegrationTest.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,231 @@
+package net.luminis.liq.test.http.listener;
+
+import static net.luminis.liq.test.utils.TestUtils.INTEGRATION;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.servlet.http.HttpServlet;
+
+import net.luminis.liq.http.listener.constants.HttpConstants;
+
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.apache.felix.dependencymanager.Service;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.http.HttpService;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+/**
+ * A test for the ServletConfigurator.
+ */
+public class ServletConfiguratorIntegrationTest {
+
+    private static Object instance;
+
+    private BundleContext m_context;
+
+    private DependencyManager m_dependencyManager;
+
+    // the echo servlet
+    private HttpServlet m_echoServlet;
+    // echo servlet service-reference
+    private Service m_echoServletService;
+    // mock http service
+    private MockHttpService m_mockHttp;
+
+    //mock http service-reference
+    private Service m_mockHttpService;
+    // regular http service service-reference
+    private Bundle m_httpBundle;
+
+    public ServletConfiguratorIntegrationTest() {
+        if (instance == null) {
+            instance = this;
+        }
+    }
+
+    @Factory
+    public Object[] createInstances() {
+        return new Object[] { instance };
+    }
+
+    /**
+     * store the dependencymanager to publish our own test services
+     */
+    public ServletConfiguratorIntegrationTest(DependencyManager dependencyManager) {
+        if (instance == null) {
+            instance = this;
+        }
+        m_dependencyManager = dependencyManager;
+        // start will be called when the dependency manager is ready
+    }
+
+    public void start() {
+        m_echoServlet = new EchoServlet();
+        Dictionary<String, String> dictionary = new Hashtable<String, String>();
+        dictionary.put(HttpConstants.ENDPOINT, "/echoServlet");
+        m_echoServletService = m_dependencyManager.createService()
+                                    .setImplementation(m_echoServlet)
+                                    .setInterface(HttpServlet.class.getName(), dictionary);
+
+        m_mockHttp = new MockHttpService();
+        m_mockHttpService = m_dependencyManager.createService()
+                                    .setImplementation(m_mockHttp)
+                                    .setInterface(HttpService.class.getName(), null);
+    }
+
+    private void setUp() throws InvalidSyntaxException, BundleException {
+        if (m_httpBundle == null) {
+            m_httpBundle = m_context.getServiceReference(HttpService.class.getName()).getBundle();
+        }
+    }
+
+    private void tearDown() {
+        try {
+            m_dependencyManager.remove(m_echoServletService);
+            m_dependencyManager.remove(m_mockHttpService);
+        }
+        catch (IllegalStateException ise) {
+            // It is possible that our services has been removed by the tests themselves; no problem here.
+        }
+    }
+
+    /**
+     * Start the http service and then register a servlet and see if it works
+     * After that, try to unregister
+     */
+    @Test(groups = { INTEGRATION })
+    public void testRegisterServlet() throws Exception {
+        setUp();
+
+        assert m_httpBundle != null : "We need a (real) http service !";
+
+        // use normal http service
+        m_httpBundle.start();
+        m_dependencyManager.add(m_echoServletService);
+        assert waitForEchoServlet(true) : "TestValue not echo'd back";
+
+        m_dependencyManager.remove(m_echoServletService);
+        assert !waitForEchoServlet(false) : "The servlet should not be available anymore";
+
+        tearDown();
+    }
+
+    /**
+     * Register a servlet and then start the http service and see if it works
+     * After that, try to unregister
+     */
+    @Test(groups = { INTEGRATION })
+    public void testStartHttpService() throws Exception {
+        setUp();
+
+        assert m_httpBundle != null : "We need a (real) http service !";
+
+        // use normal http service
+        m_dependencyManager.add(m_echoServletService);
+        m_httpBundle.start();
+        assert waitForEchoServlet(true) : "TestValue not echo'd back";
+
+        m_dependencyManager.remove(m_echoServletService);
+        assert !waitForEchoServlet(false) : "The servlet should not be available anymore";
+
+        tearDown();
+    }
+
+    /**
+     * Register a servlet with 2 http services, try to unregister and see if it is removed from both
+     */
+    @Test(groups = { INTEGRATION })
+    public void testServletOnTwoHttpServices() throws Exception {
+        setUp();
+
+        assert m_httpBundle != null : "We need a (real) http service !";
+
+        // use normal http service
+        m_dependencyManager.add(m_echoServletService);
+        // also use the mock version
+        m_dependencyManager.add(m_mockHttpService);
+        m_httpBundle.start();
+        assert waitForEchoServlet(true) : "TestValue not echo'd back";
+        assert m_mockHttp.isRegisterCalled() : "Servlet not registered with the mock service";
+
+
+        m_dependencyManager.remove(m_echoServletService);
+        assert !waitForEchoServlet(false) : "The servlet should not be available anymore";
+        assert m_mockHttp.isUnregisterCalled() : "Servlet not unregistered with the mock service";
+
+        tearDown();
+
+    }
+
+
+
+    /**
+     * now the server should be made available at
+     * http://localhost:8080/echoservlet
+     * if it is not available after 2000 ms, the test is failed anyway
+     *
+     * The expectSuccess parameter indicated if this method should expect a working echoservlet or a non-working one.
+     *
+     * This method returns whether the expect result was met. So if you expect it to work (and it does), true will be returned.
+     * If you expect it to NOT work (and it doesn't), false will be returned.
+     */
+    private boolean waitForEchoServlet(boolean expectedResult) {
+        BufferedReader bufReader = null;
+
+        long startTimeMillis = System.currentTimeMillis();
+        // make sure we iterate at least once
+        boolean success = !expectedResult;
+        try {
+            while ((expectedResult != success) && (System.currentTimeMillis() < startTimeMillis + 30000)) {
+                URL echoServletUrl = new URL("http://localhost:8080/echoServlet?test");
+                String echoString = null;
+                try {
+                    bufReader = new BufferedReader(new InputStreamReader(echoServletUrl.openStream()));
+                    echoString = bufReader.readLine();
+                } catch (IOException ioe) {
+                    // let's wait and try again.
+                }
+                boolean resultFromServlet = (echoString != null) && echoString.equals("test");
+                if (resultFromServlet == expectedResult) {
+                    success = expectedResult;
+                }
+                if ((expectedResult != success)) {
+                    Thread.sleep(100);
+                }
+            }
+        }catch (MalformedURLException e) {
+            e.printStackTrace();
+            assert false : "No MalformedURLException expected";
+        }
+        catch (InterruptedException e) {
+            e.printStackTrace();
+            assert false : "No interruptedException expected";
+        } catch (Throwable t) {
+            t.printStackTrace();
+        } finally {
+            if (bufReader != null) {
+                try {
+                    bufReader.close();
+                }
+                catch (Exception ex) {
+                    // not much we can do
+                }
+            }
+        }
+        return success;
+    }
+
+
+
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/log/Activator.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/log/Activator.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/log/Activator.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/log/Activator.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,124 @@
+package net.luminis.liq.test.log;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import net.luminis.liq.discovery.property.constants.DiscoveryConstants;
+import net.luminis.liq.http.listener.constants.HttpConstants;
+import net.luminis.liq.identification.property.constants.IdentificationConstants;
+import net.luminis.liq.log.Log;
+import net.luminis.liq.server.log.store.LogStore;
+import net.luminis.test.osgi.dm.TestActivatorBase;
+
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.log.LogService;
+
+public class Activator extends TestActivatorBase {
+    private static final String AUDITLOG = "/auditlog";
+    private static final String DEPLOYMENT = "/deployment";
+
+    @SuppressWarnings("unchecked")
+    private Class[] m_classes = new Class[] { LogIntegrationTest.class };
+    public static final String HOST = "localhost";
+    public static final int PORT = 8080;
+    public static final String GWID = "gw-id";
+    public static final String POLL_INTERVAL = "2";
+    private volatile ConfigurationAdmin m_config;
+    private volatile LogService m_log;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Class[] getTestClasses() {
+        return m_classes;
+    }
+
+    @Override
+    protected void initServices(BundleContext context, DependencyManager manager) {
+        // helper service that configures the system
+        manager.add(createService()
+            .setImplementation(this)
+            .add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
+            .add(createServiceDependency().setService(LogService.class).setRequired(false))
+        );
+        // service containing the actual integration test
+        manager.add(createService()
+            .setImplementation(LogIntegrationTest.class)
+            .add(createServiceDependency().setService(Log.class, "(&("+Constants.OBJECTCLASS+"="+Log.class.getName()+")(name=auditlog))").setRequired(true))
+            .add(createServiceDependency().setService(LogStore.class, "(&("+Constants.OBJECTCLASS+"="+LogStore.class.getName()+")(name=auditlog))").setRequired(true))
+            .add(createServiceDependency().setService(Runnable.class, "(&("+Constants.OBJECTCLASS+"="+Runnable.class.getName()+")(taskName=auditlog))").setRequired(true))
+        );
+    }
+
+    public void start() {
+        try {
+            configureServer();
+            configureGateway();
+        }
+        catch (Exception e) {
+            m_log.log(LogService.LOG_ERROR, "Exception while starting", e);
+        }
+    }
+
+    public void stop() {
+        try {
+            unconfigureGateway();
+            unconfigureServer();
+        }
+        catch (IOException e) {
+            m_log.log(LogService.LOG_ERROR, "IO exception while stopping", e);
+        }
+    }
+
+    private void configureGateway() throws IOException {
+        setProperty(DiscoveryConstants.DISCOVERY_PID, new Object[][] { { DiscoveryConstants.DISCOVERY_URL_KEY, "http://" + HOST + ":" + PORT } });
+        setProperty(IdentificationConstants.IDENTIFICATION_PID, new Object[][] { { IdentificationConstants.IDENTIFICATION_GATEWAYID_KEY, GWID } });
+        createFactoryInstance("net.luminis.liq.gateway.log.store.factory", new Object[][] { {"name", "auditlog"} });
+        createFactoryInstance("net.luminis.liq.gateway.log.factory", new Object[][] { {"name", "auditlog"} });
+    }
+
+    private void unconfigureGateway() throws IOException {
+        m_config.getConfiguration(DiscoveryConstants.DISCOVERY_PID, null).delete();
+        m_config.getConfiguration(IdentificationConstants.IDENTIFICATION_PID, null).delete();
+    }
+
+    private void unconfigureServer() throws IOException {
+        m_config.getConfiguration("net.luminis.liq.deployment.servlet", null).delete();
+        m_config.getConfiguration("net.luminis.liq.deployment.provider.filebased", null).delete();
+    }
+
+    private void configureServer() throws Exception {
+        setProperty("net.luminis.liq.deployment.servlet", new Object[][] { { HttpConstants.ENDPOINT, DEPLOYMENT } });
+        createFactoryInstance("net.luminis.liq.server.log.servlet.factory", new Object[][] { {"name", "auditlog"}, { HttpConstants.ENDPOINT, AUDITLOG } });
+        createFactoryInstance("net.luminis.liq.server.log.store.factory", new Object[][] { {"name", "auditlog"} });
+    }
+
+    @SuppressWarnings("unchecked")
+    private void setProperty(String pid, Object[][] props) throws IOException {
+        Configuration configuration = m_config.getConfiguration(pid, null);
+        Dictionary dictionary = configuration.getProperties();
+        if (dictionary == null) {
+            dictionary = new Hashtable();
+        }
+        for (Object[] pair : props) {
+            dictionary.put(pair[0], pair[1]);
+        }
+        configuration.update(dictionary);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void createFactoryInstance(String factoryPid, Object[][] props) throws IOException {
+        Dictionary dict = new Properties();
+        for (Object[] pair : props) {
+            dict.put(pair[0], pair[1]);
+        }
+        Configuration config = m_config.createFactoryConfiguration(factoryPid, null);
+        config.update(dict);
+    }
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/log/LogIntegrationTest.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/log/LogIntegrationTest.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/log/LogIntegrationTest.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/log/LogIntegrationTest.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,150 @@
+package net.luminis.liq.test.log;
+
+import static net.luminis.liq.test.utils.TestUtils.INTEGRATION;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import net.luminis.liq.log.LogEvent;
+import net.luminis.liq.log.Log;
+import net.luminis.liq.log.LogDescriptor;
+import net.luminis.liq.server.log.store.LogStore;
+
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+/**
+ * Integration tests for the audit log. Both a server and a gateway are setup
+ * on the same machine. The audit log is run and we check if it is indeed
+ * replicated to the server.
+ */
+public class LogIntegrationTest {
+    private volatile Log m_auditLog;
+    private volatile LogStore m_serverStore;
+    private volatile Runnable m_auditLogSyncTask;
+    private static Object instance;
+
+    public LogIntegrationTest() {
+        synchronized (LogIntegrationTest.class) {
+            if (instance == null) {
+                instance = this;
+            }
+        }
+    }
+
+    @Factory
+    public Object[] createInstance() {
+        synchronized (LogIntegrationTest.class) {
+            return new Object[] { instance };
+        }
+    }
+
+    @Test(groups = { INTEGRATION })
+    public void runTests() throws Exception {
+        startupAndTestReplication();
+        testServlet();
+    }
+
+    public void startupAndTestReplication() throws Exception {
+        // now log another event
+        Properties props = new Properties();
+        props.put("one", "value1");
+        props.put("two", "value2");
+        m_auditLog.log(12345, props);
+
+        boolean found = false;
+        long startTime = System.currentTimeMillis();
+        while ((!found) && (System.currentTimeMillis() - startTime < 2000)) {
+            // synchronize again
+            m_auditLogSyncTask.run();
+
+            // get and evaluate results (note that there is some concurrency that might interfere with this test)
+            List<LogDescriptor> ranges2 = m_serverStore.getDescriptors();
+            assert ranges2.size() == 1 : "We should still have audit log events for one gateway on the server, but found " + ranges2.size();
+            LogDescriptor range = ranges2.get(0);
+            List<LogEvent> events = m_serverStore.get(range);
+            assert events.size() > 1 : "We should have a couple of events, at least more than the one we added ourselves.";
+            for (LogEvent event : events) {
+                if (event.getType() == 12345) {
+                    assert event.getProperties().get("two").equals("value2") : "We could not retrieve a property of our audit log event.";
+                    found = true;
+                    break;
+                }
+            }
+
+            // wait if we have not found anything yet
+            if (!found) {
+                try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException ie) {}
+            }
+        }
+        assert found : "We could not retrieve our audit log event (after 2 seconds).";
+    }
+
+    public void testServlet() throws Exception {
+        // prepare the store
+        List<LogEvent> events = new ArrayList<LogEvent>();
+        events.add(new LogEvent("42", 1, 1, 1, 1, new Properties()));
+        events.add(new LogEvent("47", 1, 1, 1, 1, new Properties()));
+        events.add(new LogEvent("47", 2, 1, 1, 1, new Properties()));
+        events.add(new LogEvent("47", 2, 2, 1, 1, new Properties()));
+        m_serverStore.put(events);
+
+        List<String> result = getResponse("http://localhost:8080/auditlog/query");
+        assert result.size() > 1 : "We expect at least two logs on the server.";
+
+        result = getResponse("http://localhost:8080/auditlog/receive?gwid=42");
+        assert result.size() == 1 : "Gateway 42 has a single audit log event.";
+
+        result = getResponse("http://localhost:8080/auditlog/receive?gwid=47");
+        assert result.size() == 3 : "Gateway 47 has 3 audit log events.";
+
+        result = getResponse("http://localhost:8080/auditlog/receive?gwid=47&logid=1");
+        assert result.size() == 1 : "Gateway 47, logid 1 has 1 audit log event.";
+
+        result = getResponse("http://localhost:8080/auditlog/receive?gwid=47&logid=2");
+        assert result.size() == 2 : "Gateway 47, logid 2 has 2 audit log events.";
+
+        result = getResponse("http://localhost:8080/auditlog/receive?gwid=47&logid=2&range=1");
+        assert result.size() == 1 : "Gateway 47, logid 2, range 1 has 1 audit log event.";
+
+        result = getResponse("http://localhost:8080/auditlog/receive?gwid=47&logid=2&range=3,5");
+        assert result.size() == 0 : "Gateway 47, logid 2, range 3,5 has 0 audit log event.";
+    }
+
+    private List<String> getResponse(String request) throws IOException {
+        List<String> result = new ArrayList<String>();
+        InputStream in = null;
+        try {
+            in = new URL(request).openConnection().getInputStream();
+            byte[] response = new byte[in.available()];
+            in.read(response);
+
+            StringBuilder element = new StringBuilder();
+            for (byte b : response) {
+                switch(b) {
+                    case '\n' :
+                        result.add(element.toString());
+                        element = new StringBuilder();
+                        break;
+                    default :
+                        element.append(b);
+                }
+            }
+        }
+        finally {
+            try {
+                in.close();
+            }
+            catch (Exception e) {
+                // no problem.
+            }
+        }
+        return result;
+    }
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/mockautoconf/Activator.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/mockautoconf/Activator.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/mockautoconf/Activator.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/mockautoconf/Activator.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,29 @@
+package net.luminis.liq.test.mockautoconf;
+
+import java.util.Properties;
+
+import org.apache.felix.dependencymanager.DependencyActivatorBase;
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessor;
+
+public class Activator extends DependencyActivatorBase {
+
+    private static final String PID = "org.osgi.deployment.rp.autoconf";
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        MockAutoConf impl = new MockAutoConf();
+        Properties props = new Properties();
+        props.put(Constants.SERVICE_PID, PID);
+
+        manager.add(createService().setInterface(ResourceProcessor.class.getName(), props)
+                .setImplementation(impl));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+        // do nothing
+    }
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/mockautoconf/MockAutoConf.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/mockautoconf/MockAutoConf.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/mockautoconf/MockAutoConf.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/mockautoconf/MockAutoConf.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,76 @@
+package net.luminis.liq.test.mockautoconf;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.osgi.service.deploymentadmin.spi.DeploymentSession;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessor;
+import org.osgi.service.deploymentadmin.spi.ResourceProcessorException;
+
+public class MockAutoConf implements ResourceProcessor{
+
+    public void start() {
+        System.err.println("MockAutoConf started.");
+    }
+
+    public void stop() {
+        System.err.println("MockAutoConf stopped.");
+    }
+
+    public void begin(DeploymentSession session) {
+        System.err.println("Called begin(...)");
+        // TODO Auto-generated method stub
+
+    }
+
+    public void cancel() {
+        System.err.println("Called cancel(...)");
+        // TODO Auto-generated method stub
+
+    }
+
+    public void commit() {
+        System.err.println("Called commit()");
+        // TODO Auto-generated method stub
+
+    }
+
+    public void dropAllResources() throws ResourceProcessorException {
+        System.err.println("Called dropAllResources()");
+        // TODO Auto-generated method stub
+
+    }
+
+    public void dropped(String resource) throws ResourceProcessorException {
+        System.err.println("Called dropped(" + resource + ")");
+        // TODO Auto-generated method stub
+
+    }
+
+    public void prepare() throws ResourceProcessorException {
+        System.err.println("Called prepare()");
+        // TODO Auto-generated method stub
+
+    }
+
+    public void process(String name, InputStream stream)
+            throws ResourceProcessorException {
+        System.err.println("Called process(...).\nAnd here's the resource, named '" + name + "':");
+        byte[] buf = new byte[1024];
+        try {
+            while (stream.read(buf) > 0) {
+                System.err.write(buf);
+            }
+        }
+        catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        System.err.println("That's it!");
+    }
+
+    public void rollback() {
+        System.err.println("Called rollback()");
+    }
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/repository/Activator.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/repository/Activator.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/repository/Activator.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/repository/Activator.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,32 @@
+package net.luminis.liq.test.repository;
+
+import net.luminis.test.osgi.dm.TestActivatorBase;
+
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.log.LogService;
+import org.osgi.service.prefs.PreferencesService;
+
+/**
+ * Activator for the integration test.
+ */
+public class Activator extends TestActivatorBase {
+
+    @Override
+    protected void initServices(BundleContext context, DependencyManager manager) {
+        manager.add(createService()
+            .setImplementation(RepositoryTest.class)
+            .add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
+            .add(createServiceDependency().setService(PreferencesService.class).setRequired(true))
+            .add(createServiceDependency().setService(LogService.class).setRequired(false)));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Class[] getTestClasses() {
+        return new Class[] { RepositoryTest.class };
+    }
+
+}
+

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/repository/RepositoryTest.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/repository/RepositoryTest.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/repository/RepositoryTest.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/repository/RepositoryTest.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,345 @@
+package net.luminis.liq.test.repository;
+
+import static net.luminis.liq.test.utils.TestUtils.INTEGRATION;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import net.luminis.liq.http.listener.constants.HttpConstants;
+import net.luminis.liq.repository.Repository;
+import net.luminis.liq.repository.impl.constants.RepositoryConstants;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class RepositoryTest {
+
+    private static Object m_instance;
+
+    private static final int COPY_BUFFER_SIZE = 4096;
+    private static final String MIME_APPLICATION_OCTET_STREAM = "application/octet-stream";
+    private static final String HOST = "http://localhost:8080";
+
+    private volatile ConfigurationAdmin m_configAdmin;  // Injected by dependency manager
+    private volatile BundleContext m_context;           // Injected by dependency manager
+
+    public RepositoryTest() {
+        synchronized (RepositoryTest.class) {
+            if (m_instance == null) {
+                m_instance = this;
+            }
+        }
+    }
+
+    @Factory
+    public Object[] createInstances() {
+        synchronized (RepositoryTest.class) {
+            return new Object[] { m_instance };
+        }
+    }
+
+    protected void start() throws IOException {
+        // configure the (replication)repository servlets
+        setProperty("net.luminis.liq.repository.servlet.RepositoryReplicationServlet", new Object[][] { { HttpConstants.ENDPOINT, "/replication" } });
+        setProperty("net.luminis.liq.repository.servlet.RepositoryServlet", new Object[][] { { HttpConstants.ENDPOINT, "/repository" } });
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        // remove all repositories, in case a test case does not reach it's cleanup section due to an exception
+        removeAllRepositories();
+    }
+
+    private void addRepository(String instanceName, String customer, String name, boolean isMaster) throws IOException, InterruptedException, InvalidSyntaxException {
+        addRepository(instanceName, customer, name, null, isMaster);
+    }
+
+    /* Configure a new repository instance */
+    private void addRepository(String instanceName, String customer, String name, String initial, boolean isMaster) throws IOException, InterruptedException, InvalidSyntaxException {
+        // Publish configuration for a repository instance
+        Properties props = new Properties();
+        props.put(RepositoryConstants.REPOSITORY_CUSTOMER, customer);
+        props.put(RepositoryConstants.REPOSITORY_NAME, name);
+        props.put(RepositoryConstants.REPOSITORY_MASTER, String.valueOf(isMaster));
+        if (initial != null) {
+            props.put(RepositoryConstants.REPOSITORY_INITIAL_CONTENT, initial);
+        }
+        props.put("factory.instance.pid", instanceName);
+        Configuration config = m_configAdmin.createFactoryConfiguration("net.luminis.liq.server.repository.factory", null);
+
+        ServiceTracker tracker = new ServiceTracker(m_context, m_context.createFilter("(factory.instance.pid=" + instanceName + ")"), null);
+        tracker.open();
+
+        config.update(props);
+
+        if (tracker.waitForService(1000) == null) {
+            throw new IOException("Did not get notified about new repository becoming available in time.");
+        }
+        tracker.close();
+    }
+
+    private void removeAllRepositories() throws IOException, InvalidSyntaxException, InterruptedException {
+        final Configuration[] configs = m_configAdmin.listConfigurations("(factory.instance.pid=*)");
+        if ((configs != null) && (configs.length > 0)) {
+            final Semaphore sem = new Semaphore(0);
+
+            ServiceTracker tracker = new ServiceTracker(m_context, m_context.createFilter("(" + Constants.OBJECTCLASS + "=" + Repository.class.getName() + ")"), null) {
+                @Override
+                public void removedService(ServiceReference reference, Object service) {
+                    super.removedService(reference, service);
+                    // config.length times two because the service tracker also sees added events for each instance
+                    if (size() == 0) {
+                        sem.release();
+                    }
+                }
+            };
+            tracker.open();
+
+            for (int i = 0; i < configs.length; i++) {
+                configs[i].delete();
+            }
+
+            if (!sem.tryAcquire(1, TimeUnit.SECONDS)) {
+                throw new IOException("Not all instances were removed in time.");
+            }
+            tracker.close();
+        }
+    }
+
+    private void removeRepository(String instanceName) throws IOException, InterruptedException, InvalidSyntaxException {
+        Configuration[] configs = null;
+        try {
+            configs = m_configAdmin.listConfigurations("(factory.instance.pid=" + instanceName + ")");
+        }
+        catch (InvalidSyntaxException e) {
+            // should not happen
+        }
+        if ((configs != null) && (configs.length > 0)) {
+            final Semaphore sem = new Semaphore(0);
+            ServiceTracker tracker = new ServiceTracker(m_context, m_context.createFilter("(factory.instance.pid=" + instanceName + ")"), null) {
+                @Override
+                public void removedService(ServiceReference reference, Object service) {
+                    super.removedService(reference, service);
+                    sem.release();
+                }
+            };
+            tracker.open();
+
+            configs[0].delete();
+
+            if (!sem.tryAcquire(1, TimeUnit.SECONDS)) {
+                throw new IOException("Instance did not get removed in time.");
+            }
+        }
+    }
+
+    /* Configure properties for the specified service PID */
+    @SuppressWarnings("unchecked")
+    private void setProperty(String pid, Object[][] props) throws IOException {
+        Configuration configuration = m_configAdmin.getConfiguration(pid, null);
+        Dictionary dictionary = configuration.getProperties();
+        if (dictionary == null) {
+            dictionary = new Hashtable();
+        }
+        for (Object[] pair : props) {
+            dictionary.put(pair[0], pair[1]);
+        }
+        configuration.update(dictionary);
+    }
+
+    @Test(groups = { INTEGRATION })
+    public void testCreation() throws Exception {
+        addRepository("testInstance", "luminis", "test", true);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int responseCode = query(HOST, "replication/query", null, null, out);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+        assert "luminis,test,\n".equals(out.toString()) : "Expected one repository without any versions as query result instead of : " + out.toString();
+
+        addRepository("testInstance2", "luminis", "test2", true);
+
+        out.reset();
+        responseCode = query(HOST, "replication/query", null, null, out);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+        assert "luminis,test,\nluminis,test2,\n".equals(out.toString()) ||
+               "luminis,test2,\nluminis,test,\n".equals(out.toString()) : "Expected two repositories without any versions as query result instead of : " + out.toString();
+
+        removeRepository("testInstance2");
+
+        out.reset();
+        responseCode = query(HOST, "replication/query", null, null, out);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+        assert "luminis,test,\n".equals(out.toString()) : "Expected one repository without any versions as query result instead of : " + out.toString();
+
+        removeRepository("testInstance");
+
+        out.reset();
+        responseCode = query(HOST, "replication/query", null, null, out);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+        assert "".equals(out.toString()) : "Expected one repository without any versions as query result instead of : " + out.toString();
+    }
+
+    @Test(groups = { INTEGRATION })
+    public void testGetAndPut() throws Exception {
+        addRepository("testInstance", "luminis", "test", true);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int responseCode = get(HOST, "replication/get", "luminis", "test", "1", out);
+        assert responseCode == HttpURLConnection.HTTP_NOT_FOUND : "Expected responsecode " + HttpURLConnection.HTTP_NOT_FOUND + " instead of " + responseCode;
+
+        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream("test".getBytes());
+        responseCode = put("replication/put", HOST, "luminis", "test", "1", byteArrayInputStream);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+
+        out.reset();
+        responseCode = get(HOST, "replication/get", "luminis", "test", "1", out);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+        assert "test".equals(out.toString()) : "Expected 'test' as a result of the get operation, not: " + out.toString();
+
+        removeRepository("testInstance");
+    }
+
+    @Test(groups = { INTEGRATION })
+    public void testCheckoutAndCommit() throws Exception {
+        addRepository("testInstance", "luminis", "test", true);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int responseCode = get(HOST, "repository/checkout", "luminis", "test", "1", out);
+        assert responseCode == HttpURLConnection.HTTP_NOT_FOUND : "Expected responsecode " + HttpURLConnection.HTTP_NOT_FOUND + " instead of " + responseCode;
+
+        ByteArrayInputStream input = new ByteArrayInputStream("test".getBytes());
+        responseCode = put("repository/commit", HOST, "luminis", "test", "1", input);
+        assert responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR : "Expected responsecode " + HttpURLConnection.HTTP_INTERNAL_ERROR + " instead of " + responseCode;
+
+        input.reset();
+        responseCode = put("repository/commit", HOST, "luminis", "test", "0", input);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+
+        out.reset();
+        responseCode = get(HOST, "repository/checkout", "luminis", "test", "1", out);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+
+        removeRepository("testInstance");
+    }
+
+    @Test(groups = { INTEGRATION })
+    public void testMaster() throws Exception {
+        addRepository("testInstance", "luminis", "test", false);
+
+        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream("test".getBytes());
+        int responseCode = put("replication/put", HOST, "luminis", "test", "1", byteArrayInputStream);
+        assert responseCode == HttpURLConnection.HTTP_OK;
+
+        byteArrayInputStream.reset();
+        responseCode = put("repository/commit", HOST, "luminis", "test", "0", byteArrayInputStream);
+        assert responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+
+        removeRepository("testInstance");
+    }
+
+    @Test(groups = { INTEGRATION })
+    public void testBadRequests() throws Exception {
+        addRepository("testInstance", "luminis", "test", false);
+
+        URL url = new URL(new URL(HOST), "replication/query?customer=luminis&name=test&filter=test");
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        int responseCode = connection.getResponseCode();
+        assert responseCode == HttpURLConnection.HTTP_BAD_REQUEST : "Expected responsecode " + HttpURLConnection.HTTP_BAD_REQUEST + " instead of " + responseCode;
+
+        url = new URL(new URL(HOST), "repository/query?customer=luminis&name=test&filter=test");
+        connection = (HttpURLConnection) url.openConnection();
+        responseCode = connection.getResponseCode();
+        assert responseCode == HttpURLConnection.HTTP_BAD_REQUEST : "Expected responsecode " + HttpURLConnection.HTTP_BAD_REQUEST + " instead of " + responseCode;
+
+        removeRepository("testInstance");
+    }
+
+    @Test(groups = { INTEGRATION })
+    public void testInitialContent() throws Exception {
+        addRepository("testInstance", "luminis", "test", "somecontent", true);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int responseCode = get(HOST, "repository/checkout", "luminis", "test", "1", out);
+        assert responseCode == HttpURLConnection.HTTP_OK : "Expected responsecode " + HttpURLConnection.HTTP_OK + " instead of " + responseCode;
+
+        assert Arrays.equals(out.toByteArray(), "somecontent".getBytes());
+
+        removeRepository("testInstance");
+    }
+
+    private static int query(String host, String endpoint, String customer, String name, OutputStream out) throws MalformedURLException, IOException {
+        String f1 = (customer == null) ? null : "customer=" + customer;
+        String f2 = (name == null) ? null : "name=" + name;
+        String filter = ((f1 == null) ? "?" : "?" + f1 + "&") + ((f2 == null) ? "" : f2);
+        URL url = new URL(new URL(host), endpoint + filter);
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        int responseCode = connection.getResponseCode();
+        if (responseCode == HttpURLConnection.HTTP_OK) {
+            InputStream input = connection.getInputStream();
+            copy(input, out);
+            out.flush();
+        }
+        return responseCode;
+    }
+
+    private static int get(String host, String endpoint, String customer, String name, String version, OutputStream out) throws MalformedURLException, IOException, FileNotFoundException {
+        URL url = new URL(new URL(host), endpoint + "?customer=" + customer + "&name=" + name + "&version=" + version);
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        int responseCode = connection.getResponseCode();
+        if (responseCode == HttpURLConnection.HTTP_OK) {
+            InputStream input = connection.getInputStream();
+            copy(input, out);
+            out.flush();
+        }
+        return responseCode;
+    }
+
+    private static int put(String endpoint, String host, String customer, String name, String version, InputStream in) throws MalformedURLException, IOException, FileNotFoundException {
+        URL url = new URL(new URL(host), endpoint + "?customer=" + customer + "&name=" + name + "&version=" + version);
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        connection.setDoOutput(true);
+        connection.setRequestProperty("Content-Type", MIME_APPLICATION_OCTET_STREAM);
+        OutputStream out = connection.getOutputStream();
+        copy(in, out);
+        out.flush();
+        int responseCode = connection.getResponseCode();
+        if (responseCode == HttpURLConnection.HTTP_OK) {
+            InputStream is = (InputStream) connection.getContent();
+            is.close();
+        }
+        return responseCode;
+    }
+
+    /* copy in to out */
+    private static void copy(InputStream in, OutputStream out) throws IOException {
+        byte[] buffer = new byte[COPY_BUFFER_SIZE];
+        int bytes = in.read(buffer);
+        while (bytes != -1) {
+            out.write(buffer, 0, bytes);
+            bytes = in.read(buffer);
+        }
+    }
+
+
+}

Added: incubator/ace/trunk/test/src/net/luminis/liq/test/repositoryadmin/Activator.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/test/src/net/luminis/liq/test/repositoryadmin/Activator.java?rev=788992&view=auto
==============================================================================
--- incubator/ace/trunk/test/src/net/luminis/liq/test/repositoryadmin/Activator.java (added)
+++ incubator/ace/trunk/test/src/net/luminis/liq/test/repositoryadmin/Activator.java Sat Jun 27 15:53:04 2009
@@ -0,0 +1,85 @@
+package net.luminis.liq.test.repositoryadmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import net.luminis.liq.client.repository.RepositoryAdmin;
+import net.luminis.liq.client.repository.RepositoryObject;
+import net.luminis.liq.client.repository.repository.Artifact2GroupAssociationRepository;
+import net.luminis.liq.client.repository.repository.ArtifactRepository;
+import net.luminis.liq.client.repository.repository.DeploymentVersionRepository;
+import net.luminis.liq.client.repository.repository.GatewayRepository;
+import net.luminis.liq.client.repository.repository.Group2LicenseAssociationRepository;
+import net.luminis.liq.client.repository.repository.GroupRepository;
+import net.luminis.liq.client.repository.repository.License2GatewayAssociationRepository;
+import net.luminis.liq.client.repository.repository.LicenseRepository;
+import net.luminis.liq.client.repository.stateful.StatefulGatewayObject;
+import net.luminis.liq.client.repository.stateful.StatefulGatewayRepository;
+import net.luminis.liq.server.log.store.LogStore;
+import net.luminis.liq.test.utils.TestUtils;
+import net.luminis.test.osgi.dm.TestActivatorBase;
+
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+
+/**
+ * Activator for the integration test.
+ */
+public class Activator extends TestActivatorBase {
+
+    private ConfigurationAdmin m_configAdmin;
+
+    @Override
+    protected void initServices(BundleContext context, DependencyManager manager) {
+        manager.add(createService()
+            .setImplementation(this)
+            .add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true)));
+        RepositoryAdminTest test = new RepositoryAdminTest();
+        manager.add(createService()
+            .setImplementation(test)
+            .add(createServiceDependency().setService(RepositoryAdmin.class).setRequired(true))
+            .add(createServiceDependency().setService(ArtifactRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(Artifact2GroupAssociationRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(GroupRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(Group2LicenseAssociationRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(LicenseRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(License2GatewayAssociationRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(GatewayRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(DeploymentVersionRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(StatefulGatewayRepository.class).setRequired(true))
+            .add(createServiceDependency().setService(LogStore.class, "(&("+Constants.OBJECTCLASS+"="+LogStore.class.getName()+")(name=auditlog))").setRequired(true))
+            .add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true)));
+        Dictionary<String, Object> topics = new Hashtable<String, Object>();
+        topics.put(EventConstants.EVENT_TOPIC, new String[] {RepositoryObject.PUBLIC_TOPIC_ROOT + "*",
+            RepositoryObject.PRIVATE_TOPIC_ROOT + "*",
+            RepositoryAdmin.PUBLIC_TOPIC_ROOT + "*",
+            RepositoryAdmin.PRIVATE_TOPIC_ROOT + "*",
+            StatefulGatewayObject.TOPIC_ALL});
+        manager.add(createService()
+            .setImplementation(test)
+            .setInterface(EventHandler.class.getName(), topics));
+        TestUtils.configureObject(test, DependencyManager.class, manager);
+    }
+
+    public void start() throws IOException {
+        Properties props = new Properties();
+        props.put("name", "auditlog");
+        Configuration config = m_configAdmin.createFactoryConfiguration("net.luminis.liq.server.log.store.factory", null);
+        config.update(props);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Class[] getTestClasses() {
+        return new Class[] { RepositoryAdminTest.class };
+    }
+
+}
+



Mime
View raw message