/** * 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"); } }