Commits

Sam Adams committed 1302241

Refactored AT ChempoundServer

  • Participants
  • Parent commits 5625594

Comments (0)

Files changed (10)

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/AbstractAcceptanceTest.java

 package net.chempound.acceptance.dsl;
 
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
 import net.chempound.acceptance.dsl.driver.Resource;
-import org.apache.commons.io.FileUtils;
+import net.chempound.acceptance.dsl.server.ChempoundServer;
 import org.hamcrest.Matcher;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
-import org.restlet.Application;
-import org.restlet.Component;
-import org.restlet.data.Protocol;
 
-import java.io.File;
 import java.net.URI;
 import java.util.Random;
-import java.util.UUID;
 
 import static org.junit.Assert.assertThat;
 
  */
 public abstract class AbstractAcceptanceTest {
 
-    private static final URI ROOT = URI.create("http://localhost:12345/chempound/");
-
     private static final String RESOURCE_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-=";
 
-    private static Component component;
-    private static File workspace;
-    private static int port;
+    private static ChempoundServer chempoundServer = ChempoundServer.getInstance();
+    private static URI rootUri;
 
-    protected final TestContext testContext = new TestContext();
+    protected final TestContext testContext;
     protected final DriverFactory driverFactory;
 
     protected AbstractAcceptanceTest() {
-        this.driverFactory = new SeleniumDriverFactory(testContext, ROOT);
-    }
-
-    @After
-    public void tearDown() {
-        driverFactory.shutdown();
+        this.testContext = new TestContext(rootUri);
+        this.driverFactory = new SeleniumDriverFactory(testContext);
     }
 
     @BeforeClass
     public static void startChempound() throws Exception {
-        port = 12345;
-
-        workspace = new File("target/ats/" + UUID.randomUUID());
-        FileUtils.forceMkdir(workspace);
-
-        final Injector injector = Guice.createInjector(Stage.DEVELOPMENT,
-                                                       new ChempoundTestModule(port, workspace)
-        );
-
-        component = injector.getInstance(Component.class);
-        component.getServers().add(Protocol.HTTP, port)
-         .getContext().getParameters().add("maxThreads", "256");
-        component.getDefaultHost()
-         .attach("/chempound", injector.getInstance(Application.class));
-
-        component.start();
+        rootUri = chempoundServer.startChempoundInstance();
     }
 
     @AfterClass
     public static void stopChempound() throws Exception {
-        try {
-            if (component != null) {
-                component.stop();
-                component = null;
-            }
-        } finally {
-            FileUtils.deleteQuietly(workspace);
-        }
+        chempoundServer.stopChempoundInstance(rootUri);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        driverFactory.shutdown();
     }
 
     protected static <T, U extends T> void check(final U target, final Matcher<T>... matchers) {

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/ChempoundTestModule.java

 import java.io.File;
 import java.net.URI;
 
-import static java.lang.String.format;
-
 /**
  * @author Sam Adams
  */
 public class ChempoundTestModule extends DefaultChempoundWebModule {
 
-    private final int port;
+    private final URI rootUri;
     private final File workspace;
 
-    public ChempoundTestModule(final int port, final File workspace) {
-        this.port = port;
+    public ChempoundTestModule(final URI rootUri, final File workspace) {
+        this.rootUri = rootUri;
         this.workspace = workspace;
     }
 
     @Override
     protected void configure() {
-        final URI uri = URI.create(format("http://localhost:%d/chempound/", port));
-        
-        install(new ChempoundConfigurationModule(new DefaultChempoundConfiguration(uri, workspace)));
+        install(new ChempoundConfigurationModule(new DefaultChempoundConfiguration(rootUri, workspace)));
         install(new DefaultChempoundModule());
         super.configure();
     }

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/IdGenerator.java

+package net.chempound.acceptance.dsl;
+
+import java.util.Random;
+
+/**
+ * @author Sam Adams
+ */
+public class IdGenerator {
+    public static String generate(final String prefix) {
+        final Random random = new Random();
+        final StringBuilder text = new StringBuilder()
+            .append(prefix).append("--");
+        for (int i = 0; i < 10; i++) {
+            text.append((char) (65 + random.nextInt(26)));
+        }
+        return text.toString();
+    }
+}

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/SeleniumDriverFactory.java

 public class SeleniumDriverFactory implements DriverFactory {
 
     private final TestContext context;
-    private final URI root;
     private final WebDriver webDriver;
 
-    public SeleniumDriverFactory(final TestContext testContext, final URI root) {
+    public SeleniumDriverFactory(final TestContext testContext) {
         this.context = testContext;
-        this.root = root;
         this.webDriver = createWebDriver();
     }
 
 
     @Override
     public APIDriver createAPIDriver() {
-        return new APIDriver(context, root);
+        return new APIDriver(context);
     }
 
     @Override

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/StubBlogServer.java

-package net.chempound.acceptance.dsl;
-
-import org.restlet.*;
-import org.restlet.data.MediaType;
-import org.restlet.data.Protocol;
-import org.restlet.data.Status;
-import org.restlet.representation.StringRepresentation;
-
-import java.net.URI;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author Sam Adams
- */
-public class StubBlogServer {
-
-    private static final int PORT = 23456;
-
-    private final Component component;
-    private final ConcurrentMap<String, URI> posts = new ConcurrentHashMap<String, URI>();
-    private final ConcurrentMap<URI, AtomicInteger> visits = new ConcurrentHashMap<URI, AtomicInteger>();
-
-    public StubBlogServer() {
-        component = new Component();
-        component.getServers().add(Protocol.HTTP, PORT);
-        component.getDefaultHost().attach("/blog", new BlogApplication(component.getContext().createChildContext()));
-    }
-
-    public void start() throws Exception {
-        component.start();
-    }
-
-    public void stop() throws Exception {
-        component.stop();
-    }
-
-    public URI addPost(final URI uri) {
-        final String id = Long.toString(System.nanoTime());
-        posts.put(id, uri);
-        final URI blogUrl = URI.create("http://localhost:23456/blog/post/" + id);
-        visits.put(blogUrl, new AtomicInteger());
-        return blogUrl;
-    }
-
-    public void checkPageLoads(final URI blogUrl, final int count) {
-        assertEquals(count, visits.get(blogUrl).get());
-    }
-
-    private class BlogApplication extends Application {
-
-        public BlogApplication(final Context context) {
-            super(context);
-        }
-
-        @Override
-        public void handle(final Request request, final Response response) {
-            final String path = request.getResourceRef().getRemainingPart();
-            if (path.startsWith("/post/")) {
-                final String id = path.substring(6);
-                if (posts.containsKey(id)) {
-                    visits.get(request.getResourceRef().toUri()).incrementAndGet();
-
-                    final String s = "<html>" +
-                            "<head><title>Blog Post</title></head>" +
-                            "<body>" +
-                            "<p><a href='" + posts.get(id) + "'>link to item</a></p>" +
-                            "</body>" +
-                            "</html>";
-
-                    response.setEntity(new StringRepresentation(s, MediaType.TEXT_HTML));
-                    return;
-                }
-            }
-            response.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
-        }
-
-    }
-
-}

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/TestContext.java

 package net.chempound.acceptance.dsl;
 
+import java.net.URI;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Random;
 
 /**
  * @author Sam Adams
 public class TestContext {
 
     private final Map<String, String> actuals = new HashMap<String, String>();
+    private final URI rootUri;
+
+    public TestContext(final URI rootUri) {
+        this.rootUri = rootUri;
+    }
+
+    public URI getRootUri() {
+        return rootUri;
+    }
+
+    public URI getContentRoot() {
+        return rootUri.resolve("content/");
+    }
+
+    public URI getPingbackUrl() {
+        return rootUri.resolve("pingback");
+    }
 
     public String actual(final String key) {
         if (key == null) {
         if (actuals.containsKey(key)) {
             return actuals.get(key);
         }
-        final String actual = generate(key);
+        final String actual = IdGenerator.generate(key);
         actuals.put(key, actual);
         return actual;
     }
-
-    protected static String generate(final String prefix) {
-        final Random random = new Random();
-        final StringBuilder text = new StringBuilder()
-            .append(prefix).append("--");
-        for (int i = 0; i < 10; i++) {
-            text.append((char) (65 + random.nextInt(26)));
-        }
-        return text.toString();
-    }
 }

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/driver/APIDriver.java

 import net.chempound.storage.LocalResource;
 import net.chempound.util.MimeType;
 
-import java.net.URI;
-
 /**
  * @author Sam Adams
  */
     private final ChempoundClient client;
     private final TestContext context;
 
-    private final URI contentRoot;
-
-    public APIDriver(final TestContext context, final URI root) {
+    public APIDriver(final TestContext context) {
         this.context = context;
         this.client = new DefaultChempoundClient();
-        this.contentRoot = root.resolve("content/");
     }
     
     public CreateCollectionInstruction createCollection() {
 
     Collection createCollection(final CreateCollectionInstruction config) {
         final CreateCollectionRequest request = new CreateCollectionRequest()
-            .withUri(config.parent != null ? config.parent : contentRoot)
+            .withUri(config.parent != null ? config.parent : context.getContentRoot())
             .withTitle(context.actual(config.title))
             .withSlug(context.actual(config.slug));
 
 
     DepositReceipt depositItem(final DepositInstruction config) {
         final DepositItemRequest request = new DepositItemRequest()
-            .withUri(config.parent != null ? config.parent : contentRoot)
+            .withUri(config.parent != null ? config.parent : context.getContentRoot())
             .withTitle(context.actual(config.title))
             .withSlug(context.actual(config.slug));
 

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/server/ChempoundServer.java

+package net.chempound.acceptance.dsl.server;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Stage;
+import net.chempound.acceptance.dsl.ChempoundTestModule;
+import net.chempound.acceptance.dsl.IdGenerator;
+import org.apache.commons.io.FileUtils;
+import org.restlet.Application;
+import org.restlet.Component;
+import org.restlet.Server;
+import org.restlet.data.Protocol;
+
+import java.io.File;
+import java.net.URI;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * @author Sam Adams
+ */
+public class ChempoundServer {
+
+    private static final int PORT = 12345;
+
+    private static final ChempoundServer SINGLETON_INSTANCE = new ChempoundServer();
+
+    private final Component component;
+    private final ConcurrentMap<URI, Application> instances = new ConcurrentHashMap<URI, Application>();
+
+    private static File workspace;
+
+    public static ChempoundServer getInstance() {
+        return SINGLETON_INSTANCE;
+    }
+
+    private ChempoundServer() {
+        component = new Component();
+        final Server server = component.getServers().add(Protocol.HTTP, PORT);
+        server.getContext().getParameters().add("maxThreads", "256");
+    }
+
+    public URI startChempoundInstance() throws Exception {
+        if (component.isStopped()) {
+            startComponent();
+        }
+
+        final String id = IdGenerator.generate("chempound");
+
+        workspace = new File("target/ats/" + id);
+        FileUtils.forceMkdir(workspace);
+
+        final URI rootUri = URI.create(String.format("http://localhost:%d/%s/", PORT, id));
+        final Application instance = createChempoundInstance(rootUri);
+        instances.put(rootUri, instance);
+        component.getDefaultHost().attach('/' + id, instance);
+
+        instance.start();
+
+        return rootUri;
+    }
+
+    private Application createChempoundInstance(final URI rootUri) {
+        final Injector injector = Guice.createInjector(Stage.PRODUCTION, new ChempoundTestModule(rootUri, workspace));
+
+        return injector.getInstance(Application.class);
+    }
+
+    public void stopChempoundInstance(final URI rootUri) throws Exception {
+        final Application instance = instances.remove(rootUri);
+        component.getDefaultHost().detach(instance);
+        instance.stop();
+        FileUtils.deleteQuietly(workspace);
+
+        if (instances.isEmpty()) {
+            stopComponent();
+        }
+    }
+
+    private synchronized void startComponent() throws Exception {
+        if (component.isStopped()) {
+            component.start();
+        }
+    }
+
+    private synchronized void stopComponent() throws Exception {
+        if (instances.isEmpty()) {
+            component.stop();
+        }
+    }
+}

File acceptance-test-driver/src/main/java/net/chempound/acceptance/dsl/server/StubBlogServer.java

+package net.chempound.acceptance.dsl.server;
+
+import org.restlet.*;
+import org.restlet.data.MediaType;
+import org.restlet.data.Protocol;
+import org.restlet.data.Status;
+import org.restlet.representation.StringRepresentation;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Sam Adams
+ */
+public class StubBlogServer {
+
+    private static final int PORT = 12346;
+
+    private final Component component;
+    private final ConcurrentMap<String, List<URI>> posts = new ConcurrentHashMap<String, List<URI>>();
+    private final ConcurrentMap<URI, AtomicInteger> visits = new ConcurrentHashMap<URI, AtomicInteger>();
+
+    public StubBlogServer() {
+        component = new Component();
+        component.getServers().add(Protocol.HTTP, PORT);
+        component.getDefaultHost().attach("/blog", new BlogApplication(component.getContext().createChildContext()));
+    }
+
+    public void start() throws Exception {
+        component.start();
+    }
+
+    public void stop() throws Exception {
+        component.stop();
+    }
+
+    public URI addPost(final URI... uri) {
+        final String id = Long.toString(System.nanoTime());
+        posts.put(id, Arrays.asList(uri));
+        final URI blogUrl = URI.create(String.format("http://localhost:%d/blog/post/%s", PORT, id));
+        visits.put(blogUrl, new AtomicInteger());
+        return blogUrl;
+    }
+
+    public void checkPageLoads(final URI blogUrl, final int count) {
+        assertEquals(count, visits.get(blogUrl).get());
+    }
+
+    private class BlogApplication extends Application {
+
+        public BlogApplication(final Context context) {
+            super(context);
+        }
+
+        @Override
+        public void handle(final Request request, final Response response) {
+            final String path = request.getResourceRef().getRemainingPart();
+            if (path.startsWith("/post/")) {
+                final String id = path.substring(6);
+                if (posts.containsKey(id)) {
+                    visits.get(request.getResourceRef().toUri()).incrementAndGet();
+
+                    final StringBuilder html = new StringBuilder()
+                     .append("<html>")
+                     .append("<head><title>Blog Post</title></head>")
+                     .append("<body>");
+                    for (final URI item : posts.get(id)) {
+                        html.append("<p><a href='" + item + "'>link to item</a></p>");
+                    }
+                    html
+                     .append("</body>")
+                     .append("</html>");
+
+                    response.setEntity(new StringRepresentation(html.toString(), MediaType.TEXT_HTML));
+                    return;
+                }
+            }
+            response.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+        }
+
+    }
+
+}

File acceptance-tests/src/test/java/net/chempound/acceptance/PingbackAcceptanceTest.java

 package net.chempound.acceptance;
 
 import net.chempound.acceptance.dsl.AbstractAcceptanceTest;
-import net.chempound.acceptance.dsl.StubBlogServer;
+import net.chempound.acceptance.dsl.server.StubBlogServer;
 import net.chempound.acceptance.dsl.driver.APIDriver;
 import net.chempound.acceptance.dsl.driver.DepositReceipt;
 import net.chempound.acceptance.dsl.driver.PingbackDriver;
     }
 
     @Test
+    public void shouldAcceptPingbackToMultipleItems() throws Exception {
+        DepositReceipt otherItem = apiDriver.depositItem().execute();
+
+        URI blog = blogServer.addPost(item.getUri(), otherItem.getUri());
+
+        pingbackDriver.pingback(item.getUri(), blog);
+        pingbackDriver.pingback(otherItem.getUri(), blog);
+
+        blogServer.checkPageLoads(blog, 2);
+    }
+
+    @Test
     public void shouldRejectDuplicatePingbackToItem() throws Exception {
         URI blog = blogServer.addPost(item.getUri());
 
     public void shouldRejectPingbackToNonExistentItem() throws Exception {
         final URI itemUri = item.getUri().resolve("--does-not-exist");
         URI blog = blogServer.addPost(itemUri);
-        pingbackDriver.doPingback(itemUri, blog, PingbackFault.TARGET_URI_INVALID, URI.create("http://localhost:12345/chempound/pingback"));
+        pingbackDriver.doPingback(itemUri, blog, PingbackFault.TARGET_URI_INVALID, testContext.getPingbackUrl());
     }
 
     @Test