net.officefloor.plugin.woof.WoofOfficeFloorSourceTest.java Source code

Java tutorial

Introduction

Here is the source code for net.officefloor.plugin.woof.WoofOfficeFloorSourceTest.java

Source

/*
 * OfficeFloor - http://www.officefloor.net
 * Copyright (C) 2005-2013 Daniel Sagenschneider
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.officefloor.plugin.woof;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.logging.LogRecord;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.impl.client.CloseableHttpClient;

import net.officefloor.autowire.AutoWire;
import net.officefloor.autowire.AutoWireSection;
import net.officefloor.autowire.impl.AutoWireOfficeSource;
import net.officefloor.compile.impl.issues.CompileException;
import net.officefloor.compile.impl.issues.DefaultCompilerIssue;
import net.officefloor.frame.test.LoggerAssertion;
import net.officefloor.frame.test.OfficeFrameTestCase;
import net.officefloor.plugin.section.clazz.ClassSectionSource;
import net.officefloor.plugin.section.clazz.NextTask;
import net.officefloor.plugin.socket.server.http.HttpTestUtil;
import net.officefloor.plugin.socket.server.http.ServerHttpConnection;
import net.officefloor.plugin.web.http.application.WebAutoWireApplication;
import net.officefloor.plugin.web.http.location.HttpApplicationLocationManagedObjectSource;
import net.officefloor.plugin.web.http.server.HttpServerAutoWireOfficeFloorSource;
import net.officefloor.plugin.web.http.template.section.HttpTemplateSectionSource;

/**
 * Tests the {@link WoofOfficeFloorSource}.
 * 
 * @author Daniel Sagenschneider
 */
public class WoofOfficeFloorSourceTest extends OfficeFrameTestCase {

    /**
     * {@link CloseableHttpClient}.
     */
    private final CloseableHttpClient client = HttpTestUtil.createHttpClient();

    /**
     * {@link LoggerAssertion} for the {@link WoofLoader}.
     */
    private LoggerAssertion loaderLoggerAssertion;

    /**
     * {@link LoggerAssertion} for the {@link WoofOfficeFloorSource}.
     */
    private LoggerAssertion sourceLoggerAssertion;

    @Override
    protected void setUp() throws Exception {

        // Provide chain servicer extension property
        System.setProperty("CHAIN.TEST", "VALUE");

        // Create the logger assertions
        this.loaderLoggerAssertion = LoggerAssertion.setupLoggerAssertion(WoofLoaderImpl.class.getName());
        this.sourceLoggerAssertion = LoggerAssertion.setupLoggerAssertion(WoofOfficeFloorSource.class.getName());

        // Clear implicit template extension
        MockImplicitWoofTemplateExtensionSourceService.reset();
    }

    @Override
    protected void tearDown() throws Exception {

        // Clear property
        System.clearProperty("CHAIN.TEST");

        // Shutdown
        try {
            try {
                this.client.close();
            } finally {
                WoofOfficeFloorSource.stop();
            }
        } finally {
            // Disconnect from loggers
            this.sourceLoggerAssertion.disconnectFromLogger();
            this.loaderLoggerAssertion.disconnectFromLogger();
        }
    }

    /**
     * Ensure convenience constants are correctly specified.
     */
    public void testConvenienceConstants() {
        assertEquals("Incorrect convenience HTTP port property name",
                HttpApplicationLocationManagedObjectSource.PROPERTY_HTTP_PORT,
                WoofOfficeFloorSource.PROPERTY_HTTP_PORT);
    }

    /**
     * Ensure can run the application from default configuration.
     */
    public void testDefaultApplicationConfiguration() throws Exception {

        // Run the application with default configuration
        WoofOfficeFloorSource.start();

        // Test
        this.doTestRequest("/test");
    }

    /**
     * Ensure can extend the {@link WebAutoWireApplication}.
     */
    public void testWebApplicationExtension() throws Exception {

        // Run the application (extended by MockWoofApplicationExtensionService)
        WoofOfficeFloorSource.start();

        // Validate log not loading unknown extension
        LogRecord[] records = this.sourceLoggerAssertion.getLogRecords();
        StringBuilder messages = new StringBuilder();
        for (LogRecord record : records) {
            messages.append("\t" + record.getMessage() + "\n");
        }
        assertEquals("Incorrect number of records:\n" + messages.toString(), 1, records.length);
        LogRecord record = records[0];
        assertEquals("Incorrect unknown extension log record",
                WoofApplicationExtensionService.class.getName()
                        + ": Provider woof.application.extension.not.available.Service not found",
                record.getMessage());

        // Test that loaded servicer
        String response = this.doRequest("/chain");
        assertEquals("Should be serviced by chained servicer", "CHAINED", response);
    }

    /**
     * Ensure unit test methods appropriately start and stop.
     */
    public void testUnitTestMethods() throws Exception {

        final String connectionMessageSuffix = "failed: Connection refused";

        // Should not successfully connect
        try {
            this.doRequest("/test");
            fail("Should not be successful");
        } catch (HttpHostConnectException ex) {
            assertTrue("Incorrect cause: " + ex.getMessage(), ex.getMessage().endsWith(connectionMessageSuffix));
        }

        // Run the application
        WoofOfficeFloorSource.start();

        // Should now be running
        this.doTestRequest("/test");

        // Stop the application
        WoofOfficeFloorSource.stop();

        // Should not successfully connect
        CloseableHttpClient refreshedClient = HttpTestUtil.createHttpClient();
        try {
            refreshedClient.execute(new HttpGet("http://localhost:7878/test"));
            fail("Should not be successful");
        } catch (HttpHostConnectException ex) {
            assertTrue("Incorrect cause: " + ex.getMessage(), ex.getMessage().endsWith(connectionMessageSuffix));
        } finally {
            refreshedClient.close();
        }
    }

    /**
     * Ensure can run the application with additional configuration.
     */
    public void testAdditionalConfiguration() throws Exception {

        // Run the additionally configured application
        MockWoofMain.main();

        // Test
        this.doTestRequest("/another");
    }

    /**
     * Ensure can service template.
     */
    public void testTemplate() throws Exception {

        // Configure implicit template extension
        MockImplicitWoofTemplateExtensionSourceService.reset("/template");

        // Obtain no logic template WoOF configuration
        String noLogicTemplateConfigurationLocation = this.getPackageRelativePath(this.getClass())
                + "/NoLogicTemplate.woof";

        // Run the application with no logic template
        WoofOfficeFloorSource.start(WoofOfficeFloorSource.PROPERTY_WOOF_CONFIGURATION_LOCATION,
                noLogicTemplateConfigurationLocation);

        // Test
        String response = this.doRequest("/template.woof");
        assertEquals("Incorrect response", "NO LOGIC TEMPLATE", response);
    }

    /**
     * Ensure can provide command line configuration.
     */
    public void testCommandLineConfiguration() throws Exception {

        // Obtain alternate configuration location
        String alternateConfigurationLocation = this.getPackageRelativePath(this.getClass()) + "/commandline.woof";

        // Run the application with properties for alternate configuration
        WoofOfficeFloorSource.main(WoofOfficeFloorSource.PROPERTY_WOOF_CONFIGURATION_LOCATION,
                alternateConfigurationLocation);

        // Test
        this.doTestRequest("/commandline");
    }

    /**
     * Ensure can provide command line configuration with property name of the
     * form <code>-name</code>.
     */
    public void testCommandLineConfigurationWithPropertyNameHyphenPrefix() throws Exception {

        // Obtain alternate configuration location
        String alternateConfigurationLocation = this.getPackageRelativePath(this.getClass()) + "/commandline.woof";

        // Run the application with properties for alternate configuration
        WoofOfficeFloorSource.main("-" + WoofOfficeFloorSource.PROPERTY_WOOF_CONFIGURATION_LOCATION,
                alternateConfigurationLocation, "only.property.name.to.have.blank.value");

        // Test
        this.doTestRequest("/commandline");
    }

    /**
     * Ensure can retrieve <code>*.woof.html</code> files from the
     * <code>src/main/webapp</code> directory for running within unit tests for
     * maven.
     */
    public void testSrcMainWebappWoofResources() throws Exception {

        // Configure implicit template extension
        MockImplicitWoofTemplateExtensionSourceService.reset("/woofResource");

        // Obtain webapp configuration location
        String alternateConfigurationLocation = this.getPackageRelativePath(this.getClass()) + "/webapp.woof";

        // Run the application for woof resource
        WoofOfficeFloorSource.main("-" + WoofOfficeFloorSource.PROPERTY_WOOF_CONFIGURATION_LOCATION,
                alternateConfigurationLocation);

        // Test
        String response = this.doRequest("/woofResource.woof");
        assertEquals("Incorrect response",
                "This is only for testing and should not be included in built jar for project", response);
    }

    /**
     * Ensure can retrieve configured resource from the
     * <code>src/main/webapp</code> directory for running within unit tests for
     * maven.
     */
    public void testSrcMainWebappConfiguredResource() throws Exception {

        // Configure implicit template extension
        MockImplicitWoofTemplateExtensionSourceService.reset("/woofResource");

        // Obtain webapp configuration location
        String alternateConfigurationLocation = this.getPackageRelativePath(this.getClass()) + "/webapp.woof";

        // Run the application for woof resource
        WoofOfficeFloorSource.main("-" + WoofOfficeFloorSource.PROPERTY_WOOF_CONFIGURATION_LOCATION,
                alternateConfigurationLocation);

        // Test
        String response = this.doRequest("/resource");
        assertEquals("Incorrect response",
                "Configured resource for testing that should not be included in built jar for project", response);
    }

    /**
     * Ensure can retrieve static files from the <code>src/main/webapp</code>
     * directory for running within unit tests for maven.
     */
    public void testSrcMainWebappStaticResources() throws Exception {

        // Configure implicit template extension
        MockImplicitWoofTemplateExtensionSourceService.reset("/woofResource");

        // Obtain webapp configuration location
        String alternateConfigurationLocation = this.getPackageRelativePath(this.getClass()) + "/webapp.woof";

        // Run the application for woof resource
        WoofOfficeFloorSource.main("-" + WoofOfficeFloorSource.PROPERTY_WOOF_CONFIGURATION_LOCATION,
                alternateConfigurationLocation);

        // Test
        String response = this.doRequest("/NonWoof.html");
        assertEquals("Incorrect response",
                "Not a WoOF resource.  Also should not be included in resulting built jar.", response);
    }

    /**
     * Ensure only retrieve <code>*.woof.html</code> files from the
     * <code>src/main/webapp</code> directory.
     */
    public void testSrcMainWebappIgnoreOtherResources() throws Exception {

        // Configure implicit template extension
        MockImplicitWoofTemplateExtensionSourceService.reset("/not/found/resource");

        // Ensure the resource is available
        File nonWoofResource = new File(".", "src/main/webapp/NonWoof.html");
        assertTrue("Invalid test as non-WoOF resource not exists",
                (nonWoofResource.exists() && nonWoofResource.isFile()));

        // Obtain webapp configuration location
        String alternateConfigurationLocation = this.getPackageRelativePath(this.getClass()) + "/webappOther.woof";

        try {
            // Run the application for woof resource
            WoofOfficeFloorSource.main("-" + WoofOfficeFloorSource.PROPERTY_WOOF_CONFIGURATION_LOCATION,
                    alternateConfigurationLocation);
            fail("Should not successfully find resource and therefore should not start");

        } catch (CompileException ex) {
            // Should not start due to unknown resource
            assertEquals("Should not load office",
                    "Failure loading OfficeType from source " + AutoWireOfficeSource.class.getName(),
                    ex.getMessage());
            DefaultCompilerIssue issue = ex.getCompilerIssue();
            DefaultCompilerIssue officeSectionLoadIssue = (DefaultCompilerIssue) issue.getCauses()[0];
            DefaultCompilerIssue sectionLoadIssue = (DefaultCompilerIssue) officeSectionLoadIssue.getCauses()[0];
            DefaultCompilerIssue missingResourceIssue = (DefaultCompilerIssue) sectionLoadIssue.getCauses()[0];
            assertEquals("Incorrect cause",
                    "Can not obtain resource at location 'NonWoof.html' for SectionSource "
                            + HttpTemplateSectionSource.class.getName(),
                    missingResourceIssue.getIssueDescription());
        }
    }

    /**
     * Provides additional configuration to {@link WoofOfficeFloorSource} for
     * testing.
     */
    private static class MockWoofMain extends WoofOfficeFloorSource {

        /**
         * Main for running.
         * 
         * @param args
         *            Command line arguments.
         */
        public static void main(String... args) throws Exception {
            MockWoofMain main = new MockWoofMain();
            main.getOfficeFloorCompiler().addSystemProperties();
            run(main);
        }

        /*
         * =================== WoofMain ==========================
         */

        @Override
        protected void configure(HttpServerAutoWireOfficeFloorSource application) {
            AutoWireSection section = application.addSection("ANOTHER", ClassSectionSource.class.getName(),
                    Section.class.getName());
            application.linkUri("another", section, "service");
        }
    }

    /**
     * Sends request to test {@link WoofOfficeFloorSource} running.
     * 
     * @param uri
     *            URI.
     */
    private void doTestRequest(String uri) throws Exception {

        // Undertake the request
        String response = this.doRequest(uri);

        // Ensure is configured correctly by correct response
        assertEquals("Incorrect response body",
                "WOOF TEST OnePersonTeam_" + new AutoWire(MockDependency.class).getQualifiedType(), response);
    }

    /**
     * Does the request to test the running {@link WoofOfficeFloorSource}.
     * 
     * @param uri
     *            URI.
     * @return Response entity for request.
     */
    private String doRequest(String uri) throws Exception {
        HttpGet request = new HttpGet("http://localhost:7878" + uri);
        HttpResponse response = this.client.execute(request);
        assertEquals("Should be successful", 200, response.getStatusLine().getStatusCode());
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        response.getEntity().writeTo(buffer);
        return new String(buffer.toByteArray());
    }

    /**
     * Class for {@link ClassSectionSource} in testing.
     */
    public static class LinkToResource {
        @NextTask("resource")
        public void service() {
        }
    }

    /**
     * Class for {@link ClassSectionSource} in testing.
     */
    public static class Section {
        public void service(ServerHttpConnection connection, MockDependency dependency) throws IOException {

            // Obtain content to validate objects and teams
            Thread thread = Thread.currentThread();
            String content = "WOOF " + dependency.getMessage() + " " + thread.getName();

            // Write response
            net.officefloor.plugin.socket.server.http.HttpResponse response = connection.getHttpResponse();
            response.getEntity().write(content.getBytes());
        }
    }

}