net.sourceforge.cobertura.test.util.WebappServer.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.cobertura.test.util.WebappServer.java

Source

/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (C) 2000-2002 The Apache Software Foundation.  All rights
 * reserved.
 * Copyright (C) 2009 John Lewis
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "Ant" and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package net.sourceforge.cobertura.test.util;

import static org.junit.Assert.*;

import groovy.lang.Closure;
import net.sourceforge.cobertura.ant.InstrumentTask;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.tools.ant.taskdefs.*;
import org.apache.tools.ant.types.Environment.Variable;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.ZipFileSet;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class WebappServer {
    public static final String SIMPLE_SERVLET_CLASSNAME = "com.acme.servlet.SimpleServlet";

    private static final String JETTY_DIR = "src/test/resources/jetty";

    public static final String SIMPLE_SERVLET_TEXT = "\n package com.acme.servlet;" + "\n "
            + "\n import javax.servlet.http.HttpServlet;" + "\n import javax.servlet.http.HttpServletRequest;"
            + "\n import javax.servlet.http.HttpServletResponse;" + "\n " + "\n import java.io.PrintWriter;"
            + "\n import java.io.IOException;" + "\n " + "\n public class SimpleServlet extends HttpServlet"
            + "\n {"
            + "\n  protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException"
            + "\n  {" + "\n   response.setContentType(\"text/html;charset=UTF-8\");"
            + "\n   PrintWriter out = response.getWriter();" + "\n   try" + "\n   {" + "\n    out.println(\"Hi\");"
            + "\n   }" + "\n   finally" + "\n   {" + "\n    if (out != null)" + "\n    {" + "\n     out.close();"
            + "\n    }" + "\n   }" + "\n  }" + "\n }";

    public static final String SIMPLE_SERVLET_WEB_XML_TEXT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
            + "\n <web-app version=\"2.4\" xmlns=\"http://java.sun.com/xml/ns/j2ee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd\">"
            + "\n  <servlet>" + "\n   <servlet-name>SimpleServlet</servlet-name>"
            + "\n   <servlet-class>com.acme.servlet.SimpleServlet</servlet-class>" + "\n  </servlet>"
            + "\n  <servlet-mapping>" + "\n   <servlet-name>SimpleServlet</servlet-name>"
            + "\n   <url-pattern>/SimpleServlet</url-pattern>" + "\n  </servlet-mapping>" + "\n </web-app>";

    private static final String LOCALHOST = "127.0.0.1";
    private static final String WEB_XML = "src/main/resources/net/sourceforge/cobertura/webapp/web.xml";
    private static final String SRC_DIR = "src/main/java";
    private static final String appName = "simple";
    private int webappPort;
    private int stopPort;

    File dir = new File(TestUtils.getTempDir(), "webserver");
    boolean modifyMainCoberturaDataFile;
    boolean tomcat;

    public WebappServer(File webappServerDir, boolean tomcat) {
        this.tomcat = tomcat;
        ServerSocket s;
        try {
            s = new ServerSocket(0);
            webappPort = s.getLocalPort();
            s.close();

            s = new ServerSocket(0);
            stopPort = s.getLocalPort();
            s.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void deployApp(File srcDir, boolean instrumentCobertura, boolean deployCoberturaFlush,
            boolean modifyMainCoberturaDataFile, String instrumentRegEx) throws Exception {
        this.modifyMainCoberturaDataFile = modifyMainCoberturaDataFile;

        File extractedDir = new File(dir, "extracted");
        File webInfDir = new File(extractedDir, "WEB-INF");
        File classesDir = new File(webInfDir, "classes");

        File webInfFile = writeWebInfFile(webInfDir, SIMPLE_SERVLET_WEB_XML_TEXT);

        compileSourceFiles(srcDir, classesDir);

        copyJettyFiles(dir);

        File war = makeWarFile(appName, webInfFile, classesDir);

        FileUtils.deleteDirectory(extractedDir);

        File coberturaJar = createCoberturaJar();

        if (instrumentRegEx != null) {
            instrumentWar(war, instrumentRegEx);
        }

        if (instrumentCobertura != false) {
            instrumentCoberturaJar(coberturaJar);
        }

        if (deployCoberturaFlush != false) {
            deployCoberturaFlush(deployCoberturaFlush);
        }
    }

    public void deployApp(File srcDir, boolean instrumentCobertura, boolean deployCoberturaFlush,
            boolean modifyMainCoberturaDataFile) throws Exception {
        deployApp(srcDir, instrumentCobertura, deployCoberturaFlush, modifyMainCoberturaDataFile, "");
    }

    public void deployApp(File srcDir, boolean deployCoberturaFlush, String instrumentRegEx) throws Exception {
        deployApp(srcDir, false, deployCoberturaFlush, false, instrumentRegEx);
    }

    public void deployApp(File srcDir, String instrumentRegEx) throws Exception {
        deployApp(srcDir, false, instrumentRegEx);
    }

    public void deployApp(File srcDir) throws Exception {
        deployApp(srcDir, "");
    }

    private File writeWebInfFile(File webInfDir, String text) throws IOException {
        assertTrue(webInfDir.mkdirs());
        File webInfFile = new File(webInfDir, "web.xml");

        FileUtils.writeStringToFile(webInfFile, text);
        return webInfFile;
    }

    private void compileSourceFiles(File srcDir, File classesDir) {
        Mkdir mkdir = new Mkdir();
        mkdir.setProject(TestUtils.project);
        mkdir.setDir(classesDir);
        mkdir.execute();

        Javac javac = new Javac();
        javac.setProject(TestUtils.project);
        javac.setSrcdir(new Path(TestUtils.project, srcDir.getAbsolutePath()));
        javac.setDestdir(classesDir);
        javac.setDebug(true);
        javac.setTarget("1.7");

        Path classpath = new Path(TestUtils.project);
        FileSet fileSet = new FileSet();
        fileSet.setDir(new File(JETTY_DIR));
        fileSet.setIncludes("**/*.jar");
        classpath.addFileset(fileSet);

        javac.setClasspath(classpath);
        javac.execute();
    }

    private void copyJettyFiles(File todir) {
        Copy copy = new Copy();
        copy.setProject(TestUtils.project);
        copy.setTodir(todir);
        FileSet fileSet = new FileSet();
        fileSet.setProject(TestUtils.project);
        fileSet.setDir(new File(JETTY_DIR));
        copy.addFileset(fileSet);
        copy.execute();
    }

    private File makeWarFile(String appName, File webInfFile, File classesDir) {
        File webappsDir = new File(dir, "webapps");
        File war = new File(webappsDir, appName + ".war");

        War antWar = new War();
        antWar.setProject(TestUtils.project);
        antWar.setDestFile(war);
        antWar.setWebxml(webInfFile);
        ZipFileSet zipFileSet = new ZipFileSet();
        zipFileSet.setDir(classesDir);
        antWar.addClasses(zipFileSet);
        antWar.execute();

        return war;
    }

    private void deployCoberturaFlush(boolean instrumentCobertura) throws Exception {
        File webappsDir = new File(dir, "webapps");
        File war = new File(webappsDir, "coberturaFlush.war");

        File classesDir = new File("target/build/warClasses");
        if (!classesDir.exists())
            classesDir.mkdirs();
        Javac javac = new Javac();
        javac.setProject(TestUtils.project);
        javac.setSrcdir(new Path(TestUtils.project, SRC_DIR));
        javac.setDestdir(classesDir);
        javac.setDebug(true);

        Path classpath = new Path(TestUtils.project);
        FileSet jettyFileSet = new FileSet();
        jettyFileSet.setDir(new File(JETTY_DIR));
        jettyFileSet.setIncludes("**/*.jar");
        classpath.addFileset(jettyFileSet);

        javac.setIncludes("**/FlushCoberturaServlet.java");

        javac.setClasspath(classpath);
        javac.execute();

        War antWar = new War();
        antWar.setProject(TestUtils.project);
        antWar.setDestFile(war);
        antWar.setWebxml(new File(WEB_XML));

        ZipFileSet classesFileSet = new ZipFileSet();
        classesFileSet.setDir(classesDir);

        antWar.addClasses(classesFileSet);
        antWar.execute();

        if (instrumentCobertura) {
            instrumentWar(war, "net.sourceforge.cobertura.*");
        }
    }

    private void instrumentWar(File war, String instrumentRegEx) {
        InstrumentTask instrumentTask = new InstrumentTask();
        instrumentTask.setProject(TestUtils.project);
        instrumentTask.setDataFile(dir.getAbsolutePath() + "/cobertura.ser");
        instrumentTask.createIncludeClasses().setRegex(instrumentRegEx);
        instrumentTask.createExcludeClasses().setRegex(".*Test.*");
        System.out.println(war.getAbsolutePath());
        FileSet fileSet = new FileSet();
        fileSet.setDir(war.getParentFile());
        fileSet.setIncludes("**/*.war");

        instrumentTask.addFileset(fileSet);
        instrumentTask.execute();
    }

    private void instrumentCoberturaJar(File coberturaJar) {
        InstrumentTask instrumentTask = new InstrumentTask();
        instrumentTask.setProject(TestUtils.project);
        instrumentTask.setDataFile(dir.getAbsolutePath() + "/cobertura.ser");
        instrumentTask.createIncludeClasses().setRegex("net.sourceforge.cobertura.*");
        instrumentTask.createExcludeClasses().setRegex(".*Test.*");

        FileSet fileSet = new FileSet();
        fileSet.setDir(new File(coberturaJar.getParent()));
        fileSet.setIncludes(coberturaJar.getName());

        instrumentTask.addFileset(fileSet);
        instrumentTask.execute();
    }

    /**
     * Starts the web server and calls the closure.   The web server will be stopped 
     * when the closure exits (successfully or not).
     * @throws Exception 
     * 
     */
    public void withRunningServer() throws Exception {
        startWebServer();
        Map<String, Object> data = new HashMap<String, Object>();
        try {
            data.put("xmlReport", new File(dir.getAbsolutePath() + "/coverage.xml"));
            data.put("hostname", LOCALHOST);
            data.put("webappPort", webappPort);
            data.put("coberturaAnt", TestUtils.getCoberturaAntBuilder(TestUtils.getTempDir()));

            data.put("datafile", getDatafileToUse());

            /*
             * add a closure that can be called to flush the cobertura data
             */
            Closure closure = new Closure(null) {
                private static final long serialVersionUID = 1L;

                @SuppressWarnings("unused")
                public void doCall(HashMap<String, Object> values) {
                }
            };

            System.err.println(closure.call(data));
        } finally {
        }
    }

    public void killServer() {
        stopWebServer();
    }

    private File getDatafileToUse() {
        File datafile = new File(dir.getAbsolutePath() + "/cobertura.ser");

        if (modifyMainCoberturaDataFile) {
            /*
             * modify the cobertura.ser file created by the instrumentation target
             * of the main build.xml file.   That way, the counts
             * will end up in the overall coverage report
             */
            File tempfile = new File("target/build/cobertura.ser");
            if (tempfile.exists()) {
                datafile = tempfile;
            } else {
                /*
                 * It looks like the main build.xml's instrument target has not been run.
                 * So, a coverage report is not being generated.
                 */
            }
        }
        return datafile;
    }

    private void startWebServer() {
        System.out.println("Starting Jetty webapp server on " + webappPort);

        Thread t = new Thread() {
            @Override
            public void run() {
                Java java = new Java();
                java.setProject(TestUtils.project);
                java.setDir(dir);
                java.setJar(new File(dir, "start.jar"));
                java.setFork(true);

                Variable jettyPort = new Variable();
                jettyPort.setKey("jetty.port");
                jettyPort.setValue(String.valueOf(webappPort));
                java.addSysproperty(jettyPort);

                Variable stopPortVariable = new Variable();
                stopPortVariable.setKey("STOP.PORT");
                stopPortVariable.setValue(String.valueOf(stopPort));
                java.addSysproperty(stopPortVariable);

                Variable stopKey = new Variable();
                stopKey.setKey("STOP.KEY");
                stopKey.setValue("cobertura");
                java.addSysproperty(stopKey);

                if (tomcat) {
                    Variable catalinaHome = new Variable();
                    catalinaHome.setKey("catalina.home");
                    catalinaHome.setValue(dir.getAbsolutePath());
                    java.addSysproperty(catalinaHome);
                }

                if (modifyMainCoberturaDataFile) {
                    Variable dataFile = new Variable();
                    dataFile.setKey("net.sourceforge.cobertura.datafile");
                    dataFile.setValue(getDatafileToUse().getAbsolutePath());
                    java.addSysproperty(dataFile);
                }

                java.execute();
            }
        };
        t.start();

        try {
            Thread.sleep(10 * 1000); // Sleep for 10 seconds. The servlet needs a few seconds to boot up.
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void stopWebServer() {
        Thread t = new Thread() {
            @Override
            public void run() {
                Java java = new Java();
                java.setProject(TestUtils.project);
                java.setJar(new File(TestUtils.getTempDir(), "webserver/start.jar"));
                java.setDir(dir);
                java.setFork(true);
                java.setArgs("--stop");
                Variable stopPortVariable = new Variable();
                Variable stopKeyVariable = new Variable();

                stopPortVariable.setKey("STOP.PORT");
                stopPortVariable.setValue(String.valueOf(stopPort));

                stopKeyVariable.setKey("STOP.KEY");
                stopKeyVariable.setValue("cobertura");

                java.addSysproperty(stopPortVariable);
                java.addSysproperty(stopKeyVariable);

                java.execute();

                java.execute();
            }
        };
        t.start();
    }

    private File createCoberturaJar() {
        File coberturaJar = new File(dir, "lib/cobertura.jar");
        File coberturaClassDir = TestUtils.getCoberturaClassDir();

        Zip zip = new Zip();
        zip.setProject(TestUtils.project);
        zip.setDestFile(coberturaJar);

        FileSet fileSet = new FileSet();
        fileSet.setDir(coberturaClassDir);

        zip.addFileset(fileSet);
        zip.execute();

        return coberturaJar;
    }

    public static void writeSimpleServletSource(File srcDir) throws IOException {
        File servletSourceFile = new File(srcDir, "com/acme/servlet/SimpleServlet.java");
        assertTrue(servletSourceFile.getParentFile().mkdirs());

        FileUtils.write(servletSourceFile, SIMPLE_SERVLET_TEXT);
    }

    public void pingServer() {
        String webappResponse = null;
        try {
            webappResponse = IOUtils
                    .toString(new URL("http://localhost:" + webappPort + "/" + appName + "/SimpleServlet")
                            .openConnection().getInputStream());
        } catch (MalformedURLException e) {
            e.printStackTrace();
            fail(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            fail(e.getMessage());
        }

        assertNotNull(webappResponse);
        assertEquals("Webapp response was incorrect", "Hi", webappResponse.trim());
    }

    public void pingCoberturaServer() {
        //flush the cobertura data by doing an HTTP get
        String flushing = null;
        try {
            flushing = IOUtils
                    .toString(new java.net.URL("http://localhost:" + webappPort + "/coberturaFlush/flushCobertura")
                            .openConnection().getInputStream());
        } catch (MalformedURLException e) {
            e.printStackTrace();
            fail(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            fail(e.getMessage());
        }

        assertNotNull(flushing);
        assertEquals("", flushing.trim());

    }

    public File getXmlReport() {
        return new File(dir.getAbsolutePath(), "coverage.xml");
    }
}