com.github.jrh3k5.mojo.flume.process.AgentProcessTest.java Source code

Java tutorial

Introduction

Here is the source code for com.github.jrh3k5.mojo.flume.process.AgentProcessTest.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 com.github.jrh3k5.mojo.flume.process;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.whenNew;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.github.jrh3k5.mojo.flume.AbstractUnitTest;
import com.github.jrh3k5.mojo.flume.process.AgentProcess.ProcessBuilderProxy;

/**
 * Unit tests for {@link AgentProcess}.
 * 
 * @author Joshua Hyde
 */

@RunWith(PowerMockRunner.class)
@PrepareForTest({ AgentProcess.class, ProcessBuilderProxy.class })
public class AgentProcessTest extends AbstractUnitTest {
    private final String agentName = UUID.randomUUID().toString();
    private AgentProcess agentProcess;
    private File flumeDirectory;
    private File configFile;

    /**
     * Set up properties for each test.
     * 
     * @throws Exception
     *             If any errors occur during the setup.
     */
    @Before
    public void setUp() throws Exception {
        final File testDirectory = createTestDirectory();
        flumeDirectory = new File(testDirectory, "flume");
        configFile = new File(testDirectory, "flume.properties");
        agentProcess = AgentProcess.newBuilder(flumeDirectory).withAgent(agentName).withConfigFile(configFile)
                .build();
    }

    /**
     * Test the construction of the Flume process.
     * 
     * @throws Exception
     *             If any errors occur during the test run.
     */
    @Test
    public void testBuildFlumeProcess() throws Exception {
        final List<String> args = Arrays.asList("arg1", "arg2");
        final AgentProcess.ProcessBuilderProxy builderProxy = new AgentProcess.ProcessBuilderProxy(flumeDirectory,
                args);
        final ProcessBuilder builder = builderProxy.newProcessBuilder();
        assertThat(builder.command()).isEqualTo(args);
        assertThat(builder.directory()).isEqualTo(flumeDirectory);
        assertThat(builder.redirectErrorStream()).isTrue();
    }

    /**
     * Test joining to a Flume agent process.
     * 
     * @throws Exception
     *             If any errors occur during the test run.
     */
    @Test
    public void testJoin() throws Exception {
        final Process process = mockAgentStart();
        agentProcess.join();
        verify(process).waitFor();
    }

    /**
     * Test the starting and stopping of the process.
     * 
     * @throws Exception
     *             If any errors occur during the test run.
     */
    @Test
    public void testStart() throws Exception {
        @SuppressWarnings("rawtypes")
        final ArgumentCaptor<List> argsCaptor = ArgumentCaptor.forClass(List.class);
        mockAgentStart(argsCaptor);

        @SuppressWarnings("unchecked")
        final List<String> args = argsCaptor.getValue();
        // First two commands needed to start the agent - the rest can be in any orders
        assertThat(args.subList(0, 2)).containsExactly("bin/flume-ng", "agent");
        assertThat(getArguments(args.subList(2, args.size()))).containsOnly(new Argument("-c", "conf"),
                new Argument("-f", configFile.getAbsolutePath()), new Argument("-n", agentName));
    }

    /**
     * Test the stopping of the agent process.
     * 
     * @throws Exception
     *             If any errors occur during the test run.
     */
    @Test
    public void testStop() throws Exception {
        final Process process = mockAgentStart();
        agentProcess.stop();
        verify(process).destroy();
    }

    /**
     * Start a mock agent process.
     * 
     * @return A mock of a {@link Process} object representing the mocked process.
     * @throws Exception
     *             If any errors occur during the mocking.
     */
    private Process mockAgentStart() throws Exception {
        return mockAgentStart(ArgumentCaptor.forClass(List.class));
    }

    /**
     * Start a mock agent process.
     * 
     * @param argsCaptor
     *            An {@link ArgumentCaptor} used to capture the arguments used to invoke the mocked process startup.
     * @return A mock of a {@link Process} object representing the mocked process.
     * @throws Exception
     *             If any errors occur during the mocking.
     */
    private Process mockAgentStart(@SuppressWarnings("rawtypes") ArgumentCaptor<List> argsCaptor) throws Exception {
        final ProcessBuilderProxy builderProxy = mock(ProcessBuilderProxy.class);
        whenNew(ProcessBuilderProxy.class).withArguments(eq(flumeDirectory), argsCaptor.capture())
                .thenReturn(builderProxy);

        final Process flumeProcess = mock(Process.class);
        when(builderProxy.start()).thenReturn(flumeProcess);
        agentProcess.start();
        verify(builderProxy).start();
        return flumeProcess;
    }

    private Collection<Argument> getArguments(List<String> args) {
        if (args.size() % 2 != 0) {
            throw new IllegalArgumentException("Unexpected, non-even size of arguments: " + args);
        }

        final Collection<Argument> arguments = new ArrayList<Argument>(args.size() / 2);
        for (int i = 0; i < args.size(); i += 2) {
            arguments.add(new Argument(args.get(i), args.get(i + 1)));
        }
        return arguments;
    }

    /**
     * A simple "holder" class for holding the arguments given to an invocation of the Flume agent.
     * 
     * @author jh016266
     * @since 4.0
     */
    private static class Argument {
        @SuppressWarnings("unused")
        private String argumentName;
        @SuppressWarnings("unused")
        private String argumentValue;

        /**
         * Create an argument.
         * 
         * @param argumentName
         *            The name of the argument.
         * @param argumentValue
         *            The value of the argument.
         */
        public Argument(String argumentName, String argumentValue) {
            this.argumentName = argumentName;
            this.argumentValue = argumentValue;
        }

        @Override
        public boolean equals(Object object) {
            return EqualsBuilder.reflectionEquals(this, object);
        }

        @Override
        public int hashCode() {
            return HashCodeBuilder.reflectionHashCode(this);
        }

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this);
        }
    }
}