@Test public void testWithMultipleTargetValueResults() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] { new Result(1, "one", -1, -1), new Result("2", "two", -1, -1), new Result(3, "three", -1, -1) }; } }) .build(); final Message msg = createMessage("the hello"); extractor.runExtractor(msg); assertThat(msg.hasField("target")).isFalse(); assertThat(msg.getField("one")).isEqualTo(1); assertThat(msg.getField("two")).isEqualTo("2"); assertThat(msg.getField("three")).isEqualTo(3); }
@Test public void testConvertersWithMultipleFields() throws Exception { final Converter converter = new TestConverter.Builder() .multiple(true) .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return ImmutableMap.builder() .put("one", 1) .put("two", "2") .put( "message", "message should not be overwritten") // Try to overwrite reserved field. .build(); } }) .build(); final TestExtractor extractor = new TestExtractor.Builder() .converters(Lists.newArrayList(converter)) .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("1", -1, -1)}; } }) .build(); final Message msg = createMessage("the message"); extractor.runExtractor(msg); // With a "multiple fields" converter the target field is not touched, only the additional // fields are added. assertThat(msg.getField("target")).isEqualTo("1"); assertThat(msg.getField("one")).isEqualTo(1); assertThat(msg.getField("two")).isEqualTo("2"); // Reserved fields are not overwritten! assertThat(msg.getField("message")).isEqualTo("the message"); // Attempts to overwrite a reserved field are recorded as converter exception. assertThat(extractor.getConverterExceptionCount()).isEqualTo(1); }
@Test public void testConvertersThatReturnNullValue() throws Exception { final Converter converter = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return null; } }) .build(); final TestExtractor extractor = new TestExtractor.Builder() .converters(Lists.newArrayList(converter)) .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("1", -1, -1)}; } }) .build(); final Message msg = createMessage("message"); extractor.runExtractor(msg); assertThat(msg.getField("target")).isNull(); }
@Test public void testConvertersWithNonStringFieldValue() throws Exception { final Converter converter = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return "converted"; } }) .build(); final TestExtractor extractor = new TestExtractor.Builder() .converters(Lists.newArrayList(converter)) .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result(123, "target", -1, -1)}; } }) .build(); final Message msg = createMessage("message"); extractor.runExtractor(msg); // Only string values will be converted. assertThat(msg.getField("target")).isEqualTo(123); }
@Test public void testCursorStrategyCutIfTargetFieldEqualsSourceField() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .cursorStrategy(CUT) .sourceField("msg") .targetField("msg") .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("the", 0, 3)}; } }) .build(); final Message msg = createMessage("message"); msg.addField("msg", "the hello"); extractor.runExtractor(msg); // If source and target fields are the same, the field is not touched because it already got set // to a new value. assertThat(msg.getField("msg")).isEqualTo("the"); }
@Test public void testCursorStrategyCutWithMultipleResults() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .cursorStrategy(CUT) .sourceField("msg") .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] { new Result("the", "one", 0, 3), new Result("hello", "two", 10, 15), }; } }) .build(); final Message msg = createMessage("message"); msg.addField("msg", "the great hello"); extractor.runExtractor(msg); // With the cut strategy the matched data will be removed from the message. assertThat(msg.getField("msg")).isEqualTo("great"); }
@Test public void testCursorStrategyCopyWithMultipleResults() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .cursorStrategy(COPY) .sourceField("msg") .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] { new Result("the", "one", 0, 3), new Result("hello", "two", 10, 15), }; } }) .build(); final Message msg = createMessage("message"); msg.addField("msg", "the great hello"); extractor.runExtractor(msg); // With the copy strategy, the source field will not be modified. assertThat(msg.getField("msg")).isEqualTo("the great hello"); }
@Test public void testConvertersAreExecutedInOrder() throws Exception { final Converter converter1 = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return ((String) input) + "1"; } }) .build(); final Converter converter2 = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return ((String) input) + "2"; } }) .build(); final Converter converter3 = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return ((String) input) + "3"; } }) .build(); final TestExtractor extractor = new TestExtractor.Builder() .converters(Lists.newArrayList(converter1, converter2, converter3)) .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("converter", -1, -1)}; } }) .build(); final Message msg = createMessage("message"); extractor.runExtractor(msg); assertThat(msg.getField("target")).isEqualTo("converter123"); }
@Override public boolean match(Message msg, StreamRule rule) { Double msgVal = getDouble(msg.getField(rule.getField())); if (msgVal == null) { return false; } Double ruleVal = getDouble(rule.getValue()); if (ruleVal == null) { return false; } return rule.getInverted() ^ (msgVal > ruleVal); }
@Test public void testMultipleConvertersWithFirstReturningNullValue() throws Exception { final Converter converter1 = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return null; } }) .build(); final Converter converter2 = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return input + "2"; } }) .build(); final TestExtractor extractor = new TestExtractor.Builder() .converters(Lists.newArrayList(converter1, converter2)) .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("converter", -1, -1)}; } }) .build(); final Message msg = createMessage("message"); extractor.runExtractor(msg); // If the first converter returns null, the second will not be executed because the value is not // a string anymore. assertThat(msg.getField("target")).isNull(); }
@Test public void testWithOneValueOnlyResult() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("1", -1, -1)}; } }) .build(); final Message msg = createMessage("the hello"); extractor.runExtractor(msg); assertThat(msg.getField("target")).isEqualTo("1"); }
@Test public void testCursorStrategyCutIfSourceFieldIsReservedField() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .cursorStrategy(CUT) .sourceField("message") .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("the", 0, 3)}; } }) .build(); final Message msg = createMessage("the hello"); extractor.runExtractor(msg); // The source value is not modified if it is a reserved field. assertThat(msg.getField("message")).isEqualTo("the hello"); }
@Test public void testCursorStrategyCutIfBeginAndEndIndexAreDisabled() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .cursorStrategy(CUT) .sourceField("msg") .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("the", -1, -1)}; } }) .build(); final Message msg = createMessage("message"); msg.addField("msg", "the hello"); extractor.runExtractor(msg); // If the begin and end index is -1, the source field should not be modified. assertThat(msg.getField("msg")).isEqualTo("the hello"); }
@Test public void testCursorStrategyCutWithAllTextCut() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .cursorStrategy(CUT) .sourceField("msg") .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("the hello", 0, 9)}; } }) .build(); final Message msg = createMessage("message"); msg.addField("msg", "the hello"); extractor.runExtractor(msg); // If all data is cut from the source field, the "fullyCutByExtractor" string gets inserted. assertThat(msg.getField("msg")).isEqualTo("fullyCutByExtractor"); }
@Test(expected = StringIndexOutOfBoundsException.class) public void testCursorStrategyCutIfEndIndexIsDisabled() throws Exception { final TestExtractor extractor = new TestExtractor.Builder() .cursorStrategy(CUT) .sourceField("msg") .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("the", 0, -1)}; } }) .build(); final Message msg = createMessage("message"); msg.addField("msg", "the hello"); extractor.runExtractor(msg); // If the end index is -1, the source field should not be modified. // TODO: The current implementation only checks if begin index is -1. Needs to be fixed. assertThat(msg.getField("msg")).isEqualTo("the hello"); }
@Override public void write(Message msg) throws Exception { if (shutdown || driverFailed) { return; } try { if (connection == null) { reconnect(); } if (connection == null) { return; } synchronized (connection) { int index = 1; logInsert.setTimestamp(index++, new Timestamp(msg.getTimestamp().getMillis())); logInsert.setString(index++, msg.getId()); logInsert.setString(index++, msg.getSource()); String ms = msg.getMessage(); if (ms != null && ms.length() > MAX_MESSAGE) { ms = ms.substring(0, MAX_MESSAGE); } logInsert.setString(index++, ms); if (fields != null) { for (String f : fields) { Object value = msg.getField(f); String s = value != null ? value.toString() : null; if (s == null) { logInsert.setNull(index++, Types.VARCHAR); } else { if (s.length() > MAX_VALUE) { s = s.substring(0, MAX_VALUE); } logInsert.setString(index++, s); } } } logInsert.executeUpdate(); if (logInsertAttribute != null) { Object id = null; ResultSet ids = logInsert.getGeneratedKeys(); while (ids != null && ids.next()) { id = ids.getObject(1); } if (id != null) { for (Entry<String, Object> e : msg.getFieldsEntries()) { String name = e.getKey(); Object value = e.getValue(); String s = value != null ? value.toString() : null; logInsertAttribute.setObject(1, id); logInsertAttribute.setString(2, name); if (s.length() > MAX_VALUE) { s = s.substring(0, MAX_VALUE); } logInsertAttribute.setString(3, s); logInsertAttribute.executeUpdate(); } } else { throw new SQLException("Failed to generate ID for primary log record!"); } } } } catch (SQLException e) { log.log(Level.WARNING, "JDBC output error: " + e.getMessage(), e); if (connection != null) { try { connection.rollback(); connection.setAutoCommit(true); } catch (SQLException ee) { // Don`t care } } connection = null; } finally { if (connection != null) { connection.commit(); } } }
@Test public void testConvertersWithExceptions() throws Exception { final Converter converter1 = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { throw new NullPointerException("EEK"); } }) .build(); final Converter converter2 = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { return input + "2"; } }) .build(); final Converter converter3 = new TestConverter.Builder() .callback( new Function<Object, Object>() { @Nullable @Override public Object apply(Object input) { throw new NullPointerException("EEK"); } }) .build(); final TestExtractor extractor = new TestExtractor.Builder() .converters(Lists.newArrayList(converter1, converter2, converter3)) .callback( new Callable<Result[]>() { @Override public Result[] call() throws Exception { return new Result[] {new Result("converter", -1, -1)}; } }) .build(); final Message msg = createMessage("message"); extractor.runExtractor(msg); // The two exceptions should have been recorded. assertThat(extractor.getConverterExceptionCount()).isEqualTo(2); // It ignores all converters which throw an exception but executes the ones that don't. // TODO: Is this really the expected behaviour? The converters are executed in order and // basically depend on the output of the previous. This might not work for all converters. assertThat(msg.getField("target")).isEqualTo("converter2"); }