/**
* 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.ambari.server.api.predicate;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.Test;
/**
* QueryLexer unit tests
*/
public class QueryLexerTest {
@Test
public void testTokens_simple() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "a"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
listTokens.add(new Token(Token.TYPE.BRACKET_OPEN, "("));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "<="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "b"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "|"));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, ">"));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "c"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "3"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("a=1&(b<=2|c>3)");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_multipleBrackets() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "<"));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "a"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
listTokens.add(new Token(Token.TYPE.BRACKET_OPEN, "("));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "<="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "b"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
listTokens.add(new Token(Token.TYPE.BRACKET_OPEN, "("));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, ">="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "c"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "3"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "|"));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "!="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "d"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "4"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("a<1&(b<=2&(c>=3|d!=4))");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testUnaryNot() throws Exception {
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("!foo<5");
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.LOGICAL_UNARY_OPERATOR, "!"));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "<"));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "5"));
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testInOperator() throws Exception {
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("foo.in(one, two, 3)");
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".in("));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "one, two, 3"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testIsEmptyOperator() throws Exception {
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("category1.isEmpty()");
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".isEmpty("));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "category1"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignoreFieldsSyntax___noPredicate() throws InvalidQueryException {
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("fields=foo,bar");
assertEquals(0, tokens.length);
}
@Test
public void testTokens_ignoreFieldsSyntax___fieldsFirst() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("fields=foo,bar&foo=1");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignoreFieldsSyntax___fieldsLast() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("foo=1&fields=foo,bar");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignoreFormatSyntax___noPredicate() throws InvalidQueryException {
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("format=default");
assertEquals(0, tokens.length);
}
@Test
public void testTokens_ignoreFormatSyntax___formatFirst() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("format=default&foo=1");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignoreFormatSyntax___formatLast() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("foo=1&format=foo");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignoreUnderscoreSyntax___noPredicate() throws InvalidQueryException {
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("_=1");
assertEquals(0, tokens.length);
}
@Test
public void testTokens_ignoreUnderscoreSyntax___fieldsFirst() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("_=111111&foo=1");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignoreUnderscoreSyntax___fieldsLast() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("foo=1&_=11111");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignore__multipleIgnoreFields() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("fields=a/b&foo=1&_=5555555");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignore__multipleConsecutiveIgnoreFields() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("foo=1&fields=a/b&_=5555555");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignore__multipleConsecutiveIgnoreFields2() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("fields=a/b&_=5555555&foo=1");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignore__fieldsMiddle() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "bar"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("foo=1&fields=a/b&bar=2");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignore__fieldsMiddle2() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "bar"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("foo=1&fields=a/b,c&_=123&bar=2");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_ignore__userDefined() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "bar"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
QueryLexer lexer = new QueryLexer();
Set<String> propertiesToIgnore = new HashSet<>();
propertiesToIgnore.add("ignore1");
propertiesToIgnore.add("otherIgnore");
propertiesToIgnore.add("ba");
propertiesToIgnore.add("ple");
Token[] tokens = lexer.tokens("ba=gone&foo=1&ignore1=pleaseIgnoreMe&fields=a/b&bar=2&otherIgnore=byebye",
propertiesToIgnore);
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_invalidRelationalOp() {
try {
new QueryLexer().tokens("foo=1&bar|5");
fail("Expected InvalidQueryException due to invalid relational op");
} catch (InvalidQueryException e) {
//expected
}
}
@Test
public void testTokens_invalidLogicalOp() {
try {
new QueryLexer().tokens("foo=1<5=2");
fail("Expected InvalidQueryException due to invalid logical op");
} catch (InvalidQueryException e) {
//expected
}
}
@Test
public void testTokens_invalidLogicalOp2() {
try {
new QueryLexer().tokens("foo=1&&5=2");
fail("Expected InvalidQueryException due to invalid logical op");
} catch (InvalidQueryException e) {
//expected
}
}
@Test
public void testTokens_matchesRegexp_simple() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".matches("));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "StackConfigurations/property_type"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "(.*USER.*)|(.*GROUP.*)"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("StackConfigurations/property_type.matches((.*USER.*)|(.*GROUP.*))");
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test
public void testTokens_matchesRegexp() throws InvalidQueryException {
List<Token> listTokens = new ArrayList<>();
listTokens.add(new Token(Token.TYPE.BRACKET_OPEN, "("));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".matches("));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "StackConfigurations/property_type"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "(([^=])|=|!=),.in(&).*USER.*.isEmpty(a).matches(b)"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "|"));
listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".matches("));
listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "StackConfigurations/property_type"));
listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "fields format to from .*GROUP.*"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
QueryLexer lexer = new QueryLexer();
Token[] tokens = lexer.tokens("(StackConfigurations/property_type.matches((([^=])|=|!=),.in(&).*USER.*" +
".isEmpty(a).matches(b))|StackConfigurations/property_type.matches(fields format to from .*GROUP.*))");
assertArrayEquals("All characters between \".matches(\" and corresponding closing \")\" bracket should " +
"come to VALUE_OPERAND.", listTokens.toArray(new Token[listTokens.size()]), tokens);
}
@Test(expected = InvalidQueryException.class)
public void testTokens_matchesRegexpInvalidQuery() throws InvalidQueryException {
QueryLexer lexer = new QueryLexer();
lexer.tokens("StackConfigurations/property_type.matches((.*USER.*)|(.*GROUP.*)");
}
@Test(expected = InvalidQueryException.class)
public void testTokens_matchesRegexpInvalidQuery2() throws InvalidQueryException {
QueryLexer lexer = new QueryLexer();
lexer.tokens("StackConfigurations/property_type.matches((.*USER.*)|(.*GROUP.*)|StackConfigurations/property_type.matches(.*GROUP.*)");
}
}