info.pancancer.arch3.test.TestWorkerWithMocking.java Source code

Java tutorial

Introduction

Here is the source code for info.pancancer.arch3.test.TestWorkerWithMocking.java

Source

/*
 *     Consonance - workflow software for multiple clouds
 *     Copyright (C) 2016 OICR
 *
 *     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 info.pancancer.arch3.test;

import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;
import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConsumerCancelledException;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;
import com.rabbitmq.client.ShutdownSignalException;
import info.pancancer.arch3.beans.Job;
import info.pancancer.arch3.utils.Constants;
import info.pancancer.arch3.utils.Utilities;
import info.pancancer.arch3.worker.WorkerRunnable;
import info.pancancer.arch3.worker.WorkflowRunner;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import org.apache.commons.configuration.HierarchicalINIConfiguration;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecuteResultHandler;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteResultHandler;
import org.apache.commons.lang3.StringUtils;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@PrepareForTest({ QueueingConsumer.class, Utilities.class, WorkerRunnable.class, DefaultExecutor.class,
        WorkflowRunner.class, DefaultExecuteResultHandler.class, Logger.class, LoggerFactory.class,
        HierarchicalINIConfiguration.class })
@RunWith(PowerMockRunner.class)
public class TestWorkerWithMocking {

    @Mock
    private HierarchicalINIConfiguration config;

    @Mock
    private Utilities mockUtil;

    @Mock
    private Channel mockChannel;

    @Mock
    private com.rabbitmq.client.Connection mockConnection;

    @Mock
    private QueueingConsumer mockConsumer;

    @Mock
    private Envelope mockEnvelope;

    @Mock
    private BasicProperties mockProperties;

    @Spy
    private DefaultExecutor mockExecutor = new DefaultExecutor();

    private DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();

    @Mock
    private Appender<LoggingEvent> mockAppender;

    @Captor
    private ArgumentCaptor<LoggingEvent> argCaptor;

    private static ch.qos.logback.classic.Logger LOG = (ch.qos.logback.classic.Logger) LoggerFactory
            .getLogger(Logger.ROOT_LOGGER_NAME);

    @Before
    public void setUp() throws IOException, TimeoutException {
        MockitoAnnotations.initMocks(this);
        PowerMockito.mockStatic(Utilities.class);

        Mockito.when(mockAppender.getName()).thenReturn("MOCK");
        LOG.addAppender((Appender) mockAppender);

        Mockito.doNothing().when(mockConnection).close();
        Mockito.when(mockChannel.getConnection()).thenReturn(mockConnection);
        Mockito.when(Utilities.setupQueue(any(HierarchicalINIConfiguration.class), anyString()))
                .thenReturn(mockChannel);
        Mockito.when(Utilities.setupExchange(any(HierarchicalINIConfiguration.class), anyString()))
                .thenReturn(mockChannel);
    }

    private String appendEventsIntoString(List<LoggingEvent> events) {
        StringBuffer sbuff = new StringBuffer();
        for (LoggingEvent e : events) {
            sbuff.append("\n" + e.getMessage());
        }
        return sbuff.toString();
    }

    @Test
    public void testRunWorker()
            throws ShutdownSignalException, ConsumerCancelledException, InterruptedException, Exception {

        PowerMockito.whenNew(DefaultExecuteResultHandler.class).withNoArguments().thenReturn(this.handler);
        Mockito.doAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                for (int i = 0; i < 5; i++) {
                    CommandLine cli = new CommandLine("echo");
                    cli.addArgument("iteration: " + i);
                    mockExecutor.execute(cli);
                    Thread.sleep(500);
                }
                CommandLine cli = new CommandLine("bash");
                cli.addArgument("./src/test/resources/err_output.sh");
                mockExecutor.execute(cli);
                // Here we make sure that the Handler that always gets used always returns 0, and then everything completes OK.
                handler.onProcessComplete(0);
                return null;
            }
        }).when(mockExecutor).execute(any(CommandLine.class), any(ExecuteResultHandler.class));
        PowerMockito.whenNew(DefaultExecutor.class).withNoArguments().thenReturn(mockExecutor);

        setupConfig();

        Job j = new Job();
        j.setWorkflowPath("/workflows/Workflow_Bundle_HelloWorld_1.0-SNAPSHOT_SeqWare_1.1.0");
        j.setWorkflow("HelloWorld");
        j.setWorkflowVersion("1.0-SNAPSHOT");
        j.setJobHash("asdlk2390aso12jvrej");
        j.setUuid("1234567890");
        Map<String, String> iniMap = new HashMap<>(3);
        iniMap.put("param1", "value1");
        iniMap.put("param2", "value2");
        iniMap.put("param3", "help I'm trapped in an INI file");
        j.setIni(iniMap);
        byte[] body = j.toJSON().getBytes();
        Delivery testDelivery = new Delivery(mockEnvelope, mockProperties, body);
        Mockito.when(mockConsumer.nextDelivery()).thenReturn(testDelivery);

        PowerMockito.whenNew(QueueingConsumer.class).withArguments(mockChannel).thenReturn(mockConsumer);

        WorkerRunnable testWorker = new WorkerRunnable("src/test/resources/workerConfig.ini", "vm123456", 1);

        testWorker.run();
        // String testResults = TestWorkerWithMocking.outBuffer.toString();// this.outStream.toString();

        Mockito.verify(mockAppender, Mockito.atLeastOnce()).doAppend(argCaptor.capture());
        List<LoggingEvent> tmpList = new LinkedList<LoggingEvent>(argCaptor.getAllValues());
        String testResults = this.appendEventsIntoString(tmpList);

        testResults = cleanResults(testResults);
        // System.out.println("\n===============================\nTest Results: " + testResults);
        // System.out.println(testResults);
        String expectedDockerCommand = "docker run --rm -h master -t -v /var/run/docker.sock:/var/run/docker.sock -v /workflows/Workflow_Bundle_HelloWorld_1.0-SNAPSHOT_SeqWare_1.1.0:/workflow -v /tmp/seqware_tmpfile.ini:/ini -v /datastore:/datastore -v /home/$USER/.gnos:/home/$USER/.gnos -v /home/$USER/custom-seqware-settings:/home/seqware/.seqware/settings pancancer/seqware_whitestar_pancancer:1.2.3.4 seqware bundle launch --dir /workflow --ini /ini --no-metadata --engine whitestar";
        // System.out.println(expectedDockerCommand);
        assertTrue("Check for docker command, got " + testResults, testResults.contains(expectedDockerCommand));
        assertTrue("Check for sleep message in the following:" + testResults,
                testResults.contains("Sleeping before executing workflow for 1000 ms."));
        assertTrue("Check for workflow complete", testResults.contains("Docker execution result: \"iteration: 0\"\n"
                + "\"iteration: 1\"\n" + "\"iteration: 2\"\n" + "\"iteration: 3\"\n" + "\"iteration: 4\"\n"));

        String begining = new String(Files.readAllBytes(Paths.get("src/test/resources/testResult_Start.txt")));
        assertTrue("check begining of output:" + StringUtils.difference(begining, testResults),
                testResults.contains(begining));

        assertTrue("check INI: " + testResults,
                testResults.contains("param1=value1") && testResults.contains("param2=value2")
                        && testResults.contains("param3=help I'm trapped in an INI file"));

        String ending = new String(Files.readAllBytes(Paths.get("src/test/resources/testResult_End.txt")));
        assertTrue("check ending of output", testResults.contains(ending));

        String initalHeartbeat = new String(
                Files.readAllBytes(Paths.get("src/test/resources/testInitialHeartbeat.txt")));
        assertTrue("Check for an initial heart beat, found" + testResults, testResults.contains(initalHeartbeat));

        assertTrue("check for stderr in heartbeat", testResults.contains("\"stderr\": \"123_err\","));
    }

    private void setupConfig() {
        Mockito.when(config.getString(Constants.RABBIT_QUEUE_NAME)).thenReturn("seqware");
        Mockito.when(config.getString(Constants.RABBIT_HOST)).thenReturn("localhost");
        Mockito.when(config.getString(Constants.RABBIT_USERNAME)).thenReturn("guest");
        Mockito.when(config.getString(Constants.RABBIT_PASSWORD)).thenReturn("guest");

        Mockito.when(config.getString(Constants.WORKER_HEARTBEAT_RATE)).thenReturn("2.5");
        Mockito.when(config.getString(Constants.WORKER_MAX_RUNS)).thenReturn("1");
        Mockito.when(config.getLong(Constants.WORKER_PREWORKER_SLEEP, WorkerRunnable.DEFAULT_PRESLEEP))
                .thenReturn(1L);
        Mockito.when(config.getLong(Constants.WORKER_POSTWORKER_SLEEP, WorkerRunnable.DEFAULT_POSTSLEEP))
                .thenReturn(1L);
        Mockito.when(config.getString(Constants.WORKER_ENDLESS)).thenReturn("1");

        Mockito.when(config.getString(Constants.WORKER_SEQWARE_ENGINE, Constants.SEQWARE_WHITESTAR_ENGINE))
                .thenReturn(Constants.SEQWARE_WHITESTAR_ENGINE);
        Mockito.when(config.getString(Constants.WORKER_SEQWARE_SETTINGS_FILE))
                .thenReturn("/home/ubuntu/custom-seqware-settings");
        Mockito.when(config.getString(Constants.WORKER_SEQWARE_DOCKER_IMAGE_NAME))
                .thenReturn("pancancer/seqware_whitestar_pancancer:1.2.3.4");
        Mockito.when(config.getString(Constants.WORKER_HOST_USER_NAME, "ubuntu")).thenReturn("ubuntu");
        Mockito.when(Utilities.parseConfig(anyString())).thenReturn(config);
    }

    private String cleanResults(String testResults) {
        testResults = testResults.replaceAll("/home/ubuntu/", "/home/\\$USER/");
        testResults = testResults.replaceAll("seqware_[0-9]+\\.ini", "seqware_tmpfile.ini");
        testResults = testResults.replaceAll("oozie-[a-z0-9\\-]+", "JOB_ID");
        testResults = testResults.replaceAll("\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}", "0000/00/00 00:00:00");
        testResults = testResults.replaceAll("bundle_manager\\d+", "bundle_manager_LONG_NUMERIC_SEQUENCE");
        testResults = testResults.replaceAll("scheduler\\d+out", "schedulerLONG_NUMERIC_SEQUENCEout");
        testResults = testResults.replaceAll("IP address: /[^\"]*", "IP address: 0.0.0.0");
        return testResults;
    }
}