/* * Copyright 2012 the original author or authors. * * Licensed 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.springframework.data.gemfire.repository.query; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.data.gemfire.repository.query.QueryString.HINT_PATTERN; import static org.springframework.data.gemfire.repository.query.QueryString.IMPORT_PATTERN; import static org.springframework.data.gemfire.repository.query.QueryString.LIMIT_PATTERN; import static org.springframework.data.gemfire.repository.query.QueryString.TRACE_PATTERN; import java.util.Arrays; import java.util.regex.Pattern; import org.apache.geode.cache.Region; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.data.domain.Sort; import org.springframework.data.gemfire.repository.sample.Person; import org.springframework.data.gemfire.repository.sample.RootUser; /** * Test suite of test cases testing the contract and functionality of the {@link QueryString} class. * * @author Oliver Gierke * @author John Blum * @see org.junit.Test * @see org.mockito.Mock * @see org.springframework.data.gemfire.repository.query.QueryString */ @RunWith(MockitoJUnitRunner.class) public class QueryStringUnitTests { @Rule public ExpectedException exception = ExpectedException.none(); @Mock @SuppressWarnings("rawtypes") Region region; protected Sort.Order newSortOrder(String property) { return newSortOrder(property, Sort.Direction.ASC); } protected Sort.Order newSortOrder(String property, Sort.Direction direction) { return new Sort.Order(direction, property); } protected Sort newSort(Sort.Order... orders) { return new Sort(orders); } @Test public void createQueryStringWithDomainType() { assertThat(new QueryString(Person.class).toString()).isEqualTo("SELECT * FROM /Person"); } @Test public void createQueryStringWithDomainTypeHavingCount() { assertThat(new QueryString(Person.class, true).toString()).isEqualTo("SELECT count(*) FROM /Person"); } @Test public void createQueryStringWithNullDomainType() { exception.expect(IllegalArgumentException.class); exception.expectCause(is(nullValue(Throwable.class))); exception.expectMessage(is(equalTo("domainType must not be null"))); new QueryString((Class<?>) null); } @Test public void createQueryStringWithQuery() { String query = "SELECT * FROM /Example"; assertThat(new QueryString(query).toString()).isEqualTo(query); } @Test public void createQueryStringWithUnspecifiedQueryThrowsIllegalArgumentException() { assertUnspecifiedQueryThrowsIllegalArgumentException(""); assertUnspecifiedQueryThrowsIllegalArgumentException(" "); assertUnspecifiedQueryThrowsIllegalArgumentException(null); } protected void assertUnspecifiedQueryThrowsIllegalArgumentException(String query) { exception.expect(IllegalArgumentException.class); exception.expectCause(is(nullValue(Throwable.class))); exception.expectMessage(is(equalTo("An OQL Query must be specified"))); new QueryString(query); } @Test public void hintPatternMatches() { assertThat(matches(HINT_PATTERN, "<HINT 'ExampleIndex'>")).isTrue(); assertThat(matches(HINT_PATTERN, "<HINT 'IdIdx'> SELECT * FROM /Example WHERE id = $1")).isTrue(); assertThat(matches(HINT_PATTERN, "<HINT 'LastNameIdx', 'BirthDateIdx'> SELECT * FROM /Person WHERE lastName = $1 AND birthDate = $2")).isTrue(); } @Test public void hintPatternNoMatches() { assertThat(matches(HINT_PATTERN, "HINT")).isFalse(); assertThat(matches(HINT_PATTERN, "<HINT>")).isFalse(); assertThat(matches(HINT_PATTERN, "<HINT ''>")).isFalse(); assertThat(matches(HINT_PATTERN, "<HINT ' '>")).isFalse(); assertThat(matches(HINT_PATTERN, "<HINT IdIdx>")).isFalse(); assertThat(matches(HINT_PATTERN, "<HINT LastNameIdx, FirstNameIdx>")).isFalse(); assertThat(matches(HINT_PATTERN, "SELECT * FROM /Example")).isFalse(); assertThat(matches(HINT_PATTERN, "SELECT * FROM /Hint")).isFalse(); assertThat(matches(HINT_PATTERN, "SELECT x.hint FROM /Clues x WHERE x.hint > $1")).isFalse(); } @Test public void importPatternMatches() { assertThat(matches(IMPORT_PATTERN, "IMPORT *;")).isTrue(); assertThat(matches(IMPORT_PATTERN, "IMPORT org.example.*;")).isTrue(); assertThat(matches(IMPORT_PATTERN, "IMPORT org.example.Type;")).isTrue(); assertThat(matches(IMPORT_PATTERN, "IMPORT org.example.app.domain.DomainType; SELECT * FROM /DomainType")).isTrue(); } @Test public void importPatternNoMatches() { assertThat(matches(IMPORT_PATTERN, "IMPORT")).isFalse(); assertThat(matches(IMPORT_PATTERN, "IMPORT ;")).isFalse(); assertThat(matches(IMPORT_PATTERN, "IMPORT *")).isFalse(); assertThat(matches(IMPORT_PATTERN, "IMPORT *:")).isFalse(); assertThat(matches(IMPORT_PATTERN, "SELECT * FROM /Example")).isFalse(); } @Test public void limitPatternMatches() { assertThat(matches(LIMIT_PATTERN, "LIMIT 0")).isTrue(); assertThat(matches(LIMIT_PATTERN, "LIMIT 1")).isTrue(); assertThat(matches(LIMIT_PATTERN, "LIMIT 10")).isTrue(); assertThat(matches(LIMIT_PATTERN, "SELECT * FROM /Example LIMIT 10")).isTrue(); assertThat(matches(LIMIT_PATTERN, "SELECT * FROM /Example WHERE id = $1 LIMIT 10")).isTrue(); } @Test public void limitPatternNoMatches() { assertThat(matches(LIMIT_PATTERN, "LIMIT")).isFalse(); assertThat(matches(LIMIT_PATTERN, "LIMIT lO")).isFalse(); assertThat(matches(LIMIT_PATTERN, "LIMIT AF")).isFalse(); assertThat(matches(LIMIT_PATTERN, "LIMIT ten")).isFalse(); assertThat(matches(LIMIT_PATTERN, "SELECT * FROM /Example LIMIT")).isFalse(); assertThat(matches(LIMIT_PATTERN, "SELECT * FROM /Example WHERE id = $1 LIM 10")).isFalse(); } @Test public void tracePatternMatches() { assertThat(matches(TRACE_PATTERN, "<TRACE>")).isTrue(); assertThat(matches(TRACE_PATTERN, "<TRACE> SELECT * FROM /Example")).isTrue(); assertThat(matches(TRACE_PATTERN, "<TRACE>SELECT * FROM /Example")).isTrue(); assertThat(matches(TRACE_PATTERN, "SELECT * FROM /Example<TRACE>")).isTrue(); } @Test public void tracePatternNoMatches() { assertThat(matches(TRACE_PATTERN, "TRACE")).isFalse(); assertThat(matches(TRACE_PATTERN, "TRACE SELECT * FROM /Example")).isFalse(); assertThat(matches(TRACE_PATTERN, "<TRACE SELECT * FROM /Example>")).isFalse(); } protected boolean matches(Pattern pattern, String value) { return pattern.matcher(value).find(); } // SGF-251 @Test public void replacesDomainTypeSimpleNameWithRegionPathCorrectly() { QueryString query = new QueryString(Person.class); when(region.getFullPath()).thenReturn("/foo/bar"); assertThat(query.forRegion(Person.class, region).toString()).isEqualTo("SELECT * FROM /foo/bar"); verify(region, times(1)).getFullPath(); } // SGF-156, SGF-251 @Test public void replacesFromClauseWithRegionPathCorrectly() { QueryString query = new QueryString("SELECT * FROM /Persons p WHERE p.lastname = $1"); when(region.getFullPath()).thenReturn("/People"); assertThat(query.forRegion(Person.class, region).toString()) .isEqualTo("SELECT * FROM /People p WHERE p.lastname = $1"); verify(region, times(1)).getFullPath(); } // SGF-252 @Test public void replacesFullyQualifiedSubRegionPathWithRegionPathCorrectly() { QueryString query = new QueryString("SELECT * FROM //Local/Root/Users u WHERE u.username = $1"); when(region.getFullPath()).thenReturn("/Remote/Root/Users"); assertThat(query.forRegion(RootUser.class, region).toString()) .isEqualTo("SELECT * FROM /Remote/Root/Users u WHERE u.username = $1"); verify(region, times(1)).getFullPath(); } @Test public void bindsInValuesCorrectly() { QueryString query = new QueryString("SELECT * FROM /Collection WHERE elements IN SET $1"); assertThat(query.bindIn(Arrays.asList(1, 2, 3)).toString()) .isEqualTo("SELECT * FROM /Collection WHERE elements IN SET ('1', '2', '3')"); } @Test public void detectsInParameterIndexesCorrectly() { QueryString query = new QueryString("SELECT * FROM /Example WHERE values IN SET $1 OR IN SET $2"); assertThat(query.getInParameterIndexes()).isEqualTo(Arrays.asList(1, 2)); } @Test public void addsNoOrderByClauseCorrectly() { QueryString query = new QueryString("SELECT * FROM /People p").orderBy(null); assertThat(query.toString()).isEqualTo("SELECT * FROM /People p"); } @Test public void addsOrderByClauseCorrectly() { QueryString query = new QueryString("SELECT * FROM /People p WHERE p.lastName = $1") .orderBy(newSort(newSortOrder("lastName", Sort.Direction.DESC), newSortOrder("firstName"))); assertThat(query.toString()) .isEqualTo("SELECT DISTINCT * FROM /People p WHERE p.lastName = $1 ORDER BY lastName DESC, firstName ASC"); } @Test public void addsSingleOrderByClauseCorrectly() { QueryString query = new QueryString("SELECT DISTINCT p.lastName FROM /People p WHERE p.firstName = $1") .orderBy(newSort(newSortOrder("lastName"))); assertThat(query.toString()) .isEqualTo("SELECT DISTINCT p.lastName FROM /People p WHERE p.firstName = $1 ORDER BY lastName ASC"); } @Test public void withHints() { assertThat(new QueryString("SELECT * FROM /Example").withHints("IdIdx").toString()) .isEqualTo("<HINT 'IdIdx'> SELECT * FROM /Example"); assertThat(new QueryString("SELECT * FROM /Example").withHints("IdIdx", "SpatialIdx", "TxDateIdx").toString()) .isEqualTo("<HINT 'IdIdx', 'SpatialIdx', 'TxDateIdx'> SELECT * FROM /Example"); } @Test public void withoutHints() { QueryString expectedQueryString = new QueryString("SELECT * FROM /Example"); assertThat(expectedQueryString.withHints()).isSameAs(expectedQueryString); assertThat(expectedQueryString.withHints((String[]) null)).isSameAs(expectedQueryString); } @Test public void withImport() { assertThat(new QueryString("SELECT * FROM /People").withImport("org.example.app.domain.Person").toString()) .isEqualTo("IMPORT org.example.app.domain.Person; SELECT * FROM /People"); } @Test public void withoutImport() { QueryString expectedQueryString = new QueryString("SELECT * FROM /Example"); assertThat(expectedQueryString.withImport(null)).isSameAs(expectedQueryString); assertThat(expectedQueryString.withImport("")).isSameAs(expectedQueryString); assertThat(expectedQueryString.withImport(" ")).isSameAs(expectedQueryString); } @Test public void withLimit() { assertThat(new QueryString("SELECT * FROM /Example").withLimit(10).toString()) .isEqualTo("SELECT * FROM /Example LIMIT 10"); assertThat(new QueryString("SELECT * FROM /Example").withLimit(0).toString()) .isEqualTo("SELECT * FROM /Example LIMIT 0"); assertThat(new QueryString("SELECT * FROM /Example").withLimit(-5).toString()) .isEqualTo("SELECT * FROM /Example LIMIT -5"); } @Test public void withoutLimit() { QueryString expectedQueryString = new QueryString("SELECT * FROM /Example"); assertThat(expectedQueryString.withLimit(null)).isSameAs(expectedQueryString); } @Test public void withTrace() { assertThat(new QueryString("SELECT * FROM /Example").withTrace().toString()) .isEqualTo("<TRACE> SELECT * FROM /Example"); } @Test public void withHintAndTrace() { assertThat(new QueryString("SELECT * FROM /Example").withHints("IdIdx").withTrace().toString()) .isEqualTo("<TRACE> <HINT 'IdIdx'> SELECT * FROM /Example"); } @Test public void withHintImportLimitAndTrace() { QueryString query = new QueryString("SELECT * FROM /Example"); assertThat(query.withImport("org.example.domain.Type").withHints("IdIdx", "NameIdx").withLimit(20).withTrace().toString()) .isEqualTo("<TRACE> <HINT 'IdIdx', 'NameIdx'> IMPORT org.example.domain.Type; SELECT * FROM /Example LIMIT 20"); } }