org.apache.stratos.cartridge.agent.test.JavaCartridgeAgentTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.stratos.cartridge.agent.test.JavaCartridgeAgentTest.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.stratos.cartridge.agent.test;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.progress.ProgressMonitor;
import org.apache.commons.exec.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.stratos.common.domain.LoadBalancingIPType;
import org.apache.stratos.common.threading.StratosThreadPool;
import org.apache.stratos.messaging.broker.publish.EventPublisher;
import org.apache.stratos.messaging.broker.publish.EventPublisherPool;
import org.apache.stratos.messaging.domain.topology.*;
import org.apache.stratos.messaging.event.Event;
import org.apache.stratos.messaging.event.instance.notifier.ArtifactUpdatedEvent;
import org.apache.stratos.messaging.event.topology.CompleteTopologyEvent;
import org.apache.stratos.messaging.event.topology.MemberInitializedEvent;
import org.apache.stratos.messaging.listener.instance.status.InstanceActivatedEventListener;
import org.apache.stratos.messaging.listener.instance.status.InstanceStartedEventListener;
import org.apache.stratos.messaging.message.receiver.instance.status.InstanceStatusEventReceiver;
import org.apache.stratos.messaging.message.receiver.topology.TopologyEventReceiver;
import org.apache.stratos.messaging.util.MessagingUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.*;
import java.util.concurrent.ExecutorService;

import static junit.framework.Assert.assertTrue;

/**
 * An integration test that verifies the functionality of the Java cartridge agent
 */
@RunWith(Parameterized.class)
public class JavaCartridgeAgentTest {

    private static final Log log = LogFactory.getLog(JavaCartridgeAgentTest.class);
    private static final long TIMEOUT = 200000;

    private static final String NEW_LINE = System.getProperty("line.separator");
    private static final String CLUSTER_ID = "php.php.domain";
    private static final String DEPLOYMENT_POLICY_NAME = "deployment-policy-1";
    private static final String AUTOSCALING_POLICY_NAME = "autoscaling-policy-1";
    private static final String APP_ID = "application-1";
    private static final String MEMBER_ID = "php.member-1";
    private static final String INSTANCE_ID = "instance-1";
    private static final String CLUSTER_INSTANCE_ID = "cluster-1-instance-1";
    private static final String NETWORK_PARTITION_ID = "network-partition-1";
    private static final String PARTITION_ID = "partition-1";
    private static final String TENANT_ID = "-1234";
    private static final String SERVICE_NAME = "php";
    public static final String AGENT_NAME = "apache-stratos-cartridge-agent-4.2.0-SNAPSHOT";
    private static HashMap<String, Executor> executorList;
    private static ArrayList<ServerSocket> serverSocketList;
    private final ArtifactUpdatedEvent artifactUpdatedEvent;
    private final Boolean expectedResult;
    private boolean instanceStarted;
    private boolean instanceActivated;
    private ByteArrayOutputStreamLocal outputStream;
    private TopologyEventReceiver topologyEventReceiver;
    private InstanceStatusEventReceiver instanceStatusEventReceiver;

    public JavaCartridgeAgentTest(ArtifactUpdatedEvent artifactUpdatedEvent, Boolean expectedResult) {
        this.artifactUpdatedEvent = artifactUpdatedEvent;
        this.expectedResult = expectedResult;
    }

    @BeforeClass
    public static void oneTimeSetUp() {
        System.setProperty("jndi.properties.dir", getResourcesFolderPath());
    }

    @Before
    public void setup() {
        serverSocketList = new ArrayList<ServerSocket>();
        executorList = new HashMap<String, Executor>();

        String agentHome = setupJavaAgent();

        ExecutorService executorService = StratosThreadPool.getExecutorService("TEST_THREAD_POOL", 5);
        topologyEventReceiver = TopologyEventReceiver.getInstance();
        //topologyEventReceiver.setExecutorService(executorService);
        //topologyEventReceiver.execute();

        instanceStatusEventReceiver = InstanceStatusEventReceiver.getInstance();
        //        instanceStatusEventReceiver.setExecutorService(executorService);
        //        instanceStatusEventReceiver.execute();

        instanceStarted = false;
        instanceStatusEventReceiver.addEventListener(new InstanceStartedEventListener() {
            @Override
            protected void onEvent(Event event) {
                log.info("Instance started event received");
                instanceStarted = true;
            }
        });

        instanceActivated = false;
        instanceStatusEventReceiver.addEventListener(new InstanceActivatedEventListener() {
            @Override
            protected void onEvent(Event event) {
                log.info("Instance activated event received");
                instanceActivated = true;
            }
        });

        startServerSocket(7711);

        log.info("Starting Java cartridge agent...");
        String binPath = agentHome + "/bin";
        outputStream = executeCommand("bash stratos.sh", new File(binPath));

    }

    @After
    public void tearDown() {
        for (Map.Entry<String, Executor> entry : executorList.entrySet()) {
            try {
                String commandText = entry.getKey();
                Executor executor = entry.getValue();
                ExecuteWatchdog watchdog = executor.getWatchdog();
                if (watchdog != null) {
                    log.info("Terminating process: " + commandText);
                    watchdog.destroyProcess();
                }
                //                File workingDirectory = executor.getWorkingDirectory();
                //                if (workingDirectory != null) {
                //                    log.info("Cleaning working directory: " + workingDirectory.getAbsolutePath());
                //                    FileUtils.deleteDirectory(workingDirectory);
                //                }
            } catch (Exception ignore) {
            }
        }
        for (ServerSocket serverSocket : serverSocketList) {
            try {
                log.info("Stopping socket server: " + serverSocket.getLocalSocketAddress());
                serverSocket.close();
            } catch (IOException e) {
                log.info("Couldn't stop socket server " + serverSocket.getLocalSocketAddress() + ", "
                        + e.getMessage());
            }
        }

        try {
            log.info("Deleting source checkout folder...");
            FileUtils.deleteDirectory(new File("/tmp/test-jca-source"));
        } catch (Exception ignore) {
        }

        //this.instanceStatusEventReceiver.terminate();
        //  this.topologyEventReceiver.terminate();

        this.instanceActivated = false;
        this.instanceStarted = false;
    }

    /**
     * This method returns a collection of {@link org.apache.stratos.messaging.event.instance.notifier.ArtifactUpdatedEvent}
     * objects as parameters to the test
     *
     * @return
     */
    @Parameterized.Parameters
    public static Collection getArtifactUpdatedEventsAsParams() {
        ArtifactUpdatedEvent publicRepoEvent = createTestArtifactUpdatedEvent();

        ArtifactUpdatedEvent privateRepoEvent = createTestArtifactUpdatedEvent();
        privateRepoEvent.setRepoURL("https://bitbucket.org/testapache2211/testrepo.git");
        privateRepoEvent.setRepoUserName("testapache2211");
        privateRepoEvent.setRepoPassword("RExPDGa4GkPJj4kJDzSROQ==");

        ArtifactUpdatedEvent privateRepoEvent2 = createTestArtifactUpdatedEvent();
        privateRepoEvent2.setRepoURL("https://testapache2211@bitbucket.org/testapache2211/testrepo.git");
        privateRepoEvent2.setRepoUserName("testapache2211");
        privateRepoEvent2.setRepoPassword("RExPDGa4GkPJj4kJDzSROQ==");

        return Arrays.asList(new Object[][] { { publicRepoEvent, true }, { privateRepoEvent, true },
                { privateRepoEvent2, true } });

    }

    /**
     * Creates an {@link org.apache.stratos.messaging.event.instance.notifier.ArtifactUpdatedEvent} object with a public
     * repository URL
     *
     * @return
     */
    private static ArtifactUpdatedEvent createTestArtifactUpdatedEvent() {
        ArtifactUpdatedEvent publicRepoEvent = new ArtifactUpdatedEvent();
        publicRepoEvent.setClusterId(CLUSTER_ID);
        publicRepoEvent.setTenantId(TENANT_ID);
        publicRepoEvent.setRepoURL("https://bitbucket.org/testapache2211/opentestrepo1.git");
        return publicRepoEvent;
    }

    /**
     * Setup the JCA test path, copy test configurations
     *
     * @return
     */
    private String setupJavaAgent() {
        try {
            log.info("Setting up Java cartridge agent test setup");
            String jcaZipSource = getResourcesFolderPath()
                    + "/../../../../products/cartridge-agent/modules/distribution/target/" + AGENT_NAME + ".zip";
            String testHome = getResourcesFolderPath() + "/../" + UUID.randomUUID() + "/";
            File agentHome = new File(testHome + AGENT_NAME);
            log.info("Extracting Java Cartridge Agent to test folder");
            ZipFile agentZip = new ZipFile(jcaZipSource);
            ProgressMonitor zipProgresMonitor = agentZip.getProgressMonitor();
            agentZip.extractAll(testHome);
            while (zipProgresMonitor.getPercentDone() < 100) {
                log.info("Extracting: " + zipProgresMonitor.getPercentDone());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            log.info("Copying agent jar");
            String agentJar = "org.apache.stratos.cartridge.agent-4.2.0-SNAPSHOT.jar";
            String agentJarSource = getResourcesFolderPath() + "/../" + agentJar;
            String agentJarDest = agentHome.getCanonicalPath() + "/lib/" + agentJar;
            FileUtils.copyFile(new File(agentJarSource), new File(agentJarDest));

            log.info("Copying test payload file");
            String srcPayloadPath = getResourcesFolderPath() + "/../../src/test/resources/payload";
            String destPayloadPath = agentHome + "/payload";
            FileUtils.copyDirectory(new File(srcPayloadPath), new File(destPayloadPath));

            log.info("Copying test conf files");
            String srcConf = getResourcesFolderPath() + "/../../src/test/resources/conf";
            String destConf = agentHome + "/conf";
            FileUtils.copyDirectory(new File(srcConf), new File(destConf));

            log.info("Copying test stratos.sh script");
            String srcBin = getResourcesFolderPath() + "/../../src/test/resources/bin";
            String destBin = agentHome + "/bin";
            FileUtils.copyDirectory(new File(srcBin), new File(destBin));

            log.info("Changing stratos.sh permissions");
            new File(agentHome.getCanonicalPath() + "/bin/stratos.sh").setExecutable(true);
            log.info("Changed permissions for stratos.sh");

            log.info("Changing extension scripts permissions");
            File extensionsPath = new File(agentHome.getCanonicalPath() + "/extensions/");
            File[] extensions = extensionsPath.listFiles();
            for (File extension : extensions) {
                extension.setExecutable(true);
            }
            log.info("Changed permissions for extensions : " + outputStream);

            log.info("Java cartridge agent setup complete.");

            return agentHome.getCanonicalPath();
        } catch (IOException e) {
            String message = "Could not copy cartridge agent distribution";
            log.error(message, e);
            throw new RuntimeException(message, e);
        } catch (ZipException e) {
            String message = "Could not unzip cartridge agent distribution. Please make sure to build <STRATOS_HOME>/products/cartridge-agent first.";
            log.error(message, e);
            throw new RuntimeException(message, e);
        }
    }

    /**
     * Get current folder path
     *
     * @return
     */
    private static String getResourcesFolderPath() {
        return StringUtils.removeEnd(JavaCartridgeAgentTest.class.getResource("/").getPath(), File.separator);
    }

    @Test(timeout = TIMEOUT)
    public void testJavaCartridgeAgent() throws Exception {
        Thread communicatorThread = new Thread(new Runnable() {
            @Override
            public void run() {
                List<String> outputLines = new ArrayList<String>();
                while (!outputStream.isClosed()) {
                    List<String> newLines = getNewLines(outputLines, outputStream.toString());
                    if (newLines.size() > 0) {
                        for (String line : newLines) {
                            if (line.contains(
                                    "Cartridge agent topology receiver thread started, waiting for event messages")) {
                                sleep(2000);
                                // Send complete topology event
                                log.info("Publishing complete topology event...");
                                Topology topology = createTestTopology();
                                CompleteTopologyEvent completeTopologyEvent = new CompleteTopologyEvent(topology);
                                publishEvent(completeTopologyEvent);
                                log.info("Complete topology event published");

                                sleep(5000);
                                // Publish member initialized event
                                log.info("Publishing member initialized event...");
                                MemberInitializedEvent memberInitializedEvent = new MemberInitializedEvent(
                                        SERVICE_NAME, CLUSTER_ID, CLUSTER_INSTANCE_ID, MEMBER_ID,
                                        NETWORK_PARTITION_ID, PARTITION_ID, INSTANCE_ID);
                                publishEvent(memberInitializedEvent);
                                log.info("Member initialized event published");

                                // Simulate server socket
                                startServerSocket(9080);
                            }
                            if (line.contains("Artifact repository found")) {
                                // Send artifact updated event
                                publishEvent(artifactUpdatedEvent);
                            }
                            if (line.contains("Exception in thread") || line.contains("ERROR")) {
                                //throw new RuntimeException(line);
                            }
                            log.info(line);
                        }
                    }

                    if (instanceActivated) {
                        break;
                    }
                    sleep(500);
                }
            }
        });

        communicatorThread.start();

        while (!instanceActivated) {
            sleep(2000);
        }

        assertTrue("Instance started event was not received", instanceStarted);
        assertTrue("Instance activated event was not received", instanceActivated == expectedResult);
    }

    /**
     * Publish messaging event
     *
     * @param event
     */
    private void publishEvent(Event event) {
        String topicName = MessagingUtil.getMessageTopicName(event);
        EventPublisher eventPublisher = EventPublisherPool.getPublisher(topicName);
        eventPublisher.publish(event);
    }

    /**
     * Start server socket
     *
     * @param port
     */
    private void startServerSocket(final int port) {
        Thread socketThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    ServerSocket serverSocket = new ServerSocket(port);
                    serverSocketList.add(serverSocket);
                    serverSocket.accept();
                } catch (IOException e) {
                    String message = "Could not start server socket: [port] " + port;
                    log.error(message, e);
                    //                    throw new RuntimeException(message, e);
                }
            }
        });
        socketThread.start();
    }

    /**
     * Execute shell command
     *
     * @param commandText
     */
    private ByteArrayOutputStreamLocal executeCommand(final String commandText, File workingDir) {
        final ByteArrayOutputStreamLocal outputStream = new ByteArrayOutputStreamLocal();
        try {
            CommandLine commandline = CommandLine.parse(commandText);
            DefaultExecutor exec = new DefaultExecutor();
            if (workingDir != null) {
                exec.setWorkingDirectory(workingDir);
            }
            PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
            exec.setStreamHandler(streamHandler);
            ExecuteWatchdog watchdog = new ExecuteWatchdog(TIMEOUT);
            exec.setWatchdog(watchdog);
            log.info("Executing command: " + commandText
                    + (workingDir == null ? "" : " at " + workingDir.getCanonicalPath()));
            exec.execute(commandline, new ExecuteResultHandler() {
                @Override
                public void onProcessComplete(int i) {
                    log.info(commandText + " process completed");
                }

                @Override
                public void onProcessFailed(ExecuteException e) {
                    log.error(commandText + " process failed", e);
                }
            });
            executorList.put(commandText, exec);
            return outputStream;
        } catch (Exception e) {
            log.error(outputStream.toString(), e);
            throw new RuntimeException(e);
        }
    }

    /**
     * Create test topology
     *
     * @return
     */
    private Topology createTestTopology() {
        Topology topology = new Topology();
        Service service = new Service(SERVICE_NAME, ServiceType.SingleTenant);
        topology.addService(service);

        Cluster cluster = new Cluster(service.getServiceName(), CLUSTER_ID, DEPLOYMENT_POLICY_NAME,
                AUTOSCALING_POLICY_NAME, APP_ID);
        service.addCluster(cluster);

        Member member = new Member(service.getServiceName(), cluster.getClusterId(), MEMBER_ID, CLUSTER_INSTANCE_ID,
                NETWORK_PARTITION_ID, PARTITION_ID, LoadBalancingIPType.Private, System.currentTimeMillis());

        member.setDefaultPrivateIP("10.0.0.1");
        member.setDefaultPublicIP("20.0.0.1");
        Properties properties = new Properties();
        properties.setProperty("prop1", "value1");
        member.setProperties(properties);
        member.setStatus(MemberStatus.Created);
        cluster.addMember(member);

        return topology;
    }

    /**
     * Return new lines found in the output
     *
     * @param currentOutputLines current output lines
     * @param output             output
     * @return
     */
    private List<String> getNewLines(List<String> currentOutputLines, String output) {
        List<String> newLines = new ArrayList<String>();

        if (StringUtils.isNotBlank(output)) {
            String[] lines = output.split(NEW_LINE);
            if (lines != null) {
                for (String line : lines) {
                    if (!currentOutputLines.contains(line)) {
                        currentOutputLines.add(line);
                        newLines.add(line);
                    }
                }
            }
        }
        return newLines;
    }

    /**
     * Sleep current thread
     *
     * @param time
     */
    private void sleep(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException ignore) {
        }
    }

    /**
     * Implements ByteArrayOutputStream.isClosed() method
     */
    private class ByteArrayOutputStreamLocal extends ByteArrayOutputStream {
        private boolean closed;

        @Override
        public void close() throws IOException {
            super.close();
            closed = true;
        }

        public boolean isClosed() {
            return closed;
        }
    }
}