Package net.sourceforge.cruisecontrol.builders

Source Code of net.sourceforge.cruisecontrol.builders.DistributedMasterBuilderTest$PrefixedPrintWriter

package net.sourceforge.cruisecontrol.builders;

import junit.framework.TestCase;

import java.util.Properties;
import java.util.Arrays;
import java.util.List;
import java.io.File;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.EOFException;
import java.net.URL;
import java.net.InetAddress;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.MalformedURLException;

import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.Project;
import org.apache.log4j.Logger;
import org.jdom.Element;
import net.sourceforge.cruisecontrol.util.Commandline;
import net.sourceforge.cruisecontrol.util.Util;
import net.sourceforge.cruisecontrol.util.StreamPumper;
import net.sourceforge.cruisecontrol.util.OSEnvironment;
import net.sourceforge.cruisecontrol.distributed.BuildAgent;
import net.sourceforge.cruisecontrol.distributed.BuildAgentService;
import net.sourceforge.cruisecontrol.distributed.BuildAgentServiceImplTest;
import net.sourceforge.cruisecontrol.distributed.SearchablePropertyEntries;
import net.sourceforge.cruisecontrol.distributed.util.ReggieUtil;
import net.sourceforge.cruisecontrol.distributed.util.MulticastDiscovery;
import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.Builder;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.discovery.LookupLocator;
import net.jini.core.entry.Entry;
import net.jini.discovery.LookupDiscovery;

/**
* Created by IntelliJ IDEA. User: drollo Date: May 6, 2005 Time: 2:34:24 PM To change this template
* use File | Settings | File Templates.
*/
public class DistributedMasterBuilderTest extends TestCase {

    private static final Logger LOG = Logger.getLogger(DistributedMasterBuilderTest.class);

    public static final String INSECURE_POLICY_FILENAME = "insecure.policy";
    private static Properties origSysProps;
    public static final String JINI_URL_LOCALHOST = "jini://localhost";

    public static final OSEnvironment OS_ENV = new OSEnvironment();

    /** Common element names. */
    public static final String ELM_NAME_CC = "cruisecontrol";
    public static final String ELM_NAME_PROJECT = "project";
    public static final String ELM_NAME_SCHEDULE = "schedule";
    public static final String ELM_NAME_DIST = "distributed";
    public static final String ELM_NAME_AND = "ant";
    /** Common attribute names. */
    public static final String ATR_NAME_NAME = "name";
    public static final String ATR_NAME_MODULE = "module";
    public static final String ATR_NAME_DAY = "day";
    public static final String ATR_NAME_TIME = "time";
    public static final String ATR_NAME_MULTIPLE = "multiple";

    /** Expose package visible helper method for other Unit Test classes to use. */
    public static void addMissingPluginDefaults(final Element elementToFilter) {
        DistributedMasterBuilder.addMissingPluginDefaults(elementToFilter);
    }
    /**
     * Show what's happening with the jiniProcess
     */
    private static final class PrefixedPrintWriter extends PrintWriter {
        private final String writerPrefix;

        PrefixedPrintWriter(final String prefix) {
            super(System.out);
            writerPrefix = prefix;
        }

        public void write(String s) {
            //if (LOG.isEnabledFor(Priority.DEBUG)) { // gives odd newlines in console
            super.write(writerPrefix + s);
            //}
        }
    }


    /** @return the Process in which Jini Lookup _service is running, for use in killing it. */
    public static Process startJini() throws Exception {
        // make sure local lookup service is not already running
        verifyNoLocalLookupService();

        origSysProps = System.getProperties();

//        <java jar="lib/start.jar" fork="true" >
//            <jvmarg value="-Djava.security.policy=conf/${jini.policy.file}" />
//            <jvmarg value="-Djini.lib=lib" />
//            <jvmarg value="-Djini.httpPort=${jini.port}" />
//            <jvmarg value="-Djini.codebaseURI=file://lib/cc-agent-dl.jar
//                 file://lib/reggie-dl.jar
//                 file://lib/fiddler-dl.jar
//                 file://lib/mahalo-dl.jar
//                 file://lib/mercury-dl.jar
//                 file://lib/norm-dl.jar
//                 file://lib/outrigger-dl.jar
//                 file://lib/phoenix-dl.jar
//                 file://lib/holowaa-dl.jar" />
//            <jvmarg value="-Djini.classpath=.;lib/cc-agent.jar;lib/reggie.jar;lib/fiddler.jar;lib/mahalo.jar;
//                          lib/mercury.jar;lib/norm.jar;lib/outrigger.jar;lib/phoenix.jar;lib/holowaa.jar" />
//            <arg value="conf/${jini.config}"/>
//            <classpath>
//                <pathelement path="conf"/>
//                <fileset dir="lib">
//                    <include name="**/*.jar" />
//                </fileset>
//            </classpath>
//        </java>

        final String[] args = new String[] {
             "-Djava.security.policy=conf/insecure.policy", //${jini.policy.file}
             "-Djini.lib=lib",
             "-Djini.httpPort=8050",    //${jini.port}"
             "-Djini.codebaseURI=file://lib/cc-agent-dl.jar "
                     + "file://lib/reggie-dl.jar "
                     + "file://lib/fiddler-dl.jar "
                     + "file://lib/mahalo-dl.jar "
                     + "file://lib/mercury-dl.jar "
                     + "file://lib/norm-dl.jar "
                     + "file://lib/outrigger-dl.jar "
                     + "file://lib/phoenix-dl.jar "
                     + "file://lib/holowaa-dl.jar",
             "-Djini.classpath=.;lib/cc-agent.jar;lib/reggie.jar;lib/fiddler.jar;lib/mahalo.jar;"
                     + "lib/mercury.jar;lib/norm.jar;lib/outrigger.jar;lib/phoenix.jar;lib/holowaa.jar"
        };

        // @todo There must be a nicer way to do this...
        // @todo Assumes current dir is same as build.xml.
        final String libDir = "lib/";
        FileSet set = new FileSet();
        set.setDir(new File(libDir));
        set.setIncludes("**/*.jar");
        Project project = new Project();
        set.setProject(project);
        String libjars = set.toString();
        libjars = libjars.replaceAll("jar" + File.pathSeparator, "jar" + File.pathSeparator + libDir);
        libjars = libDir + libjars;

        final Commandline cmdLine = new Commandline();
        cmdLine.addArguments(args);
        Commandline.Argument argClasspath = cmdLine.createArgument();
        argClasspath.setLine("-classpath " + "conf" + File.pathSeparator + libjars);

        Commandline.Argument argStart = cmdLine.createArgument();
        argStart.setLine("-jar lib/start.jar");

        Commandline.Argument argProg = cmdLine.createArgument();
        argProg.setValue("conf/start-jini.config"); // ${jini.config}

        cmdLine.setExecutable(getJavaExec());

        LOG.debug("jini startup command: " + Arrays.asList(cmdLine.getCommandline()));
        final Process newJiniProcess = Runtime.getRuntime().exec(cmdLine.getCommandline());

        // show what's happening with the jiniProcess
        new Thread(new StreamPumper(newJiniProcess.getErrorStream(),
                new PrefixedPrintWriter("[JiniErr] "))).start();
        new Thread(new StreamPumper(newJiniProcess.getInputStream(),
                new PrefixedPrintWriter("[JiniOut] "))).start();

        // setup security policy
        URL policyFile = ClassLoader.getSystemClassLoader().getResource(INSECURE_POLICY_FILENAME);
        assertNotNull("Can't load policy file resource: " + INSECURE_POLICY_FILENAME
                + ". Make sure this file is in the classes (bin) directory.",
            policyFile);
        System.setProperty(BuildAgent.JAVA_SECURITY_POLICY, policyFile.toExternalForm());
        ReggieUtil.setupRMISecurityManager();

        ServiceRegistrar serviceRegistrar = findTestLookupService(20);
        assertNotNull("Failed to start local lookup _service.", serviceRegistrar);
        assertEquals("Unexpected local lookup _service host",
            InetAddress.getLocalHost().getCanonicalHostName(),
            serviceRegistrar.getLocator().getHost());

        Thread.sleep(1000); // kludged attempt to avoid occaisional test failures
        return newJiniProcess;
    }

    public static String getJavaExec() {
        final String javaExecFilename;
        if (Util.isWindows()) {
            javaExecFilename = "java.exe";
        } else {
            javaExecFilename = "java";
        }
        // use JAVA_HOME env var to find java
        final String javaHome = getJAVA_HOME();
        final String javaExec;
        if (javaHome != null) {
            javaExec = javaHome + File.separator + "bin" + File.separator + javaExecFilename;
        } else {
            String msg = "Unit Test couldn't find JAVA_HOME env var. Maybe java/bin is in the path? Here goes...";
            System.out.println(msg);
            LOG.warn(msg);
            javaExec = javaExecFilename;
        }
        return javaExec;
    }

    public static String getJAVA_HOME() {
        return OS_ENV.getVariable("JAVA_HOME");
    }

    public static ServiceRegistrar findTestLookupService(int retryTimeoutSecs)
            throws IOException, ClassNotFoundException, InterruptedException {

        // find/wait for lookup _service
        final long startTime = System.currentTimeMillis();
        ServiceRegistrar serviceRegistrar = null;
        final LookupLocator lookup = new LookupLocator(JINI_URL_LOCALHOST);
        while (serviceRegistrar == null
                && (System.currentTimeMillis() - startTime < (retryTimeoutSecs * 1000))) {

            try {
                serviceRegistrar = lookup.getRegistrar();
            } catch (ConnectException e) {
                Thread.sleep(500);
            } catch (SocketException e) {
                Thread.sleep(500);
            } catch (EOFException e) {
                Thread.sleep(500);
            }
            // more exceptions will likely need to added here as the Jini libraries are updated.
            // could catch a generic super class, but I kinda like to know what's being thrown.
        }
        return serviceRegistrar;
    }

    public static void killJini(final Process jiniProcess) throws Exception {
        if (jiniProcess != null) {
            jiniProcess.destroy();

            jiniProcess.getInputStream().close();
            jiniProcess.getOutputStream().close();
            jiniProcess.getErrorStream().close();

            LOG.debug("Jini process killed.");

            // make sure local Lookup Service is dead
            // @todo why do we need to retry this on Linux?
            if (findTestLookupService(1) != null) {
                final int secs = 5;
                LOG.debug("Waiting " + secs + " seconds for Lookup Service to die...need to fix this.");
                Thread.sleep(secs * 1000);
            }
            verifyNoLocalLookupService();
            Thread.sleep(1000); // kludged attempt to avoid occaisional test failures
        }

        // restore original system properties
        System.setProperties(origSysProps);
    }

    private static void verifyNoLocalLookupService() throws IOException, ClassNotFoundException, InterruptedException {
        ServiceRegistrar serviceRegistrar = findTestLookupService(1);
        assertNull("Found local lookup service, but it should be dead. Is an orphaned java process still running?",
                serviceRegistrar);
    }


    private Process jiniProcess;



    private static Element getDistElement(final String projectName, final int projectIndex)
            throws CruiseControlException {

        final Element rootElement = Util.loadConfigFile(BuildAgentServiceImplTest.TEST_CONFIG_FILE);

        final List projects = rootElement.getChildren(ELM_NAME_PROJECT);
        final Element project = (Element) projects.get(projectIndex);
        assertEquals(ELM_NAME_PROJECT, project.getName());
        assertEquals(projectName, project.getAttributeValue(ATR_NAME_NAME));

        final Element schedule = (Element) project.getChildren(ELM_NAME_SCHEDULE).get(0);
        assertEquals(ELM_NAME_SCHEDULE, schedule.getName());

        final Element dist = (Element) schedule.getChildren().get(0);
        assertEquals(ELM_NAME_DIST, dist.getName());
        return dist;
    }

    private static Element getAntElement(final Element dist) {
        final Element ant = (Element) dist.getChildren().get(0);
        assertEquals(ELM_NAME_AND, ant.getName());
        return ant;
    }



    protected void setUp() throws Exception {
        jiniProcess = DistributedMasterBuilderTest.startJini();
    }

    protected void tearDown() throws Exception {
        DistributedMasterBuilderTest.killJini(jiniProcess);
    }



    public void testDistAttribs() throws Exception {

        final Element dist = getDistElement("testproject2", 1);
        assertEquals("testmodule-attribs", dist.getAttributeValue(ATR_NAME_MODULE));

        final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder();
        masterBuilder.configure(dist);
        assertEquals("agent/log", masterBuilder.getAgentLogDir());
        assertEquals("master/log", masterBuilder.getMasterLogDir());
        // check PreconfiguredPlugin attib on distributed tag
        final String preConfMsg = "Are PreConfgured Plugin settings still broken for distributed builds?"
                + "\nSee " + BuildAgentServiceImplTest.TEST_CONFIG_FILE + " for more info.";
        assertEquals(preConfMsg, "build.type=test", dist.getAttributeValue("entries"));

        // check attribs on nested builder
        final Element childBuilder = masterBuilder.getChildBuilderElement();
        assertEquals("testtargetSuccess", childBuilder.getAttributeValue("target"));
        // check PreconfiguredPlugin attribs on nested builder
        assertEquals(preConfMsg, "${env.ANT_HOME}", childBuilder.getAttributeValue("anthome"));
        assertEquals(preConfMsg, "test/testdist.build.xml", childBuilder.getAttributeValue("buildfile"));
        assertEquals(preConfMsg, "true", childBuilder.getAttributeValue("uselogger"));
    }

    public void testScheduleDay() throws Exception {

        final Element dist = getDistElement("testprojectNoModule", 2);
        final Element ant = getAntElement(dist);
        assertEquals("This unit test requires there be a '" + ATR_NAME_DAY + "' attribute",
                "7", ant.getAttributeValue(ATR_NAME_DAY));

        final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder();
        masterBuilder.configure(dist);

        assertEquals("Distributed builder should wrap child-builder schedule fields",
                7, masterBuilder.getDay());
        assertEquals("Distributed builder should wrap child-builder schedule fields",
                Builder.NOT_SET, masterBuilder.getTime());
        // @todo Is this logic correct, or should value be NOT_SET?
        assertEquals("Distributed builder should wrap child-builder schedule fields",
                1, masterBuilder.getMultiple());
    }

    public void testScheduleTime() throws Exception {

        final Element dist = getDistElement("testprojectTime", 3);
        final Element ant = getAntElement(dist);
        assertEquals("This unit test requires there be a '" + ATR_NAME_TIME + "' attribute",
                "0530", ant.getAttributeValue(ATR_NAME_TIME));

        final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder();
        masterBuilder.configure(dist);

        assertEquals("Distributed builder should wrap child-builder schedule fields",
                530, masterBuilder.getTime());
        assertEquals("Distributed builder should wrap child-builder schedule fields",
                Builder.NOT_SET, masterBuilder.getDay());
        assertEquals("Distributed builder should wrap child-builder schedule fields",
                Builder.NOT_SET, masterBuilder.getMultiple());
    }

    public void testScheduleMultiple() throws Exception {

        final Element dist = getDistElement("testprojectMultiple", 4);
        final Element ant = getAntElement(dist);
        assertEquals("This unit test requires there be a '" + ATR_NAME_MULTIPLE + "' attribute",
                "2", ant.getAttributeValue(ATR_NAME_MULTIPLE));

        final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder();
        masterBuilder.configure(dist);

        assertEquals("Distributed builder should wrap child-builder schedule fields",
                2, masterBuilder.getMultiple());
        assertEquals("Distributed builder should wrap child-builder schedule fields",
                Builder.NOT_SET, masterBuilder.getTime());
        assertEquals("Distributed builder should wrap child-builder schedule fields",
                Builder.NOT_SET, masterBuilder.getDay());
    }

    public void testDefaultModuleValue() throws Exception {

        final Element dist = getDistElement("testprojectNoModule", 2);
        assertNull("This unit test requires there be no '" + ATR_NAME_MODULE + "' attribute",
                dist.getAttributeValue(ATR_NAME_MODULE));

        final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder();
        masterBuilder.configure(dist)// this would fail if default "module" value didn't work

        assertEquals("agent/log", masterBuilder.getAgentLogDir());
        assertEquals("master/log", masterBuilder.getMasterLogDir());
        // check PreconfiguredPlugin attib on distributed tag
        final String preConfMsg = "Are PreConfgured Plugin settings still broken for distributed builds?"
                + "\nSee " + BuildAgentServiceImplTest.TEST_CONFIG_FILE + " for more info.";
        assertEquals(preConfMsg, "build.type=test", dist.getAttributeValue("entries"));
    }

    public void testPickAgent2Agents() throws Exception {
        // register agent
        final BuildAgent agentAvailable = new BuildAgent(
                BuildAgentServiceImplTest.TEST_AGENT_PROPERTIES_FILE,
                BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE, true);
        final BuildAgent agentAvailable2 = new BuildAgent(
                BuildAgentServiceImplTest.TEST_AGENT_PROPERTIES_FILE,
                BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE, true);
        try {
            assertFalse(agentAvailable.getService().isBusy());
            assertFalse(agentAvailable2.getService().isBusy());

            DistributedMasterBuilder masterBuilder = createMasterBuilder();

            // try to find agents
            final BuildAgentService agentFoundFirst = masterBuilder.pickAgent();
            assertNotNull("Couldn't find first agent", agentFoundFirst);
            assertTrue(agentFoundFirst.isBusy());
            final BuildAgentService agentFoundSecond = masterBuilder.pickAgent();
            assertNotNull("Couldn't find second agent", agentFoundSecond);

            assertTrue(agentFoundFirst.isBusy());
            assertTrue(agentFoundSecond.isBusy());
            final BuildAgentService agentFoundThird = masterBuilder.pickAgent();
            assertNull("Shouldn't find third agent", agentFoundThird);

            // set Agent to Not busy, then make sure it can be found again.
            // callTestDoBuild() only needed to clearOuputFiles() will succeed
            BuildAgentServiceImplTest.callTestDoBuild(false, agentAvailable.getService());
            agentAvailable.getService().clearOutputFiles();
            final BuildAgentService agentRefound = masterBuilder.pickAgent();
            assertNotNull("Couldn't find released agent", agentRefound);
            assertTrue("Claimed agent should show as busy. (Did we find a better way?)",
                    agentRefound.isBusy());

        } finally {
            // terminate JoinManager in BuildAgent
            agentAvailable.terminate();
            agentAvailable2.terminate();
        }
    }

    public void testPickAgentAfterReleased() throws Exception {
        // register agent
        final BuildAgent agentAvailable = new BuildAgent(
                BuildAgentServiceImplTest.TEST_AGENT_PROPERTIES_FILE,
                BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE, true);
        try {
            assertFalse(agentAvailable.getService().isBusy());
            agentAvailable.getService().claim(); // mark as busy

            DistributedMasterBuilder masterBuilder = createMasterBuilder();

            // try to find agent, shouldn't find any available
            final BuildAgentService agentBusy = masterBuilder.pickAgent();
            assertNull("Shouldn't find any available agents", agentBusy);

            // set Agent to Not busy, then make sure it can be found again.
            // callTestDoBuild() only needed to clearOuputFiles() will succeed
            BuildAgentServiceImplTest.callTestDoBuild(false, agentAvailable.getService());
            agentAvailable.getService().clearOutputFiles();
            final BuildAgentService agentRefound = masterBuilder.pickAgent();
            assertNotNull("Couldn't find released agent", agentRefound);
            assertTrue("Claimed agent should show as busy. (Did we find a better way?)",
                    agentRefound.isBusy());

        } finally {
            // terminate JoinManager in BuildAgent
            agentAvailable.terminate();
        }
    }

    public void testPickAgentAgentNotBusy() throws Exception {
        // register agent
        final BuildAgent agentAvailable = new BuildAgent(
                BuildAgentServiceImplTest.TEST_AGENT_PROPERTIES_FILE,
                BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE, true);
        try {
            assertFalse(agentAvailable.getService().isBusy());

            DistributedMasterBuilder masterBuilder = createMasterBuilder();

            final BuildAgentService agent = masterBuilder.pickAgent();
            assertNotNull("Couldn't find agent", agent);
            assertTrue("Claimed agent should show as busy. (Did we find a better way?)",
                    agent.isBusy());

            // try to find agent, shouldn't find any available
            final BuildAgentService agentBusy = masterBuilder.pickAgent();
            assertNull("Shouldn't find any available agents", agentBusy);

            // set Agent to Not busy, then make sure it can be found again.
            BuildAgentServiceImplTest.callTestDoBuild(false, agent); // only needed to clearOuputFiles() will succeed
            agent.clearOutputFiles();
            final BuildAgentService agentRefound = masterBuilder.pickAgent();
            assertNotNull("Couldn't find released agent", agentRefound);
            assertTrue("Claimed agent should show as busy. (Did we find a better way?)",
                    agentRefound.isBusy());
        } finally {
            // terminate JoinManager in BuildAgent
            agentAvailable.terminate();
        }
    }

    private static DistributedMasterBuilder createMasterBuilder() throws MalformedURLException, InterruptedException {
        DistributedMasterBuilder masterBuilder = getMasterBuilder_LocalhostAndTestPropsONLY(
                BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE
        );

        // wait for cache to discover agent
        int i = 0;
        int waitSecs = 15;
        while (!masterBuilder.getDiscovery().isDiscovered() && i < waitSecs) {
            Thread.sleep(1000);
            i++;
        }
        assertTrue("MasterBuilder was not discovered before timeout.\n"
                + "1. Make sure MULTICAST is enabled on your network devices (ifconfig -a).\n"
                + "2. No Firewall is blocking multicasts.\n",
                masterBuilder.getDiscovery().isDiscovered());
        return masterBuilder;
    }

    public void testPickAgentNoAgents() throws Exception {

        DistributedMasterBuilder masterBuilder = getMasterBuilder_LocalhostAndTestPropsONLY(
                BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE
        );

        BuildAgentService agent = masterBuilder.pickAgent();
        assertNull(agent);
    }

    public void testPickAgentNoRegistrars() throws Exception {
        // kill local reggie
        DistributedMasterBuilderTest.killJini(jiniProcess);

        DistributedMasterBuilder masterBuilder = getMasterBuilder_LocalhostAndTestPropsONLY(
                BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE
        );

        BuildAgentService agent = masterBuilder.pickAgent();
        assertNull(agent);
    }

    private static DistributedMasterBuilder getMasterBuilder_LocalhostAndTestPropsONLY(
            final String testUserPropsFilename)
            throws MalformedURLException {

        DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder();

        final LookupLocator[] unicastLocators = new LookupLocator[] {
                new LookupLocator(DistributedMasterBuilderTest.JINI_URL_LOCALHOST)
        };

        final Entry[] entries = SearchablePropertyEntries.getPropertiesAsEntryArray(
                new SearchablePropertyEntries(testUserPropsFilename).getProperties()
        );

        final MulticastDiscovery discovery = new MulticastDiscovery(
                LookupDiscovery.ALL_GROUPS, unicastLocators, BuildAgentService.class, entries
        );
        masterBuilder.setDiscovery(discovery);
        masterBuilder.setFailFast(true); // don't block until an available agent is found
        return masterBuilder;
    }

}
TOP

Related Classes of net.sourceforge.cruisecontrol.builders.DistributedMasterBuilderTest$PrefixedPrintWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.