/* * RHQ Management Platform * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program 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 version 2 of the License. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.util; import static java.util.Arrays.asList; import static org.testng.Assert.assertEquals; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.testng.AssertJUnit; import org.testng.annotations.Test; import org.rhq.core.domain.criteria.Criteria; import org.rhq.core.domain.criteria.JPADriftCriteria; import org.rhq.core.domain.criteria.ResourceCriteria; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.core.domain.util.PageOrdering; public class CriteriaQueryTest { private static class FakeEntity { private int id; public FakeEntity(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } } private static class FakeEntityCriteria extends Criteria { @Override public Class<?> getPersistentClass() { return FakeEntity.class; } } private static class FakeCriteriaQueryExecutor implements CriteriaQueryExecutor<FakeEntity, FakeEntityCriteria> { //list of pagelists private List<PageList<FakeEntity>> pages = new ArrayList<PageList<FakeEntity>>(); //total size private int totalSize; // the pageControl instance to use private PageControl pc; // public FakeCriteriaQueryExecutor(int totalSize, PageControl pc) { this.totalSize = totalSize; this.pc = pc; } public void addPage(List<FakeEntity> entities) { int pageNumber = pages.size(); pages .add(new PageList<FakeEntity>(entities, totalSize, new PageControl(pageNumber, this.pc.getPageSize()))); } @Override public PageList<FakeEntity> execute(FakeEntityCriteria criteria) { int page = criteria.getPageNumber(); return pages.size() > page ? pages.get(page) : new PageList<FakeEntity>(new PageControl(page, pc.getPageSize())); } } @Test public void executeQueryThatReturnsASinglePageOfResults() { List<FakeEntity> expected = asList(new FakeEntity(1), new FakeEntity(2)); FakeCriteriaQueryExecutor queryExecutor = new FakeCriteriaQueryExecutor(2, PageControl.getUnlimitedInstance()); queryExecutor.addPage(expected); FakeEntityCriteria criteria = new FakeEntityCriteria(); CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>( criteria, queryExecutor); List<FakeEntity> actual = new ArrayList<FakeEntity>(); for (FakeEntity entity : query) { actual.add(entity); } assertEquals(actual, expected, "Failed to iterate over query results with a single page"); } @Test public void executeQueryThatReturnsMultiplePagesOfResults() { PageControl pc = new PageControl(0, 2); List<FakeEntity> expected = asList(new FakeEntity(1), new FakeEntity(2), new FakeEntity(3), new FakeEntity(4)); FakeCriteriaQueryExecutor queryExecutor = new FakeCriteriaQueryExecutor(4, pc); queryExecutor.addPage(expected.subList(0, 2)); queryExecutor.addPage(expected.subList(2, 4)); FakeEntityCriteria criteria = new FakeEntityCriteria(); //spinder 2-20-13: DO NOT use criteria.setPageControl(pc) here as it causes ignore of pageNumber/pageSize criteria.setPaging(pc.getPageNumber(), pc.getPageSize()); CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>( criteria, queryExecutor); List<FakeEntity> actual = new ArrayList<FakeEntity>(); for (FakeEntity entity : query) { actual.add(entity); } assertEquals(actual, expected); } /** This is like executeQueryThatReturnsMultiplePagesOfResults(), creates more * that two pages of ordered entries and iterates over them. This is to test * a nasty bug in CriteriaQuery where results beyond the first two pages were * not being parsed. */ @Test public void executeQueryThatReturnsTotalPagesOfResults() { //create page control to browse entries 100 at a time and start at page 0 int pageSize = 100; PageControl pc = new PageControl(0, pageSize); //Total size of result set is 500. int totalSize = 500; //Create list and populate with all entries. List<FakeEntity> total = new ArrayList<FakeEntity>(); for (int i = 0; i < totalSize; i++) { total.add(new FakeEntity(i)); } //build executor to parse a given list with using PageControl passed in FakeCriteriaQueryExecutor queryExecutor = new FakeCriteriaQueryExecutor(totalSize, pc); //add pages of results to simulate PageList results as returned by db queries //todo: spinder, modify to support fractional results below and add last page. int bucketCount = totalSize / pageSize;//number of full pages to list int start = 0; int end = pageSize; //add bucketCount pages of data to read from. for (int i = 0; i < bucketCount; i++) { //Ex. first two pages (0, 100), (100,200), etc. queryExecutor.addPage(total.subList(start, end)); start += pageSize; end += pageSize; } //build criteria and attach pageControl FakeEntityCriteria criteria = new FakeEntityCriteria(); //spinder 2-20-13:DO NOT use criteria.setPageControl(pc) here as it causes ignore of pageNumber/pageSize criteria.setPaging(pc.getPageNumber(), pc.getPageSize()); //?? So which pageControl has the right details? Criteria.pageControl? OR PageControl passed into the QueryExecutor. //Start off the initial query to page through the items in chunks defined by the pageControl instance CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>( criteria, queryExecutor); //Now iterate over the list and make sure that iteration happens in order as expected //monotonically increasing. int last = -1; for (FakeEntity entity : query) { //this fails with earlier bug in CriteriaQuery assertEquals(true, (last < entity.getId())); last = entity.getId(); } } @Test public void testIteratingOverQueryWithInconsistentResults_fewResultsOnLastPage() { PageControl pc = new PageControl(0, 100); int realResults = 490; FakeCriteriaQueryExecutor executor = prepareExecutor(realResults, 500, pc); FakeEntityCriteria criteria = new FakeEntityCriteria(); criteria.setPaging(pc.getPageNumber(), pc.getPageSize()); CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>( criteria, executor); //Now iterate over the list and make sure that iteration happens in order as expected //monotonically increasing. int num = 0; int last = -1; for (FakeEntity entity : query) { //this fails with earlier bug in CriteriaQuery assertEquals(true, (last < entity.getId())); last = entity.getId(); ++num; } assertEquals(num, realResults, "Unexpected number for results returned"); } @Test public void testIteratingOVerQueryWithInconsistentResults_emptyLastPage() { PageControl pc = new PageControl(0, 100); int realResults = 400; FakeCriteriaQueryExecutor executor = prepareExecutor(realResults, 500, pc); FakeEntityCriteria criteria = new FakeEntityCriteria(); criteria.setPaging(pc.getPageNumber(), pc.getPageSize()); CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>( criteria, executor); //Now iterate over the list and make sure that iteration happens in order as expected //monotonically increasing. int num = 0; int last = -1; for (FakeEntity entity : query) { //this fails with earlier bug in CriteriaQuery assertEquals(true, (last < entity.getId())); last = entity.getId(); ++num; } assertEquals(num, realResults, "Unexpected number for results returned"); } @Test public void testIteratingOverQueryWithInconsistentResults_tooManyResults() { PageControl pc = new PageControl(0, 100); int realResults = 551; FakeCriteriaQueryExecutor executor = prepareExecutor(realResults, 520, pc); FakeEntityCriteria criteria = new FakeEntityCriteria(); criteria.setPaging(pc.getPageNumber(), pc.getPageSize()); CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>( criteria, executor); //Now iterate over the list and make sure that iteration happens in order as expected //monotonically increasing. int num = 0; int last = -1; for (FakeEntity entity : query) { //this fails with earlier bug in CriteriaQuery assertEquals(true, (last < entity.getId())); last = entity.getId(); ++num; } assertEquals(num, realResults, "Unexpected number for results returned"); } @Test public void singleResultTest() { // This test doesn't really fit here but I;m adding it for convenience List<FakeEntity> result = null; try { FakeEntityCriteria.getSingleResult(result); assert false : "Should have thrown Runtime Exception"; } catch (RuntimeException e) { assert e.getMessage().contains("NoResultException"); } result = new ArrayList<FakeEntity>(2); try { FakeEntityCriteria.getSingleResult(result); assert false : "Should have thrown Runtime Exception"; } catch (RuntimeException e) { assert e.getMessage().contains("NoResultException"); } result.add(new FakeEntity(1)); try { FakeEntity r = FakeEntityCriteria.getSingleResult(result); assert r.getId() == 1 : "Should have retuned expected entity but returned: " + r; } catch (Throwable t) { assert false : "Should have returned single result"; } result.add(new FakeEntity(2)); try { FakeEntityCriteria.getSingleResult(result); assert false : "Should have thrown Runtime Exception"; } catch (RuntimeException e) { assert e.getMessage().contains("NonUniqueResultException"); } } @Test public void testAddSort() { try { JPADriftCriteria c = new JPADriftCriteria(); c.addSortId(PageOrdering.ASC); AssertJUnit.fail("Should have thrown exception"); } catch (UnsupportedOperationException e) { //expected } ResourceCriteria c = new ResourceCriteria(); c.addSortName(PageOrdering.ASC); assertEquals(2, CriteriaQueryGenerator.getPageControl(c).getOrderingFields().size()); assertEquals("name", CriteriaQueryGenerator.getPageControl(c).getOrderingFields().get(0).getField()); assertEquals("id", CriteriaQueryGenerator.getPageControl(c).getOrderingFields().get(1).getField()); } private FakeCriteriaQueryExecutor prepareExecutor(int realTotalSize, int reportedTotalSize, PageControl pc) { FakeCriteriaQueryExecutor executor = new FakeCriteriaQueryExecutor(reportedTotalSize, pc); List<FakeEntity> page = new ArrayList(pc.getPageSize()); for(int i = 0; i < realTotalSize; ++i) { if (i != 0 && i % pc.getPageSize() == 0) { executor.addPage(page); page.clear(); } page.add(new FakeEntity(i)); } //add the last page if (realTotalSize != reportedTotalSize) { executor.addPage(page); } return executor; } }