org.apache.stratos.python.cartridge.agent.test.PythonAgentTestManager.java Source code

Java tutorial

Introduction

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

Source

package org.apache.stratos.python.cartridge.agent.test;/*
                                                       * 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.
                                                       */

import org.apache.activemq.broker.BrokerService;
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.threading.StratosThreadPool;
import org.apache.stratos.messaging.broker.publish.EventPublisher;
import org.apache.stratos.messaging.broker.publish.EventPublisherPool;
import org.apache.stratos.messaging.event.Event;
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 java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class PythonAgentTestManager {
    protected final Properties integrationProperties = new Properties();
    public static final String PATH_SEP = File.separator;
    private static final Log log = LogFactory.getLog(PythonAgentTestManager.class);
    protected BrokerService broker = new BrokerService();

    public final long TIMEOUT = 180000;
    public static final String NEW_LINE = System.getProperty("line.separator");
    public static final String ACTIVEMQ_AMQP_BIND_ADDRESS = "activemq.amqp.bind.address";
    public static final String ACTIVEMQ_MQTT_BIND_ADDRESS = "activemq.mqtt.bind.address";
    public static final String CEP_PORT = "cep.port";
    public static final String CEP_SSL_PORT = "cep.ssl.port";
    public static final String DISTRIBUTION_NAME = "distribution.name";
    protected final UUID PYTHON_AGENT_DIR_NAME = UUID.randomUUID();

    protected Map<Integer, ServerSocket> serverSocketMap = new HashMap<>();
    protected Map<String, Executor> executorList = new HashMap<String, Executor>();

    protected int cepPort;
    protected int cepSSLPort;
    protected String amqpBindAddress;
    protected String mqttBindAddress;
    protected String distributionName;

    protected boolean eventReceiverInitiated = false;
    protected TopologyEventReceiver topologyEventReceiver;
    protected InstanceStatusEventReceiver instanceStatusEventReceiver;
    protected boolean instanceStarted;
    protected boolean instanceActivated;
    protected ByteArrayOutputStreamLocal outputStream;
    private ThriftTestServer thriftTestServer;

    /**
     * Setup method for test method testPythonCartridgeAgent
     */
    protected void setup(String resourcePath) {
        try {
            startBroker();
        } catch (Exception e) {
            log.error("Error while starting MB", e);
            return;
        }
        if (!this.eventReceiverInitiated) {
            ExecutorService executorService = StratosThreadPool.getExecutorService("TEST_THREAD_POOL", 15);
            topologyEventReceiver = new TopologyEventReceiver();
            topologyEventReceiver.setExecutorService(executorService);
            topologyEventReceiver.execute();

            instanceStatusEventReceiver = new InstanceStatusEventReceiver();
            instanceStatusEventReceiver.setExecutorService(executorService);
            instanceStatusEventReceiver.execute();

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

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

            this.eventReceiverInitiated = true;
        }

        // Start Thrift server to emulate CEP
        thriftTestServer = new ThriftTestServer();
        try {
            File file = new File(getResourcesPath("common") + PATH_SEP + "stratos-health-stream-def.json");
            FileInputStream fis = new FileInputStream(file);
            byte[] data = new byte[(int) file.length()];
            fis.read(data);
            fis.close();
            String str = new String(data, "UTF-8");
            if (str.equals("")) {
                log.warn(
                        "Stream definition of health stat stream is empty. Thrift server will not function properly");
            }
            thriftTestServer.addStreamDefinition(str, -1234);
            // start with non-ssl port; test server will automatically bind to ssl port
            thriftTestServer.start(cepPort);
            log.info("Started Thrift server with stream definition: " + str);
        } catch (Exception e) {
            log.error("Could not start Thrift test server", e);
        }

        String agentPath = setupPythonAgent(resourcePath);
        log.info("Python agent working directory name: " + PYTHON_AGENT_DIR_NAME);
        log.info("Starting python cartridge agent...");
        this.outputStream = executeCommand("python " + agentPath + PATH_SEP + "agent.py");
    }

    protected void tearDown() {
        tearDown(null);
    }

    /**
     * TearDown method for test method testPythonCartridgeAgent
     */
    protected void tearDown(String sourcePath) {
        for (Map.Entry<String, Executor> entry : executorList.entrySet()) {
            try {
                String commandText = entry.getKey();
                Executor executor = entry.getValue();
                log.info("Terminating process: " + commandText);
                executor.setExitValue(0);
                executor.getWatchdog().destroyProcess();
            } catch (Exception ignore) {
            }
        }
        // wait until everything cleans up to avoid connection errors
        sleep(1000);
        for (ServerSocket serverSocket : serverSocketMap.values()) {
            try {
                log.info("Stopping socket server: " + serverSocket.getLocalSocketAddress());
                serverSocket.close();
            } catch (IOException ignore) {
            }
        }
        try {
            if (thriftTestServer != null) {
                thriftTestServer.stop();
            }
        } catch (Exception e) {
            log.error("Could not stop Thrift test server", e);
        }

        try {
            log.info("Deleting source checkout folder...");
            FileUtils.deleteDirectory(new File(sourcePath));
        } catch (Exception ignore) {
        }
        this.instanceStatusEventReceiver.terminate();
        this.topologyEventReceiver.terminate();

        this.instanceActivated = false;
        this.instanceStarted = false;
        try {
            broker.stop();
        } catch (Exception e) {
            log.error("Error while stopping the broker service", e);
        }
    }

    public PythonAgentTestManager() {
        try {
            integrationProperties.load(
                    PythonAgentTestManager.class.getResourceAsStream(PATH_SEP + "integration-test.properties"));
            distributionName = integrationProperties.getProperty(DISTRIBUTION_NAME);
            amqpBindAddress = integrationProperties.getProperty(ACTIVEMQ_AMQP_BIND_ADDRESS);
            mqttBindAddress = integrationProperties.getProperty(ACTIVEMQ_MQTT_BIND_ADDRESS);
            cepPort = Integer.parseInt(integrationProperties.getProperty(CEP_PORT));
            cepSSLPort = Integer.parseInt(integrationProperties.getProperty(CEP_SSL_PORT));
            log.info("PCA integration properties: " + integrationProperties.toString());
        } catch (IOException e) {
            log.error("Error loading integration-test.properties file from classpath. Please make sure that file "
                    + "exists in classpath.", e);
        }
    }

    protected void startBroker() throws Exception {
        broker.addConnector(amqpBindAddress);
        broker.addConnector(mqttBindAddress);
        broker.setBrokerName("testBroker");
        broker.setDataDirectory(PythonAgentTestManager.class.getResource(PATH_SEP).getPath() + PATH_SEP + ".."
                + PATH_SEP + PYTHON_AGENT_DIR_NAME + PATH_SEP + "activemq-data");
        broker.start();
        log.info("Broker service started!");
    }

    protected void startCommunicatorThread() {
        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("Exception in thread") || line.contains("ERROR")) {
                                try {
                                    throw new RuntimeException(line);
                                } catch (Exception e) {
                                    log.error("ERROR found in PCA log", e);
                                }
                            }
                            log.info("[PCA] " + line);
                        }
                    }
                    sleep(100);
                }
            }
        });
        communicatorThread.start();
    }

    /**
     * Start server socket
     *
     * @param port
     */
    protected void startServerSocket(final int port) {
        Thread socketThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) { // do this infinitely until test is complete
                    try {
                        ServerSocket serverSocket = new ServerSocket(port);
                        serverSocketMap.put(port, serverSocket);
                        log.info("Server socket started on port: " + port);
                        Socket socket = serverSocket.accept();
                        log.info("Client connected to [port] " + port);

                        InputStream is = socket.getInputStream();
                        byte[] buffer = new byte[1024];
                        int read;
                        while (true) {
                            if (socket.isClosed()) {
                                log.info("Socket for [port] " + port + " has been closed.");
                                break;
                            }
                            if ((read = is.read(buffer)) != -1) {
                                String output = new String(buffer, 0, read);
                                log.info("Message received for [port] " + port + ", [message] " + output);
                            }
                        }
                    } catch (IOException e) {
                        String message = "Could not start server socket: [port] " + port;
                        log.error(message, e);
                        throw new RuntimeException(message, e);
                    }
                }
            }
        });
        socketThread.start();
    }

    protected static String getResourcesPath() {
        return PythonAgentTestManager.class.getResource(PATH_SEP).getPath() + PATH_SEP + ".." + PATH_SEP + ".."
                + PATH_SEP + "src" + PATH_SEP + "test" + PATH_SEP + "resources";
    }

    protected static String getResourcesPath(String resourcesPath) {
        return PythonAgentTestManager.class.getResource(PATH_SEP).getPath() + ".." + PATH_SEP + ".." + PATH_SEP
                + "src" + PATH_SEP + "test" + PATH_SEP + "resources" + PATH_SEP + resourcesPath;
    }

    /**
     * Copy python agent distribution to a new folder, extract it and copy sample configuration files
     *
     * @return
     */
    protected String setupPythonAgent(String resourcesPath) {
        try {
            log.info("Setting up python cartridge agent...");

            String srcAgentPath = PythonAgentTestManager.class.getResource(PATH_SEP).getPath() + PATH_SEP + ".."
                    + PATH_SEP + ".." + PATH_SEP + ".." + PATH_SEP + "distribution" + PATH_SEP + "target" + PATH_SEP
                    + distributionName + ".zip";
            String unzipDestPath = PythonAgentTestManager.class.getResource(PATH_SEP).getPath() + PATH_SEP + ".."
                    + PATH_SEP + PYTHON_AGENT_DIR_NAME + PATH_SEP;
            //FileUtils.copyFile(new File(srcAgentPath), new File(destAgentPath));
            unzip(srcAgentPath, unzipDestPath);
            String destAgentPath = PythonAgentTestManager.class.getResource(PATH_SEP).getPath() + PATH_SEP + ".."
                    + PATH_SEP + PYTHON_AGENT_DIR_NAME + PATH_SEP + distributionName;

            String srcAgentConfPath = getResourcesPath(resourcesPath) + PATH_SEP + "agent.conf";
            String destAgentConfPath = destAgentPath + PATH_SEP + "agent.conf";
            FileUtils.copyFile(new File(srcAgentConfPath), new File(destAgentConfPath));

            String srcLoggingIniPath = getResourcesPath(resourcesPath) + PATH_SEP + "logging.ini";
            String destLoggingIniPath = destAgentPath + PATH_SEP + "logging.ini";
            FileUtils.copyFile(new File(srcLoggingIniPath), new File(destLoggingIniPath));

            String srcPayloadPath = getResourcesPath(resourcesPath) + PATH_SEP + "payload";
            String destPayloadPath = destAgentPath + PATH_SEP + "payload";
            FileUtils.copyDirectory(new File(srcPayloadPath), new File(destPayloadPath));

            log.info("Changing extension scripts permissions");
            File extensionsPath = new File(destAgentPath + PATH_SEP + "extensions" + PATH_SEP + "bash");
            File[] extensions = extensionsPath.listFiles();
            for (File extension : extensions) {
                extension.setExecutable(true);
            }

            log.info("Python cartridge agent setup completed");

            return destAgentPath;
        } catch (Exception e) {
            String message = "Could not copy cartridge agent distribution";
            log.error(message, e);
            throw new RuntimeException(message, e);
        }
    }

    private void unzip(String zipFilePath, String destDirectory) throws IOException {
        File destDir = new File(destDirectory);
        if (!destDir.exists()) {
            destDir.mkdir();
        }
        ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
        ZipEntry entry = zipIn.getNextEntry();
        // iterates over entries in the zip file
        while (entry != null) {
            String filePath = destDirectory + File.separator + entry.getName();
            if (!entry.isDirectory()) {
                // if the entry is a file, extracts it
                extractFile(zipIn, filePath);
            } else {
                // if the entry is a directory, make the directory
                File dir = new File(filePath);
                dir.mkdir();
            }
            zipIn.closeEntry();
            entry = zipIn.getNextEntry();
        }
        zipIn.close();
    }

    private void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        byte[] bytesIn = new byte[4096];
        int read = 0;
        while ((read = zipIn.read(bytesIn)) != -1) {
            bos.write(bytesIn, 0, read);
        }
        bos.close();
    }

    /**
     * Execute shell command
     *
     * @param commandText
     */
    protected ByteArrayOutputStreamLocal executeCommand(final String commandText) {
        final ByteArrayOutputStreamLocal outputStream = new ByteArrayOutputStreamLocal();
        try {
            CommandLine commandline = CommandLine.parse(commandText);
            DefaultExecutor exec = new DefaultExecutor();
            PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
            exec.setWorkingDirectory(new File(PythonAgentTestManager.class.getResource(PATH_SEP).getPath()
                    + PATH_SEP + ".." + PATH_SEP + PYTHON_AGENT_DIR_NAME));
            exec.setStreamHandler(streamHandler);
            ExecuteWatchdog watchdog = new ExecuteWatchdog(TIMEOUT);
            exec.setWatchdog(watchdog);
            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);
        }
    }

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

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

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

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

    /**
     * Implements ByteArrayOutputStream.isClosed() method
     */
    protected class ByteArrayOutputStreamLocal extends org.apache.commons.io.output.ByteArrayOutputStream {
        private boolean closed;

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

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