/** * diqube: Distributed Query Base. * * Copyright (C) 2015 Bastian Gloeckle * * This file is part of diqube. * * diqube is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.diqube.ui.analysis; import java.util.Arrays; import java.util.List; import org.diqube.diql.DiqlParseUtil; import org.diqube.diql.antlr.DiqlParser.DiqlStmtContext; import org.diqube.diql.request.ComparisonRequest; import org.diqube.diql.request.ExecutionRequest; import org.diqube.diql.visitors.SelectStmtVisitor; import org.diqube.name.FunctionBasedColumnNameBuilderFactory; import org.diqube.name.RepeatedColumnNameGenerator; import org.diqube.ui.analysis.QueryBuilder.QueryBuilderException; import org.testng.Assert; import org.testng.annotations.Test; /** * Tests {@link QueryBuilder}. * * <p> * This test works by comparing the parsing results of the diql string returned by the {@link QueryBuilder} and the * correct query. This is done because comparing the diql strings directly is not good, as the {@link QueryBuilder} can * and will add additional spaces/parenthesis etc, whcih though must not change the result of the query -> therefore we * compare the {@link ExecutionRequest}s generated by the queries: These need to be equal in order for the query to * produce the same result. We then just have to take care that our query will produce the same * {@link ComparisonRequest} tree as the generated one. * * @author Bastian Gloeckle */ public class QueryBuilderTest { private static final String TABLE = "table"; @Test public void simpleTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", null, Arrays.asList()); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test(expectedExceptions = QueryBuilderException.class) public void partialContainsFrom() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() from abc group by a order by a asc", null, Arrays.asList()); // WHEN generateQueryBuilder(analysis).build(); // THEN exception. } @Test public void singleWhereInQueryTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() where a = 5 group by a order by a asc", null, Arrays.asList()); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where a = 5 group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void singleWhereInSliceTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", null, Arrays.asList(new UiSliceDisjunction("a", Arrays.asList("5")))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where a = 5 group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void whereInSliceAndManualConjunctionTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", "b = 3", Arrays.asList(new UiSliceDisjunction("a", Arrays.asList("5")))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where a = 5 and b = 3 group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void singleWhereWithTwoValuesInSliceTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", null, Arrays.asList(new UiSliceDisjunction("a", Arrays.asList("5", "6")))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where a = 5 or a = 6 group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void singleWhereWithTwoValuesAndManualConjunctionInSliceTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", "b=3 or b=4", Arrays.asList(new UiSliceDisjunction("a", Arrays.asList("5", "6")))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where (a = 5 or a = 6) and (b = 3 or b = 4) group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void multipleWhereWithTwoValuesInSliceTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", null, Arrays.asList( new UiSliceDisjunction("a", Arrays.asList("5", "6")), new UiSliceDisjunction("b", Arrays.asList("3", "4")))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where (a = 5 or a = 6) and (b = 3 or b = 4) group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void multipleWhereWithSingleTwoValuesInSliceTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", null, Arrays .asList(new UiSliceDisjunction("a", Arrays.asList("5", "6")), new UiSliceDisjunction("b", Arrays.asList("3")))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where (a = 5 or a = 6) and b = 3 group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void multipleWhereWithSingleTwoValuesAndManualConjunctionInSliceTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", "c=5", Arrays .asList(new UiSliceDisjunction("a", Arrays.asList("5", "6")), new UiSliceDisjunction("b", Arrays.asList("3")))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where (a = 5 or a = 6) and b = 3 and c=5 group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void multipleWhereWithSingleTwoValuesAndManualConjunctionAndManualWhereInSliceTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() where d = 1 group by a order by a asc", "c=5", Arrays .asList(new UiSliceDisjunction("a", Arrays.asList("5", "6")), new UiSliceDisjunction("b", Arrays.asList("3")))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN String expectedDiql = "select a, count() from " + TABLE + " where d=1 and ((a = 5 or a = 6) and b = 3 and c=5) group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } @Test public void emptyDisjunctionValuesTest() throws QueryBuilderException { // GIVEN UiAnalysis analysis = createAnalysis("select a, count() group by a order by a asc", null, Arrays .asList(new UiSliceDisjunction("a", Arrays.asList("5", "6")), new UiSliceDisjunction("b", Arrays.asList()))); // WHEN String queryBuilderDiql = generateQueryBuilder(analysis).build(); ExecutionRequest queryBuilderRequest = parse(queryBuilderDiql); // THEN // UiSliceDisjunction "b" is ignored, since it does not have any value! This is needed because in the UI we can // remove the last "value" from a disjunction easily, but most probably do not want that disjunction to evaluate to // "false" and no rows being returned therefore. String expectedDiql = "select a, count() from " + TABLE + " where a = 5 or a = 6 group by a order by a asc"; ExecutionRequest expectedRequest = parse(expectedDiql); Assert.assertEquals(queryBuilderRequest, expectedRequest, "Built query found to be not equal to the genrated one. Expected: '" + expectedDiql + "' but was '" + queryBuilderDiql + "'"); } private QueryBuilder generateQueryBuilder(UiAnalysis analysis) { return new QueryBuilder().withAnalysis(analysis).withQuery(analysis.getQubes().get(0).getQueries().get(0)) .withSlice(analysis.getSlices().get(0)); } private UiAnalysis createAnalysis(String queryPartialDiql, String sliceManualConjunction, List<UiSliceDisjunction> sliceDisjunctions) { UiAnalysis analysis = new UiAnalysis("analysisId", "analysis", TABLE, "testUser", 0L); UiSlice slice = new UiSlice("sliceId", "slice", sliceDisjunctions); slice.setManualConjunction(sliceManualConjunction); analysis.getSlices().add(slice); analysis.getQubes().add(new UiQube("queryId", "query", "sliceId")); analysis.getQubes().iterator().next().getQueries() .add(new UiQuery("queryId", "queryName", queryPartialDiql, UiQuery.DISPLAY_TYPE_TABLE)); return analysis; } private ExecutionRequest parse(String diql) { DiqlStmtContext ctx = DiqlParseUtil.parseWithAntlr(diql); return ctx .accept(new SelectStmtVisitor(new RepeatedColumnNameGenerator(), new FunctionBasedColumnNameBuilderFactory())); } }