org.graylog2.search.SearchQueryParserTest.java Source code

Java tutorial

Introduction

Here is the source code for org.graylog2.search.SearchQueryParserTest.java

Source

/**
 * This file is part of Graylog.
 *
 * Graylog is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Graylog is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Graylog.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.graylog2.search;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Before;
import org.junit.Test;
import org.mongojack.DBQuery;
import org.mongojack.internal.query.CollectionQueryCondition;
import org.mongojack.internal.query.CompoundQueryCondition;
import org.mongojack.internal.query.QueryCondition;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

import static org.assertj.core.api.Assertions.assertThat;

public class SearchQueryParserTest {

    @Before
    public void setUp() throws Exception {
    }

    @Test
    public void explicitAllowedField() throws Exception {
        SearchQueryParser parser = new SearchQueryParser("defaultfield", ImmutableSet.of("name", "id"));
        final SearchQuery query = parser.parse("name:foo");
        final Multimap<String, SearchQueryParser.FieldValue> queryMap = query.getQueryMap();

        assertThat(queryMap.size()).isEqualTo(1);
        assertThat(queryMap.get("name")).containsOnly(new SearchQueryParser.FieldValue("foo", false));
        assertThat(query.hasDisallowedKeys()).isFalse();
        assertThat(query.getDisallowedKeys()).isEmpty();

        final DBQuery.Query dbQuery = query.toDBQuery();
        final Collection<String> fieldNamesUsed = extractFieldNames(dbQuery.conditions());
        assertThat(fieldNamesUsed).containsExactly("name");
    }

    @Test
    public void disallowedField() {
        SearchQueryParser parser = new SearchQueryParser("defaultfield", ImmutableSet.of("name", "id"));
        final SearchQuery query = parser.parse("notallowed:foo");
        final Multimap<String, SearchQueryParser.FieldValue> queryMap = query.getQueryMap();

        assertThat(queryMap.size()).isEqualTo(1);
        assertThat(queryMap.get("defaultfield")).containsOnly(new SearchQueryParser.FieldValue("foo", false));
        assertThat(query.hasDisallowedKeys()).isTrue();
        assertThat(query.getDisallowedKeys()).containsExactly("notallowed");
        final DBQuery.Query dbQuery = query.toDBQuery();
        final Collection<String> fieldNames = extractFieldNames(dbQuery.conditions());
        assertThat(fieldNames).containsExactly("defaultfield");
    }

    @Test
    public void mappedFields() {
        SearchQueryParser parser = new SearchQueryParser("defaultfield", ImmutableMap.of("name",
                SearchQueryField.create("index_name"), "id", SearchQueryField.create("real_id")));

        final SearchQuery query = parser.parse("name:foo id:1234");
        final Multimap<String, SearchQueryParser.FieldValue> queryMap = query.getQueryMap();

        assertThat(queryMap.size()).isEqualTo(2);
        assertThat(queryMap.keySet()).containsOnly("index_name", "real_id");
        assertThat(queryMap.get("index_name")).containsOnly(new SearchQueryParser.FieldValue("foo", false));
        assertThat(queryMap.get("real_id")).containsOnly(new SearchQueryParser.FieldValue("1234", false));
        assertThat(query.hasDisallowedKeys()).isFalse();

        final DBQuery.Query dbQuery = query.toDBQuery();
        final Collection<String> fieldNames = extractFieldNames(dbQuery.conditions());
        assertThat(fieldNames).containsOnly("index_name", "real_id");
    }

    private Collection<String> extractFieldNames(Set<Map.Entry<String, QueryCondition>> conditions) {
        final ImmutableSet.Builder<String> names = ImmutableSet.builder();

        // recurse into the tree, conveniently there's no visitor we can use, so it's manual
        conditions.forEach(entry -> {
            final String op = entry.getKey();
            if (!op.startsWith("$")) {
                names.add(op);
            }
            final QueryCondition queryCondition = entry.getValue();
            if (queryCondition instanceof CollectionQueryCondition) {
                names.addAll(extractFieldNames(((CollectionQueryCondition) queryCondition).getValues().stream()
                        .map(qc -> Maps.immutableEntry("$dummy", qc)).collect(Collectors.toSet())));
            } else if (queryCondition instanceof CompoundQueryCondition) {
                names.addAll(extractFieldNames(((CompoundQueryCondition) queryCondition).getQuery().conditions()));
            }
        });

        return names.build();
    }

    @Test
    public void extractOperator() throws Exception {
        final SearchQueryParser parser = new SearchQueryParser("defaultfield",
                ImmutableMap.of("id", SearchQueryField.create("real_id"), "date",
                        SearchQueryField.create("created_at", SearchQueryField.Type.DATE)));

        final SearchQueryOperator defaultOp = SearchQueryOperators.REGEXP;

        checkQuery(parser, "", "", defaultOp);
        checkQuery(parser, "h", "h", defaultOp);
        checkQuery(parser, "he", "he", defaultOp);
        checkQuery(parser, "hel", "hel", defaultOp);
        checkQuery(parser, "hello", "hello", defaultOp);

        checkQuery(parser, ">=2017-03-23", "2017-03-23", SearchQueryOperators.GREATER_EQUALS);
        checkQuery(parser, ">= 2017-03-23", "2017-03-23", SearchQueryOperators.GREATER_EQUALS);
        checkQuery(parser, "<=2017-03-23", "2017-03-23", SearchQueryOperators.LESS_EQUALS);
        checkQuery(parser, "<=  2017-03-23", "2017-03-23", SearchQueryOperators.LESS_EQUALS);
        checkQuery(parser, ">2017-03-23", "2017-03-23", SearchQueryOperators.GREATER);
        checkQuery(parser, ">    2017-03-23", "2017-03-23", SearchQueryOperators.GREATER);
        checkQuery(parser, "<2017-03-23", "2017-03-23", SearchQueryOperators.LESS);
        checkQuery(parser, "< 2017-03-23", "2017-03-23", SearchQueryOperators.LESS);
        checkQuery(parser, "=~ hello", "hello", SearchQueryOperators.REGEXP);
        checkQuery(parser, "=  hello", "hello", SearchQueryOperators.EQUALS);
    }

    private void checkQuery(SearchQueryParser parser, String query, String expectedQuery,
            SearchQueryOperator expectedOp) {
        final Pair<String, SearchQueryOperator> pair = parser.extractOperator(query, SearchQueryOperators.REGEXP);
        assertThat(pair.getLeft()).isEqualTo(expectedQuery);
        assertThat(pair.getRight()).isEqualTo(expectedOp);
    }

    @Test
    public void querySplitterMatcher() throws Exception {
        final SearchQueryParser parser = new SearchQueryParser("defaultfield",
                ImmutableMap.of("id", SearchQueryField.create("real_id"), "date",
                        SearchQueryField.create("created_at", SearchQueryField.Type.DATE)));

        final String queryString = "from:\"2017-10-02 12:07:01.345\" hello:world foo:=~\"bar baz\"";
        final Matcher matcher = parser.querySplitterMatcher(queryString);

        assertThat(matcher.find()).isTrue();
        assertThat(matcher.group()).isEqualTo("from:\"2017-10-02 12:07:01.345\"");
        assertThat(matcher.find()).isTrue();
        assertThat(matcher.group()).isEqualTo("hello:world");
        assertThat(matcher.find()).isTrue();
        assertThat(matcher.group()).isEqualTo("foo:=~\"bar baz\"");
        assertThat(matcher.find()).isFalse();
    }

    @Test
    public void createFieldValue() throws Exception {
        final ImmutableMap<String, SearchQueryField> fields = ImmutableMap.of("id",
                SearchQueryField.create("real_id"), "date",
                SearchQueryField.create("created_at", SearchQueryField.Type.DATE));
        final SearchQueryParser parser = new SearchQueryParser("defaultfield", fields);

        final SearchQueryParser.FieldValue v1 = parser.createFieldValue(fields.get("id"), "abc", false);
        assertThat(v1.getOperator()).isEqualTo(SearchQueryParser.DEFAULT_OPERATOR);
        assertThat(v1.getValue()).isEqualTo("abc");
        assertThat(v1.isNegate()).isFalse();

        final SearchQueryParser.FieldValue v2 = parser.createFieldValue(fields.get("id"), "=abc", true);
        assertThat(v2.getOperator()).isEqualTo(SearchQueryOperators.EQUALS);
        assertThat(v2.getValue()).isEqualTo("abc");
        assertThat(v2.isNegate()).isTrue();

        final SearchQueryParser.FieldValue v3 = parser.createFieldValue(fields.get("date"), ">=2017-03-01", false);
        assertThat(v3.getOperator()).isEqualTo(SearchQueryOperators.GREATER_EQUALS);
        assertThat(v3.getValue()).isEqualTo(new DateTime(2017, 3, 1, 0, 0, DateTimeZone.UTC));
        assertThat(v3.isNegate()).isFalse();

        final SearchQueryParser.FieldValue v4 = parser.createFieldValue(fields.get("date"), ">=2017-03-01 12:12:12",
                false);
        assertThat(v4.getOperator()).isEqualTo(SearchQueryOperators.GREATER_EQUALS);
        assertThat(v4.getValue()).isEqualTo(new DateTime(2017, 3, 1, 12, 12, 12, DateTimeZone.UTC));
        assertThat(v4.isNegate()).isFalse();

        final SearchQueryParser.FieldValue v5 = parser.createFieldValue(fields.get("date"),
                "\">=2017-03-01 12:12:12\"", false);
        assertThat(v5.getOperator()).isEqualTo(SearchQueryOperators.GREATER_EQUALS);
        assertThat(v5.getValue()).isEqualTo(new DateTime(2017, 3, 1, 12, 12, 12, DateTimeZone.UTC));
        assertThat(v5.isNegate()).isFalse();
    }
}