org.eclipse.virgo.repository.internal.remote.RemoteRepositoryTests.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.virgo.repository.internal.remote.RemoteRepositoryTests.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2010 VMware Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   VMware Inc. - initial contribution
 *******************************************************************************/

package org.eclipse.virgo.repository.internal.remote;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.httpclient.HttpStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Version;

import org.eclipse.virgo.medic.eventlog.EventLogger;
import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;

import org.eclipse.virgo.repository.ArtifactBridge;
import org.eclipse.virgo.repository.ArtifactDescriptor;
import org.eclipse.virgo.repository.ArtifactGenerationException;
import org.eclipse.virgo.repository.DuplicateArtifactException;
import org.eclipse.virgo.repository.IndexFormatException;
import org.eclipse.virgo.repository.Repository;
import org.eclipse.virgo.repository.RepositoryAwareArtifactDescriptor;
import org.eclipse.virgo.repository.builder.ArtifactDescriptorBuilder;
import org.eclipse.virgo.repository.configuration.RemoteRepositoryConfiguration;
import org.eclipse.virgo.repository.configuration.StubRepositoryConfiguration;
import org.eclipse.virgo.repository.internal.PersistentRepository;
import org.eclipse.virgo.repository.internal.RepositoryLogEvents;
import org.eclipse.virgo.repository.internal.remote.RemoteRepository;
import org.eclipse.virgo.repository.management.RepositoryInfo;
import org.eclipse.virgo.util.io.FileCopyUtils;
import org.eclipse.virgo.util.osgi.manifest.VersionRange;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class RemoteRepositoryTests {

    private static final String MBEAN_DOMAIN_VIRGO_WEB_SERVER = "org.eclipse.virgo.server";

    private final MockEventLogger mockEventLogger = new MockEventLogger();

    private String indexEtag;

    private final Object repositoryLock = new Object();

    private int repositoryId = 0;

    private HttpServer httpServer;

    private final File indexLocation = new File("target/index");

    private final File proxyIndexLocation = new File("target/proxy.index");

    private final File cacheDirectory = new File("target");

    @Before
    public void deleteIndex() {
        this.indexLocation.delete();
        this.proxyIndexLocation.delete();
    }

    private void createRepository(ArtifactBridge artefactBridge, EventLogger eventLogger) throws Exception {
        this.indexLocation.delete();
        synchronized (this.repositoryLock) {
            StubRepository repository = new StubRepository(artefactBridge, this.indexLocation, eventLogger);
            repository.addArtifact(new File("artefact0"));
            repository.addArtifact(new File("artefact1"));
            repository.addArtifact(new File("artefact2"));
            repository.persist();

            this.indexEtag = Integer.toString(this.repositoryId++);
        }
    }

    private void bootstrapHttpServer(HttpHandler handler) throws IOException {
        this.httpServer = HttpServer.create(new InetSocketAddress("localhost", 8080), 30);
        this.httpServer.start();

        this.httpServer.createContext("/repository", handler);
    }

    private class StandardHttpHandler implements HttpHandler {

        public void handle(HttpExchange exchange) throws IOException {
            synchronized (RemoteRepositoryTests.this.repositoryLock) {
                boolean notModified = false;

                List<String> etags = exchange.getRequestHeaders().get("If-None-Match");

                if (etags != null) {
                    for (String etag : etags) {
                        if (RemoteRepositoryTests.this.indexEtag.equals(etag)) {
                            notModified = true;
                            break;
                        }
                    }
                }

                exchange.getResponseHeaders().set("Etag", RemoteRepositoryTests.this.indexEtag);

                if (notModified) {
                    exchange.sendResponseHeaders(304, 0);
                } else {
                    sendIndex(exchange);
                }
                exchange.getResponseBody().close();
            }
        }
    }

    private void sendIndex(HttpExchange exchange) throws IOException {
        exchange.getResponseHeaders().set("Content-Type", "application/org.eclipse.virgo.repository.Index");

        ByteArrayOutputStream indexStream = new ByteArrayOutputStream();
        FileInputStream input = new FileInputStream(RemoteRepositoryTests.this.indexLocation);
        FileCopyUtils.copy(input, indexStream);
        byte[] index = indexStream.toByteArray();
        exchange.sendResponseHeaders(200, index.length);
        exchange.getResponseBody().write(index);
    }

    @After
    public void shutdownHttpServer() {
        if (this.httpServer != null) {
            this.httpServer.stop(0);
        }
        this.indexLocation.delete();
    }

    @Test(timeout = 5 * 60 * 1000)
    public void queryAcrossUpdates() throws Exception {
        ArtifactBridge bridge = new StubArtifactBridge();
        createRepository(bridge, this.mockEventLogger);
        bootstrapHttpServer(new StandardHttpHandler());

        URI repositoryUri = URI.create("http://localhost:8080/repository");
        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = createRemoteRepository(configuration, this.mockEventLogger);
        repository.start();

        int size = 0;
        Set<RepositoryAwareArtifactDescriptor> artifacts = null;
        while (size != 3) {
            artifacts = repository.createQuery("type", "dummy").run();
            size = artifacts.size();
        }

        for (RepositoryAwareArtifactDescriptor artifact : artifacts) {
            Version version = artifact.getVersion();

            if (version.getMajor() > 2) {
                fail("Unexpected version: " + version);
            }
        }

        createRepository(bridge, this.mockEventLogger);
        boolean success = true;

        do {
            artifacts = repository.createQuery("type", "dummy").run();
            if (artifacts.size() != 3) {
                success = false;
            } else {
                for (RepositoryAwareArtifactDescriptor artifact : artifacts) {
                    Version version = artifact.getVersion();

                    if (version.getMajor() < 3 || version.getMajor() > 5) {
                        success = false;
                        break;
                    }

                    success = true;
                }
            }
        } while (!success);

        repository.stop();

    }

    protected RemoteRepository createRemoteRepository(RemoteRepositoryConfiguration configuration,
            EventLogger eventLogger) {
        return new RemoteRepository(configuration, eventLogger);
    }

    @Test
    public void get() throws Exception {
        ArtifactBridge bridge = new StubArtifactBridge();
        createRepository(bridge, this.mockEventLogger);

        bootstrapHttpServer(new StandardHttpHandler());

        URI repositoryUri = URI.create("http://localhost:8080/repository");

        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = new RemoteRepository(configuration, new MockEventLogger());

        repository.start();

        pollUntilDescriptorAvailable(repository, "dummy", "dummy", new VersionRange("[2,2]"));
        assertNull(repository.get("dummy", "dummy", new VersionRange("[3,4)")));

        repository.stop();
    }

    @Test
    public void repositoryAvailableMessageIsLoggedOnceRepositoryHasStarted() throws Exception {
        ArtifactBridge bridge = new StubArtifactBridge();
        createRepository(bridge, new MockEventLogger());
        bootstrapHttpServer(new StandardHttpHandler());

        URI repositoryUri = URI.create("http://localhost:8080/repository");
        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = createRemoteRepository(configuration, this.mockEventLogger);
        repository.start();

        String eventCode = RepositoryLogEvents.REPOSITORY_AVAILABLE.getEventCode();
        while (!this.mockEventLogger.containsLogged(eventCode)) {
            Thread.sleep(50);
        }
    }

    @Test
    public void indexlessRepository() throws Exception {
        URI repositoryUri = URI.create("http://localhost:8080/does-not-exist");

        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = new RemoteRepository(configuration, new MockEventLogger());

        repository.start();

        assertTrue(repository.createQuery("name", "foo").run().isEmpty());
        assertNull(repository.get("foo", "the-foo", VersionRange.NATURAL_NUMBER_RANGE));

        repository.stop();
    }

    @Test(expected = IllegalArgumentException.class)
    public void badScheme() throws Exception {
        URI repositoryUri = URI.create("hotp://localhost:8080/repository");

        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = new RemoteRepository(configuration, new MockEventLogger());
        assertFalse("Managed to create a badly formed RemoteRepository!", repository != null);
    }

    @Test(timeout = 5 * 60 * 1000)
    public void shorterThanExpectedIndex() throws Exception {
        ArtifactBridge bridge = new StubArtifactBridge();
        createRepository(bridge, this.mockEventLogger);
        final AtomicBoolean sendProperIndex = new AtomicBoolean(false);

        bootstrapHttpServer(new HttpHandler() {

            public void handle(HttpExchange exchange) throws IOException {
                if (sendProperIndex.get()) {
                    sendIndex(exchange);
                } else {
                    long responseLength = 1234;
                    exchange.sendResponseHeaders(HttpStatus.SC_OK, responseLength);
                }
                exchange.getResponseBody().close();
            }
        });

        URI repositoryUri = URI.create("http://localhost:8080/repository");

        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = new RemoteRepository(configuration, new MockEventLogger());
        repository.start();

        assertNull(repository.get("dummy", "dummy", new VersionRange("[2,2]")));

        createRepository(new StubArtifactBridge(), this.mockEventLogger);
        sendProperIndex.set(true);

        pollUntilDescriptorAvailable(repository, "dummy", "dummy", new VersionRange("[2,2]"));

        repository.stop();
    }

    void pollUntilDescriptorAvailable(Repository repository, String type, String name, VersionRange version) {
        while (repository.get(type, name, version) == null) {
        }
    }

    @Test(timeout = 5 * 60 * 1000)
    public void longerThanExpectedIndex() throws Exception {
        ArtifactBridge bridge = new StubArtifactBridge();
        createRepository(bridge, this.mockEventLogger);
        final AtomicBoolean sendProperIndex = new AtomicBoolean(false);

        bootstrapHttpServer(new HttpHandler() {

            public void handle(HttpExchange exchange) throws IOException {
                if (sendProperIndex.get()) {
                    sendIndex(exchange);
                } else {
                    exchange.sendResponseHeaders(200, 4);
                    exchange.getResponseBody().write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
                }
                exchange.getResponseBody().close();
            }
        });

        URI repositoryUri = URI.create("http://localhost:8080/repository");

        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = new RemoteRepository(configuration, new MockEventLogger());
        repository.start();

        assertNull(repository.get("dummy", "dummy", new VersionRange("[2,2]")));

        createRepository(new StubArtifactBridge(), this.mockEventLogger);
        sendProperIndex.set(true);

        while (repository.get("dummy", "dummy", new VersionRange("[2,2]")) == null) {
        }

        repository.stop();
    }

    @Test(timeout = 5 * 60 * 1000)
    public void corruptedIndex() throws Exception {
        ArtifactBridge bridge = new StubArtifactBridge();
        createRepository(bridge, this.mockEventLogger);
        final AtomicBoolean sendProperIndex = new AtomicBoolean(false);

        bootstrapHttpServer(new HttpHandler() {

            public void handle(HttpExchange exchange) throws IOException {
                if (sendProperIndex.get()) {
                    sendIndex(exchange);
                } else {
                    byte[] indexBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
                    exchange.sendResponseHeaders(200, indexBytes.length);
                    exchange.getResponseBody().write(indexBytes);
                }
                exchange.getResponseBody().close();
            }
        });

        URI repositoryUri = URI.create("http://localhost:8080/repository");
        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = new RemoteRepository(configuration, new MockEventLogger());
        repository.start();

        assertNull(repository.get("dummy", "dummy", new VersionRange("[2,2]")));

        createRepository(new StubArtifactBridge(), this.mockEventLogger);
        sendProperIndex.set(true);

        while (repository.get("dummy", "dummy", new VersionRange("[2,2]")) == null) {
        }

        sendProperIndex.set(false);

        Thread.sleep(3000);

        repository.stop();
    }

    @Test
    public void mBeanPublication() throws Exception {
        URI repositoryUri = URI.create("http://localhost:8080/repository");
        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, MBEAN_DOMAIN_VIRGO_WEB_SERVER, this.cacheDirectory);
        RemoteRepository repository = new RemoteRepository(configuration, new MockEventLogger());
        ObjectName objectName = new ObjectName(MBEAN_DOMAIN_VIRGO_WEB_SERVER + ":type=Repository,name=remote-repo");

        MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();

        try {
            platformMBeanServer.getMBeanInfo(objectName);
            fail("MBean should not be present until repository has been started");
        } catch (InstanceNotFoundException infe) {
        }

        repository.start();

        MBeanInfo mBeanInfo = platformMBeanServer.getMBeanInfo(objectName);
        Object type = mBeanInfo.getDescriptor().getFieldValue("type");
        assertNotNull(type);
        assertEquals("remote", type);

        repository.stop();

        try {
            platformMBeanServer.getMBeanInfo(objectName);
            fail("MBean should not be present once repository has been stopped");
        } catch (InstanceNotFoundException infe) {
        }
    }

    @Test
    public void mBeanNonPublication() throws Exception {
        URI repositoryUri = URI.create("http://localhost:8080/repository");
        RemoteRepositoryConfiguration configuration = new RemoteRepositoryConfiguration("remote-repo",
                this.proxyIndexLocation, repositoryUri, 1, null, this.cacheDirectory);
        RemoteRepository repository = new RemoteRepository(configuration, new MockEventLogger());
        ObjectName objectName = new ObjectName(MBEAN_DOMAIN_VIRGO_WEB_SERVER + ":type=Repository,name=remote-repo");
        MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();

        try {
            platformMBeanServer.getMBeanInfo(objectName);
            fail("MBean should not be present before start");
        } catch (InstanceNotFoundException infe) {
        }

        repository.start();

        try {
            platformMBeanServer.getMBeanInfo(objectName);
            fail("MBean should not be present after start");
        } catch (InstanceNotFoundException infe) {
        }

        repository.stop();

        try {
            platformMBeanServer.getMBeanInfo(objectName);
            fail("MBean should not be present once repository has been stopped");
        } catch (InstanceNotFoundException infe) {
        }
    }

    private static class StubArtifactBridge implements ArtifactBridge {

        private int version = 0;

        private final RuntimeException exception;

        StubArtifactBridge() {
            this.exception = null;
        }

        @SuppressWarnings("unused")
        StubArtifactBridge(RuntimeException exception) {
            this.exception = exception;
        }

        public ArtifactDescriptor generateArtifactDescriptor(File artifact) throws ArtifactGenerationException {
            if (this.exception == null) {
                return new ArtifactDescriptorBuilder().setUri(artifact.toURI()).setType("dummy").setName("dummy")
                        .setVersion(String.valueOf(this.version++)).build();
            }
            throw this.exception;
        }
    }

    private static class StubRepository extends PersistentRepository {

        StubRepository(ArtifactBridge artifactBridge, File indexLocation, EventLogger eventLogger)
                throws IndexFormatException {
            super(new StubRepositoryConfiguration(artifactBridge, indexLocation), eventLogger);
        }

        public void persist() throws IOException {
            getDepository().persist();
        }

        public void addArtifact(File artifact) throws DuplicateArtifactException {
            RepositoryAwareArtifactDescriptor artifactDescriptor = createArtifactDescriptor(artifact);
            if (artifactDescriptor != null) {
                getDepository().addArtifactDescriptor(artifactDescriptor);
            }
        }

        @Override
        protected RepositoryInfo createMBean() {
            return null;
        }
    }

}