/**
* Licensed to Cloudera, Inc. under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Cloudera, Inc. 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.cloudera.flume.conf;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cloudera.flume.ExampleData;
import com.cloudera.flume.handlers.rolling.RollSink;
import com.cloudera.flume.master.availability.FailoverChainSink;
/**
* This code tests the parser and config spec error exceptions and data. Thses
* should parse properly but fail becuase of invalid # of args, invalid types
* for args, or invalid names for sources, sinks, and decorators.
*/
public class TestFlumeBuilder implements ExampleData {
public static final Logger LOG = LoggerFactory.getLogger(TestFlumeBuilder.class);
String SOURCE = "text(\"bogusfile\")";
@Test
public void testBadParse() throws FlumeSpecException {
try {
FlumeBuilder.buildSink(new Context(), "asink [ something bad] ");
} catch (Exception e) {
// This is actually what happens
System.out.println(e);
return;
}
fail("expected recognition exception");
}
@Test
public void testBadLex() throws FlumeSpecException {
try {
FlumeBuilder.buildSink(new Context(), "#$!@#$!@#$ ");
} catch (Exception e) {
// This is actually what happens
System.out.println(e);
return;
}
fail("expected recognition exception");
}
@Test
public void testBuildConsole() throws IOException, FlumeSpecException {
FlumeBuilder.buildSink(new Context(), "console");
}
@Test
public void testBuildBadArgs() throws FlumeSpecException {
try {
// too many arguments
FlumeBuilder.buildSink(new Context(), "console(1,2,3,4,5,6)");
} catch (FlumeArgException e) {
System.out.println(e);
return;// we expected this exception to be thrown.
}
fail("should have thrown exception");
}
@Test
public void testBuildConsoleBad() {
// too many arguments
try {
FlumeBuilder.buildSink(new Context(), "unpossiblesink");
} catch (FlumeSpecException e) {
System.out.println(e);
return; // we expected this exception to be thrown.
}
fail("should have thrown exception");
}
// Need to be able to handle FQDN names like www.foo.com, and
// IPv4 addresses like 192.168.1.1
@Test
public void testHostnamne() throws org.antlr.runtime.RecognitionException {
// simple
CommonTree t = null;
t = FlumeBuilder.parseHost("localhost");
System.out.println(t);
// fqdn
t = FlumeBuilder.parseHost("localhost.localdomain.com");
System.out.println(t);
// ip adder
t = FlumeBuilder.parseHost("1.2.3.4");
System.out.println(t);
}
@Test
public void testMultiSink() throws IOException, FlumeSpecException {
String multi = "[ console , counter(\"count\") ]";
FlumeBuilder.buildSink(new Context(), multi);
}
@Test
public void testMultiSinkBad() throws IOException, FlumeSpecException {
try {
String multi = "[ console , unpossiblesink(\"count\") ]";
FlumeBuilder.buildSink(new Context(), multi);
} catch (FlumeSpecException e) {
System.out.println(e);
return;
}
fail("should have thrown exception");
}
@Test
public void testDecorated() throws IOException, FlumeSpecException {
String decorated = "{ intervalSampler(5) => console }";
FlumeBuilder.buildSink(new Context(), decorated);
}
@Test
public void testDecoratedBad1() throws IOException, FlumeSpecException {
try {
String decorated = "{ unpossible(5) => console }";
FlumeBuilder.buildSink(new Context(), decorated);
} catch (FlumeSpecException e) {
System.out.println(e);
return;
}
fail("should have thrown exception");
}
@Test
public void testDecoratedBad2() throws IOException, FlumeSpecException {
try {
String decorated = "{ intervalSampler(5) => unpossible }";
FlumeBuilder.buildSink(new Context(), decorated);
} catch (FlumeSpecException e) {
System.out.println(e);
return;
}
fail("should have thrown exception");
}
/**
* This is being ignored for the time being -- this is a future JIRA.
*/
@Ignore
@Test
public void testDecoChain() throws RecognitionException {
String decoChain = "{ nullDeco => nullDeco => nullDeco => null}";
FlumeBuilder.parseSink(decoChain);
}
@Test
public void testFailover() throws IOException, FlumeSpecException {
String multi = "< { flakeyAppend(.9,1337) => console } ? counter(\"count\") >";
FlumeBuilder.buildSink(new Context(), multi);
}
@Test
public void testFailoverBad1() throws IOException, FlumeSpecException {
try {
String multi = "< unpossible ? counter(\"count\") >";
FlumeBuilder.buildSink(new Context(), multi);
} catch (FlumeSpecException e) {
System.out.println(e);
return;
}
fail("should have thrown exception");
}
@Test
public void testFailoverBad2() throws IOException, FlumeSpecException {
try {
String multi = "< { flakeyAppend(.9,1337) => console } ? unpossible(\"count\") >";
FlumeBuilder.buildSink(new Context(), multi);
} catch (FlumeSpecException e) {
System.out.println(e);
return;
}
fail("should have thrown exception");
}
/**
* Testing a successful parse (would throw exn on parser failure)
*/
@Test
public void testLet() throws FlumeSpecException {
String let = "let foo := console in let bar := console in [ foo, bar ]";
FlumeBuilder.buildSink(new Context(), let);
}
/**
* Tests a parsing a case where lets vars are shadowed in a sub let expression
* (let names foo, and a sub let names a foo).
*/
@Test
public void testLetShadow() throws IOException, FlumeSpecException {
String let = "let foo := console in let foo := null in foo";
FlumeBuilder.buildSink(new Context(), let);
}
/**
* Tests a parse that fails due to an undeclared var.
*/
@Test
public void testLetBad() throws FlumeSpecException {
try {
String let2 = "let foo := console in let bar := console in [ foo, barf ]";
FlumeBuilder.buildSink(new Context(), let2);
} catch (FlumeSpecException e) {
System.out.println(e);
return;
}
fail("should have barfed");
}
/**
* Test a parse that fails due to a a variable used that is out of scope.
*/
@Test
public void testLetBadContext() throws FlumeSpecException {
// bad variable names
try {
String let2 = "[ let foo := console in foo, let bar := console in [ foo, bar ] ]";
FlumeBuilder.buildSink(new Context(), let2);
} catch (FlumeSpecException e) {
System.out.println(e);
return;
}
fail("should have failed because foo is out of context");
}
@Test
public void testRollSinkParse() throws FlumeSpecException,
RecognitionException {
String roll = "roll (2123) { null } ";
FlumeBuilder.parseSink(roll);
}
@Test
public void testRollSink() throws FlumeSpecException, RecognitionException {
String roll = "roll (200) { null } ";
assertTrue(FlumeBuilder.buildSink(new Context(), roll) instanceof RollSink);
}
@Test
public void testFailChain() throws FlumeSpecException {
String failchain = "failchain (\"foo\", \"bar\",\"baz\") { logicalSink(\"%s\") } ";
assertTrue(FlumeBuilder.buildSink(new Context(), failchain) instanceof FailoverChainSink);
}
/**
* Make sure only simple "sink" things allowed in left hand side of decorator.
* In this case , deco1 is ok, but the let statement makes no sense because it
* ends up that there is a sink decorating a sink instead of a sink decorator
* decorating a sink.
*/
@Test(expected = RuntimeRecognitionException.class)
public void testLetInWrongPlace() throws RecognitionException {
String badsink = "{ deco1 => { let letvar := test in deco2 => [ < sink1 ? sink2> , sink3, { deco3 => sink4} ] } } ";
CommonTree parse = FlumeBuilder.parseSink(badsink);
LOG.info(parse.toStringTree());
}
/**
* Verify basic functionality - contains basic sink/source/decorator
*/
@Test
public void testListExtensions() {
FlumeBuilder.getSinkNames().contains("agentSink");
FlumeBuilder.getDecoratorNames().contains("regex");
FlumeBuilder.getSourceNames().contains("collectorSource");
}
}