/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wps; import static org.junit.Assert.*; import java.io.IOException; import java.util.List; import org.geoserver.wps.executor.ExecutionStatus; import org.geoserver.wps.executor.ProcessState; import org.geotools.data.Query; import org.geotools.factory.CommonFactoryFinder; import org.geotools.feature.NameImpl; import org.geotools.filter.text.cql2.CQL; import org.geotools.filter.text.cql2.CQLException; import org.geotools.filter.text.ecql.ECQL; import org.junit.Before; import org.junit.Test; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.sort.SortBy; import org.opengis.filter.sort.SortOrder; /** * Base class for status store tests * * @author Andrea Aime - GeoSolutions */ public abstract class AbstractProcessStoreTest { static final FilterFactory2 FF = CommonFactoryFinder.getFilterFactory2(); protected ProcessStatusStore store; protected ExecutionStatus s1; protected ExecutionStatus s2; protected ExecutionStatus s3; protected ExecutionStatus s4; @Before public void setup() throws IOException { // prepare a few statues this.store = buildStore(); s1 = new ExecutionStatus(new NameImpl("test1"), "abcde1", false); s2 = new ExecutionStatus(new NameImpl("test2"), "abcde2", false); s2.setException(new Exception()); s3 = new ExecutionStatus(new NameImpl("test3"), "abcde3", false); s3.setPhase(ProcessState.RUNNING); s3.setProgress(50f); s3.setTask("Having fun"); s4 = new ExecutionStatus(new NameImpl("test3"), "abcde4", false); s4.setPhase(ProcessState.RUNNING); s4.setProgress(70f); s4.setTask("Fun is almost over"); fillStore(); } /** * Builds the status store for this test * * * @throws IOException */ protected abstract ProcessStatusStore buildStore() throws IOException; /** * Puts all the test statuses in the store */ protected void fillStore() { store.save(s1); store.save(s2); store.save(s3); store.save(s4); } @Test public void testFilter() throws CQLException { // simple filters checkFiltered(store, query("processName = 'test1'"), s1); checkFiltered(store, query("phase = 'RUNNING'"), s3, s4); checkFiltered(store, query("progress > 30"), s3, s4); // force a post filter checkFiltered(store, query("strToLowerCase(phase) = 'running'"), s3, s4); checkFiltered(store, query("strToLowerCase(phase) = 'running' AND progress > 30"), s3, s4); } @Test public void testPaging() throws CQLException { // simple filters with some paging, sometimes odd checkFiltered(store, query("processName = 'test1'", 0, 1), s1); checkFiltered(store, query("processName = 'test1'", 1, 1)); checkFiltered(store, query("phase = 'RUNNING'", 0, 1, asc("progress")), s3); checkFiltered(store, query("phase = 'RUNNING'", 1, 1, asc("progress")), s4); checkFiltered(store, query("phase = 'RUNNING'", 0, 1, desc("progress")), s4); checkFiltered(store, query("phase = 'RUNNING'", 1, 1, desc("progress")), s3); // force a post filter String lowercaseRunning = "strToLowerCase(phase) = 'running'"; checkFiltered(store, query(lowercaseRunning), s3, s4); checkFiltered(store, query(lowercaseRunning, 0, 1, asc("progress")), s3); checkFiltered(store, query(lowercaseRunning, 1, 1, asc("progress")), s4); checkFiltered(store, query(lowercaseRunning, 0, 1, desc("progress")), s4); checkFiltered(store, query(lowercaseRunning, 1, 1, desc("progress")), s3); // force a mix of pre and post filter String lowercaseRunningProgress = "strToLowerCase(phase) = 'running' AND progress > 30"; checkFiltered(store, query(lowercaseRunningProgress), s3, s4); checkFiltered(store, query(lowercaseRunningProgress), s3, s4); checkFiltered(store, query(lowercaseRunningProgress, 0, 1, asc("progress")), s3); checkFiltered(store, query(lowercaseRunningProgress, 1, 1, asc("progress")), s4); checkFiltered(store, query(lowercaseRunningProgress, 0, 1, desc("progress")), s4); checkFiltered(store, query(lowercaseRunningProgress, 1, 1, desc("progress")), s3); } private SortBy asc(String propertyName) { return FF.sort(propertyName, SortOrder.ASCENDING); } private SortBy desc(String propertyName) { return FF.sort(propertyName, SortOrder.DESCENDING); } protected void checkFiltered(ProcessStatusStore store, Query query, ExecutionStatus... statuses) { List<ExecutionStatus> filtered = store.list(query); checkContains(filtered, statuses); } private Query query(String cql) throws CQLException { return query(cql, 0, Integer.MAX_VALUE); } private Query query(String cql, int startIndex, int maxFeatures, SortBy... sortBy) throws CQLException { Filter filter = ECQL.toFilter(cql); Query query = new Query(null, filter); query.setStartIndex(startIndex); query.setMaxFeatures(maxFeatures); query.setSortBy(sortBy); return query; } private void checkContains(List<ExecutionStatus> filtered, ExecutionStatus... statuses) { assertEquals(statuses.length, filtered.size()); for (ExecutionStatus status : statuses) { assertTrue(filtered.contains(status)); } } @Test public void testDelete() throws CQLException { assertEquals(1, store.remove(CQL.toFilter("processName = 'test1'"))); checkContains(store.list(Query.ALL), s2, s3, s4); assertEquals(2, store.remove(CQL.toFilter("progress > 30"))); checkContains(store.list(Query.ALL), s2); assertEquals(1, store.remove(CQL.toFilter("phase = 'FAILED'"))); checkContains(store.list(Query.ALL)); } @Test public void testIsolated() { store.remove(Filter.INCLUDE); ExecutionStatus status = new ExecutionStatus(new NameImpl("test"), "abcde", false); store.save(status); List<ExecutionStatus> statuses = store.list(Query.ALL); assertEquals(1, statuses.size()); assertEquals("incorrect status",status, statuses.get(0)); assertNotSame(status, statuses.get(0)); } }