/* * 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.flume.test.agent; import java.io.File; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Properties; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import org.apache.flume.test.util.StagedInstall; import org.apache.log4j.Logger; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.google.common.base.Charsets; import com.google.common.base.Splitter; import com.google.common.io.Files; public class TestFileChannel { private static final Logger LOGGER = Logger.getLogger(TestFileChannel.class); private static final Collection<File> tempResources = new ArrayList<File>(); private Properties agentProps; private File sinkOutputDir; @Before public void setUp() throws Exception { /* Create 3 temp dirs, each used as value within agentProps */ final File sinkOutputDir = Files.createTempDir(); tempResources.add(sinkOutputDir); final String sinkOutputDirPath = sinkOutputDir.getCanonicalPath(); LOGGER.info("Created rolling file sink's output dir: " + sinkOutputDirPath); final File channelCheckpointDir = Files.createTempDir(); tempResources.add(channelCheckpointDir); final String channelCheckpointDirPath = channelCheckpointDir .getCanonicalPath(); LOGGER.info("Created file channel's checkpoint dir: " + channelCheckpointDirPath); final File channelDataDir = Files.createTempDir(); tempResources.add(channelDataDir); final String channelDataDirPath = channelDataDir.getCanonicalPath(); LOGGER.info("Created file channel's data dir: " + channelDataDirPath); /* Build props to pass to flume agent */ Properties agentProps = new Properties(); // Active sets agentProps.put("a1.channels", "c1"); agentProps.put("a1.sources", "r1"); agentProps.put("a1.sinks", "k1"); // c1 agentProps.put("a1.channels.c1.type", "FILE"); agentProps.put("a1.channels.c1.checkpointDir", channelCheckpointDirPath); agentProps.put("a1.channels.c1.dataDirs", channelDataDirPath); // r1 agentProps.put("a1.sources.r1.channels", "c1"); agentProps.put("a1.sources.r1.type", "EXEC"); agentProps.put("a1.sources.r1.command", "seq 1 100"); // k1 agentProps.put("a1.sinks.k1.channel", "c1"); agentProps.put("a1.sinks.k1.type", "FILE_ROLL"); agentProps.put("a1.sinks.k1.sink.directory", sinkOutputDirPath); agentProps.put("a1.sinks.k1.sink.rollInterval", "0"); this.agentProps = agentProps; this.sinkOutputDir = sinkOutputDir; } @After public void tearDown() throws Exception { StagedInstall.getInstance().stopAgent(); for (File tempResource : tempResources) { tempResource.delete(); } agentProps = null; } /** * File channel in/out test. Verifies that all events inserted into the * file channel are received by the sink in order. * * The EXEC source creates 100 events where the event bodies have * sequential numbers. The source puts those events into the file channel, * and the FILE_ROLL The sink is expected to take all 100 events in FIFO * order. * * @throws Exception */ @Test public void testInOut() throws Exception { LOGGER.debug("testInOut() started."); /* Find hadoop jar and append it to the flume agent's classpath */ String hadoopJarPath = findHadoopJar(); Assert.assertNotNull("Hadoop jar not found in classpath.", hadoopJarPath); StagedInstall.getInstance().setAgentClasspath(hadoopJarPath); StagedInstall.getInstance().startAgent("a1", agentProps); TimeUnit.SECONDS.sleep(10); // Wait for source and sink to finish // TODO make this more deterministic LOGGER.info("Started flume agent with hadoop in classpath"); /* Create expected output */ StringBuffer sb = new StringBuffer(); for (int i = 1; i <= 100; i++) { sb.append(i).append("\n"); } String expectedOutput = sb.toString(); LOGGER.info("Created expected output: " + expectedOutput); /* Create actual output file */ File[] sinkOutputDirChildren = sinkOutputDir.listFiles(); // Only 1 file should be in FILE_ROLL sink's dir (rolling is disabled) Assert.assertEquals("Expected FILE_ROLL sink's dir to have only 1 child," + " but found " + sinkOutputDirChildren.length + " children.", 1, sinkOutputDirChildren.length); File actualOutput = sinkOutputDirChildren[0]; if (!Files.toString(actualOutput, Charsets.UTF_8).equals(expectedOutput)) { LOGGER.error("Actual output doesn't match expected output.\n"); throw new AssertionError("FILE_ROLL sink's actual output doesn't " + "match expected output."); } LOGGER.debug("testInOut() ended."); } /** * Search for and return the first path element found that includes hadoop. * We search the class path of the current JVM process to grab the same * hadoop jar that's depended on by the file channel. * * TODO Add all deps of hadoop jar to classpath * * @return path to the first hadoop jar found, null if not found */ private String findHadoopJar() { //Grab classpath String classpath = System.getProperty("java.class.path"); String trimmedClasspath = classpath.trim(); //parse classpath into path elements Iterable<String> pathElements = Splitter.on(Pattern.compile("[;:]")) .omitEmptyStrings() .trimResults() .split(trimmedClasspath); //find the first path element that includes the hadoop jar for (String pathElement : pathElements) { if (Pattern.compile("(?i)hadoop").matcher(pathElement).find()) { return pathElement; } } LOGGER.error("Hadoop not found in classpath: |" + classpath + "|"); return null; } }