/**
* 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()));
}
}