/*
* 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.activemq.artemis.core.filter.impl;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.ActiveMQInvalidFilterExpressionException;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.filter.Filter;
import org.apache.activemq.artemis.core.message.impl.CoreMessage;
import org.apache.activemq.artemis.tests.util.SilentTestCase;
import org.apache.activemq.artemis.utils.RandomUtil;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Tests the compliance with the ActiveMQ Artemis Filter syntax.
*/
public class FilterTest extends SilentTestCase {
private Filter filter;
private Message message;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
message = new CoreMessage().initBuffer(1024).setMessageID(1);
}
@Test
public void testNewlineMatch() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("fooprop LIKE '%1234%'"));
message.putStringProperty(new SimpleString("fooprop"), new SimpleString("hello1234\n"));
Assert.assertTrue(filter.match(message));
}
@Test
public void testFilterForgets() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("color = 'RED'"));
message.putStringProperty(new SimpleString("color"), new SimpleString("RED"));
Assert.assertTrue(filter.match(message));
message = new CoreMessage();
Assert.assertFalse(filter.match(message));
}
@Test
public void testInvalidString() throws Exception {
testInvalidFilter("color = 'red");
testInvalidFilter(new SimpleString("color = 'red"));
testInvalidFilter("3");
testInvalidFilter(new SimpleString("3"));
}
@Test
public void testNullFilter() throws Exception {
Assert.assertNull(FilterImpl.createFilter((String) null));
Assert.assertNull(FilterImpl.createFilter(""));
Assert.assertNull(FilterImpl.createFilter((SimpleString) null));
Assert.assertNull(FilterImpl.createFilter(new SimpleString("")));
}
@Test
public void testAMQDurable() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("AMQDurable='DURABLE'"));
message.setDurable(true);
Assert.assertTrue(filter.match(message));
message.setDurable(false);
Assert.assertFalse(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("AMQDurable='NON_DURABLE'"));
message = new CoreMessage();
message.setDurable(true);
Assert.assertFalse(filter.match(message));
message.setDurable(false);
Assert.assertTrue(filter.match(message));
}
@Test
public void testAMQSize() throws Exception {
message.setAddress(RandomUtil.randomSimpleString());
int encodeSize = message.getEncodeSize();
Filter moreThanSmall = FilterImpl.createFilter(new SimpleString("AMQSize > " + (encodeSize - 1)));
Filter lessThanLarge = FilterImpl.createFilter(new SimpleString("AMQSize < " + (encodeSize + 1)));
Filter lessThanSmall = FilterImpl.createFilter(new SimpleString("AMQSize < " + encodeSize));
Filter moreThanLarge = FilterImpl.createFilter(new SimpleString("AMQSize > " + encodeSize));
Assert.assertTrue(moreThanSmall.match(message));
Assert.assertTrue(lessThanLarge.match(message));
Assert.assertFalse(lessThanSmall.match(message));
Assert.assertFalse(moreThanLarge.match(message));
}
@Test
public void testAMQPriority() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("AMQPriority=3"));
for (int i = 0; i < 10; i++) {
message.setPriority((byte) i);
if (i == 3) {
Assert.assertTrue(filter.match(message));
} else {
Assert.assertFalse(filter.match(message));
}
}
}
@Test
public void testAMQTimestamp() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("AMQTimestamp=12345678"));
message.setTimestamp(87654321);
Assert.assertFalse(filter.match(message));
message.setTimestamp(12345678);
Assert.assertTrue(filter.match(message));
}
@Test
public void testBooleanTrue() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("MyBoolean=true"));
testBoolean("MyBoolean", true);
}
@Test
public void testIdentifier() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("MyBoolean"));
testBoolean("MyBoolean", true);
}
@Test
public void testDifferentNullString() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("prop <> 'foo'"));
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("NOT (prop = 'foo')"));
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("prop <> 'foo'"));
doPutStringProperty("prop", "bar");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("prop <> 'foo'"));
doPutStringProperty("prop", "foo");
Assert.assertFalse(filter.match(message));
}
@Test
public void testBooleanFalse() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("MyBoolean=false"));
testBoolean("MyBoolean", false);
}
private void testBoolean(final String name, final boolean flag) throws Exception {
message.putBooleanProperty(new SimpleString(name), flag);
Assert.assertTrue(filter.match(message));
message.putBooleanProperty(new SimpleString(name), !flag);
Assert.assertTrue(!filter.match(message));
}
@Test
public void testStringEquals() throws Exception {
// First, simple test of string equality and inequality
filter = FilterImpl.createFilter(new SimpleString("MyString='astring'"));
doPutStringProperty("MyString", "astring");
Assert.assertTrue(filter.match(message));
doPutStringProperty("MyString", "NOTastring");
Assert.assertTrue(!filter.match(message));
// test empty string
filter = FilterImpl.createFilter(new SimpleString("MyString=''"));
doPutStringProperty("MyString", "");
Assert.assertTrue("test 1", filter.match(message));
doPutStringProperty("MyString", "NOTastring");
Assert.assertTrue("test 2", !filter.match(message));
// test literal apostrophes (which are escaped using two apostrophes
// in selectors)
filter = FilterImpl.createFilter(new SimpleString("MyString='test JBoss''s filter'"));
// note: apostrophes are not escaped in string properties
doPutStringProperty("MyString", "test JBoss's filter");
// this test fails -- bug 530120
// assertTrue("test 3", filter.match(message));
doPutStringProperty("MyString", "NOTastring");
Assert.assertTrue("test 4", !filter.match(message));
}
@Test
public void testNOT_INWithNullProperty() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("myNullProp NOT IN ('foo','jms','test')"));
assertFalse(filter.match(message));
message.putStringProperty("myNullProp", "JMS");
assertTrue(filter.match(message));
}
@Test
public void testNOT_LIKEWithNullProperty() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("myNullProp NOT LIKE '1_3'"));
assertFalse(filter.match(message));
message.putStringProperty("myNullProp", "JMS");
assertTrue(filter.match(message));
}
@Test
public void testIS_NOT_NULLWithNullProperty() throws Exception {
filter = FilterImpl.createFilter(new SimpleString("myNullProp IS NOT NULL"));
assertFalse(filter.match(message));
message.putStringProperty("myNullProp", "JMS");
assertTrue(filter.match(message));
}
@Test
public void testStringLike() throws Exception {
// test LIKE operator with no wildcards
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'astring'"));
Assert.assertFalse(filter.match(message));
// test where LIKE operand matches
doPutStringProperty("MyString", "astring");
Assert.assertTrue(filter.match(message));
// test one character string
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'a'"));
doPutStringProperty("MyString", "a");
Assert.assertTrue(filter.match(message));
// test empty string
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE ''"));
doPutStringProperty("MyString", "");
Assert.assertTrue(filter.match(message));
// tests where operand does not match
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'astring'"));
// test with extra characters at beginning
doPutStringProperty("MyString", "NOTastring");
Assert.assertTrue(!filter.match(message));
// test with extra characters at end
doPutStringProperty("MyString", "astringNOT");
Assert.assertTrue(!filter.match(message));
// test with extra characters in the middle
doPutStringProperty("MyString", "astNOTring");
Assert.assertTrue(!filter.match(message));
// test where operand is entirely different
doPutStringProperty("MyString", "totally different");
Assert.assertTrue(!filter.match(message));
// test case sensitivity
doPutStringProperty("MyString", "ASTRING");
Assert.assertTrue(!filter.match(message));
// test empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(!filter.match(message));
// test lower-case 'like' operator?
}
@Test
public void testStringLikeUnderbarWildcard() throws Exception {
// test LIKE operator with the _ wildcard, which
// matches any single character
// first, some tests with the wildcard by itself
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '_'"));
Assert.assertFalse(filter.match(message));
// test match against single character
doPutStringProperty("MyString", "a");
Assert.assertTrue(filter.match(message));
// test match failure against multiple characters
doPutStringProperty("MyString", "aaaaa");
Assert.assertTrue(!filter.match(message));
// test match failure against the empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(!filter.match(message));
// next, tests with wildcard at the beginning of the string
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '_bcdf'"));
// test match at beginning of string
doPutStringProperty("MyString", "abcdf");
Assert.assertTrue(filter.match(message));
// match failure in first character after wildcard
doPutStringProperty("MyString", "aXcdf");
Assert.assertTrue(!filter.match(message));
// match failure in middle character
doPutStringProperty("MyString", "abXdf");
Assert.assertTrue(!filter.match(message));
// match failure in last character
doPutStringProperty("MyString", "abcdX");
Assert.assertTrue(!filter.match(message));
// match failure with empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at beginning
doPutStringProperty("MyString", "XXXabcdf");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at the end
doPutStringProperty("MyString", "abcdfXXX");
Assert.assertTrue(!filter.match(message));
// test that the _ wildcard does not match the 'empty' character
doPutStringProperty("MyString", "bcdf");
Assert.assertTrue(!filter.match(message));
// next, tests with wildcard at the end of the string
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'abcd_'"));
// test match at end of string
doPutStringProperty("MyString", "abcdf");
Assert.assertTrue(filter.match(message));
// match failure in first character before wildcard
doPutStringProperty("MyString", "abcXf");
Assert.assertTrue(!filter.match(message));
// match failure in middle character
doPutStringProperty("MyString", "abXdf");
Assert.assertTrue(!filter.match(message));
// match failure in first character
doPutStringProperty("MyString", "Xbcdf");
Assert.assertTrue(!filter.match(message));
// match failure with empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at beginning
doPutStringProperty("MyString", "XXXabcdf");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at the end
doPutStringProperty("MyString", "abcdfXXX");
Assert.assertTrue(!filter.match(message));
// test that the _ wildcard does not match the 'empty' character
doPutStringProperty("MyString", "abcd");
Assert.assertTrue(!filter.match(message));
// test match in middle of string
// next, tests with wildcard in the middle of the string
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'ab_df'"));
// test match in the middle of string
doPutStringProperty("MyString", "abcdf");
Assert.assertTrue(filter.match(message));
// match failure in first character before wildcard
doPutStringProperty("MyString", "aXcdf");
Assert.assertTrue(!filter.match(message));
// match failure in first character after wildcard
doPutStringProperty("MyString", "abcXf");
Assert.assertTrue(!filter.match(message));
// match failure in last character
doPutStringProperty("MyString", "abcdX");
Assert.assertTrue(!filter.match(message));
// match failure with empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at beginning
doPutStringProperty("MyString", "XXXabcdf");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at the end
doPutStringProperty("MyString", "abcdfXXX");
Assert.assertTrue(!filter.match(message));
// test that the _ wildcard does not match the 'empty' character
doPutStringProperty("MyString", "abdf");
Assert.assertTrue(!filter.match(message));
// test match failures
}
@Test
public void testNotLikeExpression() throws Exception {
// Should evaluate to false when the property MyString is not set
filter = FilterImpl.createFilter(new SimpleString("NOT (MyString LIKE '%')"));
Assert.assertFalse(filter.match(message));
}
@Test
public void testStringLikePercentWildcard() throws Exception {
// test LIKE operator with the % wildcard, which
// matches any sequence of characters
// note many of the tests are similar to those for _
// first, some tests with the wildcard by itself
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '%'"));
Assert.assertFalse(filter.match(message));
// test match against single character
doPutStringProperty("MyString", "a");
Assert.assertTrue(filter.match(message));
// test match against multiple characters
doPutStringProperty("MyString", "aaaaa");
Assert.assertTrue(filter.match(message));
doPutStringProperty("MyString", "abcdf");
Assert.assertTrue(filter.match(message));
// test match against the empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(filter.match(message));
// next, tests with wildcard at the beginning of the string
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '%bcdf'"));
// test match with single character at beginning of string
doPutStringProperty("MyString", "Xbcdf");
Assert.assertTrue(filter.match(message));
// match with multiple characters at beginning
doPutStringProperty("MyString", "XXbcdf");
Assert.assertTrue(filter.match(message));
// match failure in middle character
doPutStringProperty("MyString", "abXdf");
Assert.assertTrue(!filter.match(message));
// match failure in last character
doPutStringProperty("MyString", "abcdX");
Assert.assertTrue(!filter.match(message));
// match failure with empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at the end
doPutStringProperty("MyString", "abcdfXXX");
Assert.assertTrue(!filter.match(message));
// test that the % wildcard matches the empty string
doPutStringProperty("MyString", "bcdf");
Assert.assertTrue(filter.match(message));
// next, tests with wildcard at the end of the string
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'abcd%'"));
// test match of single character at end of string
doPutStringProperty("MyString", "abcdf");
Assert.assertTrue(filter.match(message));
// test match of multiple characters at end of string
doPutStringProperty("MyString", "abcdfgh");
Assert.assertTrue(filter.match(message));
// match failure in first character before wildcard
doPutStringProperty("MyString", "abcXf");
Assert.assertTrue(!filter.match(message));
// match failure in middle character
doPutStringProperty("MyString", "abXdf");
Assert.assertTrue(!filter.match(message));
// match failure in first character
doPutStringProperty("MyString", "Xbcdf");
Assert.assertTrue(!filter.match(message));
// match failure with empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at beginning
doPutStringProperty("MyString", "XXXabcdf");
Assert.assertTrue(!filter.match(message));
// test that the % wildcard matches the empty string
doPutStringProperty("MyString", "abcd");
Assert.assertTrue(filter.match(message));
// next, tests with wildcard in the middle of the string
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'ab%df'"));
// test match with single character in the middle of string
doPutStringProperty("MyString", "abXdf");
Assert.assertTrue(filter.match(message));
// test match with multiple characters in the middle of string
doPutStringProperty("MyString", "abXXXdf");
Assert.assertTrue(filter.match(message));
// match failure in first character before wildcard
doPutStringProperty("MyString", "aXcdf");
Assert.assertTrue(!filter.match(message));
// match failure in first character after wildcard
doPutStringProperty("MyString", "abcXf");
Assert.assertTrue(!filter.match(message));
// match failure in last character
doPutStringProperty("MyString", "abcdX");
Assert.assertTrue(!filter.match(message));
// match failure with empty string
doPutStringProperty("MyString", "");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at beginning
doPutStringProperty("MyString", "XXXabcdf");
Assert.assertTrue(!filter.match(message));
// match failure due to extra characters at the end
doPutStringProperty("MyString", "abcdfXXX");
Assert.assertTrue(!filter.match(message));
// test that the % wildcard matches the empty string
doPutStringProperty("MyString", "abdf");
Assert.assertTrue(filter.match(message));
}
@Test
public void testStringLikePunctuation() throws Exception {
// test proper handling of some punctuation characters.
// non-trivial since the underlying implementation might
// (and in fact currently does) use a general-purpose
// RE library, which has a different notion of which
// characters are wildcards
// the particular tests here are motivated by the
// wildcards of the current underlying RE engine,
// GNU regexp.
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'a^$b'"));
Assert.assertFalse(filter.match(message));
doPutStringProperty("MyString", "a^$b");
Assert.assertTrue(filter.match(message));
// this one has a double backslash since backslash
// is interpreted specially by Java
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'a\\dc'"));
doPutStringProperty("MyString", "a\\dc");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'a.c'"));
doPutStringProperty("MyString", "abc");
Assert.assertTrue(!filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '[abc]'"));
doPutStringProperty("MyString", "[abc]");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '[^abc]'"));
doPutStringProperty("MyString", "[^abc]");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '[a-c]'"));
doPutStringProperty("MyString", "[a-c]");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '[:alpha]'"));
doPutStringProperty("MyString", "[:alpha]");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(abc)'"));
doPutStringProperty("MyString", "(abc)");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE 'a|bc'"));
doPutStringProperty("MyString", "a|bc");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(abc)?'"));
doPutStringProperty("MyString", "(abc)?");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(abc)*'"));
doPutStringProperty("MyString", "(abc)*");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(abc)+'"));
doPutStringProperty("MyString", "(abc)+");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(abc){3}'"));
doPutStringProperty("MyString", "(abc){3}");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(abc){3,5}'"));
doPutStringProperty("MyString", "(abc){3,5}");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(abc){3,}'"));
doPutStringProperty("MyString", "(abc){3,}");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(?=abc)'"));
doPutStringProperty("MyString", "(?=abc)");
Assert.assertTrue(filter.match(message));
filter = FilterImpl.createFilter(new SimpleString("MyString LIKE '(?!abc)'"));
doPutStringProperty("MyString", "(?!abc)");
Assert.assertTrue(filter.match(message));
}
// TODO: re-implement this.
//
// @Test
// public void testStringLongToken() throws Exception
// {
// String largeString;
//
// {
// StringBuffer strBuffer = new StringBuffer();
// strBuffer.append('\'');
// for (int i = 0; i < 4800; i++)
// {
// strBuffer.append('a');
// }
// strBuffer.append('\'');
//
// largeString = strBuffer.toString();
// }
//
// FilterParser parse = new FilterParser();
// SimpleStringReader reader = new SimpleStringReader(new SimpleString(largeString));
// parse.ReInit(reader);
// // the server would fail at doing this when HORNETQ-545 wasn't solved
// parse.getNextToken();
// }
// Private -----------------------------------------------------------------------------------
private void doPutStringProperty(final String key, final String value) {
message.putStringProperty(new SimpleString(key), new SimpleString(value));
}
private void testInvalidFilter(final String filterString) throws Exception {
try {
filter = FilterImpl.createFilter(filterString);
Assert.fail("Should throw exception");
} catch (ActiveMQInvalidFilterExpressionException ife) {
//pass
} catch (ActiveMQException e) {
fail("Invalid exception type:" + e.getType());
}
}
private void testInvalidFilter(final SimpleString filterString) throws Exception {
try {
filter = FilterImpl.createFilter(filterString);
Assert.fail("Should throw exception");
} catch (ActiveMQInvalidFilterExpressionException ife) {
//pass
} catch (ActiveMQException e) {
fail("Invalid exception type:" + e.getType());
}
}
}