From c6436da4551055bb3f0b91a6bd57acf063cac7ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 9 Apr 2019 12:14:32 +0200 Subject: [PATCH] Remove old AbstractManagerResource --- .../resources/AbstractManagerResource.java | 581 ------------------ .../CollectionResourceManagerAdapter.java | 47 +- .../SingleResourceManagerAdapter.java | 93 ++- .../AbstractManagerResourceTest.java | 164 ----- .../sonia/scm/api/rest/resources/Simple.java | 52 ++ .../CollectionResourceManagerAdapterTest.java | 62 ++ 6 files changed, 221 insertions(+), 778 deletions(-) delete mode 100644 scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractManagerResource.java delete mode 100644 scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java create mode 100644 scm-webapp/src/test/java/sonia/scm/api/rest/resources/Simple.java create mode 100644 scm-webapp/src/test/java/sonia/scm/api/v2/resources/CollectionResourceManagerAdapterTest.java diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractManagerResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractManagerResource.java deleted file mode 100644 index dfc0bd2a5d..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractManagerResource.java +++ /dev/null @@ -1,581 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - - -package sonia.scm.api.rest.resources; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.net.UrlEscapers; -import org.apache.shiro.authz.AuthorizationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import sonia.scm.LastModifiedAware; -import sonia.scm.Manager; -import sonia.scm.ModelObject; -import sonia.scm.PageResult; -import sonia.scm.api.rest.RestExceptionResult; -import sonia.scm.util.AssertUtil; -import sonia.scm.util.Comparables; -import sonia.scm.util.Util; - -import javax.ws.rs.core.CacheControl; -import javax.ws.rs.core.EntityTag; -import javax.ws.rs.core.GenericEntity; -import javax.ws.rs.core.Request; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.UriInfo; -import java.net.URI; -import java.util.Collection; -import java.util.Comparator; -import java.util.Date; - -//~--- JDK imports ------------------------------------------------------------ - -public abstract class AbstractManagerResource { - - /** the logger for AbstractManagerResource */ - private static final Logger logger = - LoggerFactory.getLogger(AbstractManagerResource.class); - - protected final Manager manager; - private final Class type; - - protected int cacheMaxAge = 0; - protected boolean disableCache = false; - - public AbstractManagerResource(Manager manager, Class type) { - this.manager = manager; - this.type = type; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param items - * - * @return - */ - protected abstract GenericEntity> createGenericEntity( - Collection items); - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param item - * - * @return - */ - protected abstract String getId(T item); - - /** - * Method description - * - * - * @return - */ - protected abstract String getPathPart(); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * - * @param uriInfo - * @param item - * - * @return - */ - public Response create(UriInfo uriInfo, T item) - { - preCreate(item); - - Response response; - - try - { - manager.create(item); - - String id = getId(item); - response = Response.created(location(uriInfo, id)).build(); - } - catch (AuthorizationException ex) - { - logger.warn("create is not allowd", ex); - response = Response.status(Status.FORBIDDEN).build(); - } - catch (Exception ex) - { - logger.error("error during create", ex); - response = createErrorResponse(ex); - } - - return response; - } - - @VisibleForTesting - URI location(UriInfo uriInfo, String id) { - String escaped = UrlEscapers.urlPathSegmentEscaper().escape(id); - return uriInfo.getAbsolutePath().resolve(getPathPart().concat("/").concat(escaped)); - } - - /** - * Method description - * - * - * @param name - * - * @return - */ - public Response delete(String name) - { - Response response = null; - T item = manager.get(name); - - if (item != null) - { - preDelete(item); - - try - { - manager.delete(item); - response = Response.noContent().build(); - } - catch (AuthorizationException ex) - { - logger.warn("delete not allowd", ex); - response = Response.status(Response.Status.FORBIDDEN).build(); - } - catch (Exception ex) - { - logger.error("error during delete", ex); - response = createErrorResponse(ex); - } - } - - return response; - } - - /** - * Method description - * - * - * - * - * @param name - * @param item - * - * - * @return - */ - public Response update(String name, T item) - { - Response response = null; - - preUpdate(item); - - try - { - manager.modify(item); - response = Response.noContent().build(); - } - catch (AuthorizationException ex) - { - logger.warn("update not allowed", ex); - response = Response.status(Response.Status.FORBIDDEN).build(); - } - catch (Exception ex) - { - logger.error("error during update", ex); - response = createErrorResponse(ex); - } - - return response; - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * - * @param request - * @param id - * - * @return - */ - public Response get(Request request, String id) - { - Response response; - T item = manager.get(id); - - if (item != null) - { - prepareForReturn(item); - - if (disableCache) - { - response = Response.ok(item).build(); - } - else - { - response = createCacheResponse(request, item, item); - } - } - else - { - response = Response.status(Response.Status.NOT_FOUND).build(); - } - - return response; - } - - /** - * Method description - * - * - * - * @param request - * @param start - * @param limit - * @param sortby - * @param desc - * @return - */ - public Response getAll(Request request, int start, int limit, String sortby, - boolean desc) - { - Collection items = fetchItems(sortby, desc, start, limit); - - if (Util.isNotEmpty(items)) - { - items = prepareForReturn(items); - } - - Response response = null; - Object entity = createGenericEntity(items); - - if (disableCache) - { - response = Response.ok(entity).build(); - } - else - { - response = createCacheResponse(request, manager, items, entity); - } - - return response; - } - - /** - * Method description - * - * - * @return - */ - public int getCacheMaxAge() - { - return cacheMaxAge; - } - - /** - * Method description - * - * - * @return - */ - public boolean isDisableCache() - { - return disableCache; - } - - //~--- set methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param cacheMaxAge - */ - public void setCacheMaxAge(int cacheMaxAge) - { - this.cacheMaxAge = cacheMaxAge; - } - - /** - * Method description - * - * - * @param disableCache - */ - public void setDisableCache(boolean disableCache) - { - this.disableCache = disableCache; - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param throwable - * - * @return - */ - protected Response createErrorResponse(Throwable throwable) - { - return createErrorResponse(Status.INTERNAL_SERVER_ERROR, - throwable.getMessage(), throwable); - } - - /** - * Method description - * - * - * @param status - * @param message - * @param throwable - * - * @return - */ - protected Response createErrorResponse(Status status, String message, - Throwable throwable) - { - return Response.status(status).entity(new RestExceptionResult(message, - throwable)).build(); - } - - /** - * Method description - * - * - * @param item - */ - protected void preCreate(T item) {} - - /** - * Method description - * - * - * @param item - */ - protected void preDelete(T item) {} - - /** - * Method description - * - * - * @param item - */ - protected void preUpdate(T item) {} - - /** - * Method description - * - * - * @param item - * - * @return - */ - protected T prepareForReturn(T item) - { - return item; - } - - /** - * Method description - * - * - * @param items - * - * @return - */ - protected Collection prepareForReturn(Collection items) - { - return items; - } - - /** - * Method description - * - * - * @param rb - */ - private void addCacheControl(Response.ResponseBuilder rb) - { - CacheControl cc = new CacheControl(); - - cc.setMaxAge(cacheMaxAge); - rb.cacheControl(cc); - } - - /** - * Method description - * - * - * @param request - * @param timeItem - * @param item - * @param - * - * @return - */ - private Response createCacheResponse(Request request, - LastModifiedAware timeItem, I item) - { - return createCacheResponse(request, timeItem, item, item); - } - - /** - * Method description - * - * - * @param request - * @param timeItem - * @param entityItem - * @param item - * @param - * - * @return - */ - private Response createCacheResponse(Request request, - LastModifiedAware timeItem, Object entityItem, I item) - { - Response.ResponseBuilder builder = null; - Date lastModified = getLastModified(timeItem); - EntityTag e = new EntityTag(Integer.toString(entityItem.hashCode())); - - if (lastModified != null) - { - builder = request.evaluatePreconditions(lastModified, e); - } - else - { - builder = request.evaluatePreconditions(e); - } - - if (builder == null) - { - builder = Response.ok(item).tag(e).lastModified(lastModified); - } - - addCacheControl(builder); - - return builder.build(); - } - - private Comparator createComparator(String sortBy, boolean desc) { - Comparator comparator = Comparables.comparator(type, sortBy); - if (desc) { - comparator = comparator.reversed(); - } - return comparator; - } - - private Collection fetchItems(String sortBy, boolean desc, int start, - int limit) - { - AssertUtil.assertPositive(start); - - Collection items = null; - - if (limit > 0) - { - if (Util.isEmpty(sortBy)) - { - - // replace with something useful - sortBy = "id"; - } - - items = manager.getAll(createComparator(sortBy, desc), start, limit); - } - else if (Util.isNotEmpty(sortBy)) - { - items = manager.getAll(createComparator(sortBy, desc)); - } - else - { - items = manager.getAll(); - } - - return items; - } - - protected PageResult fetchPage(String sortBy, boolean desc, int pageNumber, - int pageSize) { - AssertUtil.assertPositive(pageNumber); - AssertUtil.assertPositive(pageSize); - - if (Util.isEmpty(sortBy)) { - // replace with something useful - sortBy = "id"; - } - - return manager.getPage(createComparator(sortBy, desc), pageNumber, pageSize); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param item - * - * @return - */ - private Date getLastModified(LastModifiedAware item) - { - Date lastModified = null; - Long l = item.getLastModified(); - - if (l != null) - { - lastModified = new Date(l); - } - - return lastModified; - } -} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/CollectionResourceManagerAdapter.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/CollectionResourceManagerAdapter.java index 052bf771b1..c9eb6a9d26 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/CollectionResourceManagerAdapter.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/CollectionResourceManagerAdapter.java @@ -4,12 +4,13 @@ import de.otto.edison.hal.HalRepresentation; import sonia.scm.Manager; import sonia.scm.ModelObject; import sonia.scm.PageResult; -import sonia.scm.api.rest.resources.AbstractManagerResource; +import sonia.scm.util.AssertUtil; +import sonia.scm.util.Comparables; +import sonia.scm.util.Util; -import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.Response; import java.net.URI; -import java.util.Collection; +import java.util.Comparator; import java.util.function.Function; import java.util.function.Supplier; @@ -27,10 +28,14 @@ import static javax.ws.rs.core.Response.Status.BAD_REQUEST; */ @SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right? class CollectionResourceManagerAdapter extends AbstractManagerResource { + DTO extends HalRepresentation>{ + + protected final Manager manager; + protected final Class type; CollectionResourceManagerAdapter(Manager manager, Class type) { - super(manager, type); + this.manager = manager; + this.type = type; } /** @@ -42,6 +47,27 @@ class CollectionResourceManagerAdapter fetchPage(String sortBy, boolean desc, int pageNumber, + int pageSize) { + AssertUtil.assertPositive(pageNumber); + AssertUtil.assertPositive(pageSize); + + if (Util.isEmpty(sortBy)) { + // replace with something useful + sortBy = "id"; + } + + return manager.getPage(createComparator(sortBy, desc), pageNumber, pageSize); + } + + private Comparator createComparator(String sortBy, boolean desc) { + Comparator comparator = Comparables.comparator(type, sortBy); + if (desc) { + comparator = comparator.reversed(); + } + return comparator; + } + /** * Creates a model object for the given dto and returns a corresponding http response. * This handles all corner cases, eg. no conflicts or missing privileges. @@ -55,18 +81,7 @@ class CollectionResourceManagerAdapter> createGenericEntity(Collection modelObjects) { - throw new UnsupportedOperationException(); - } - - @Override protected String getId(MODEL_OBJECT item) { return item.getId(); } - - @Override - protected String getPathPart() { - throw new UnsupportedOperationException(); - } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java index 72507562dd..082064902a 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java @@ -1,15 +1,16 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; +import org.apache.shiro.authz.AuthorizationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.ConcurrentModificationException; import sonia.scm.Manager; import sonia.scm.ModelObject; import sonia.scm.NotFoundException; -import sonia.scm.api.rest.resources.AbstractManagerResource; +import sonia.scm.api.rest.RestExceptionResult; -import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.Response; -import java.util.Collection; import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; @@ -29,10 +30,13 @@ import static javax.ws.rs.core.Response.Status.BAD_REQUEST; */ @SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right? class SingleResourceManagerAdapter extends AbstractManagerResource { + DTO extends HalRepresentation> { + + private static final Logger LOG = LoggerFactory.getLogger(SingleResourceManagerAdapter.class); private final Function> errorHandler; - private final Class type; + protected final Manager manager; + protected final Class type; SingleResourceManagerAdapter(Manager manager, Class type) { this(manager, type, e -> Optional.empty()); @@ -42,7 +46,7 @@ class SingleResourceManagerAdapter manager, Class type, Function> errorHandler) { - super(manager, type); + this.manager = manager; this.errorHandler = errorHandler; this.type = type; } @@ -75,6 +79,33 @@ class SingleResourceManagerAdapter updated.getLastModified()); @@ -89,23 +120,51 @@ class SingleResourceManagerAdapter> createGenericEntity(Collection modelObjects) { - throw new UnsupportedOperationException(); + protected Response createErrorResponse(Response.Status status, String message, + Throwable throwable) + { + return Response.status(status).entity(new RestExceptionResult(message, + throwable)).build(); } - @Override protected String getId(MODEL_OBJECT item) { return item.getId(); } - - @Override - protected String getPathPart() { - throw new UnsupportedOperationException(); - } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java deleted file mode 100644 index fd9745be83..0000000000 --- a/scm-webapp/src/test/java/sonia/scm/api/rest/resources/AbstractManagerResourceTest.java +++ /dev/null @@ -1,164 +0,0 @@ -package sonia.scm.api.rest.resources; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.Manager; -import sonia.scm.ModelObject; - -import javax.ws.rs.core.GenericEntity; -import javax.ws.rs.core.Request; -import javax.ws.rs.core.UriInfo; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Collection; -import java.util.Comparator; - -import static java.util.Collections.emptyList; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -@RunWith(MockitoJUnitRunner.class) -public class AbstractManagerResourceTest { - - @Mock - private Manager manager; - - @Mock - private Request request; - - @Mock - private UriInfo uriInfo; - - @Captor - private ArgumentCaptor> comparatorCaptor; - - private AbstractManagerResource abstractManagerResource; - - @Before - public void captureComparator() { - when(manager.getAll(comparatorCaptor.capture(), eq(0), eq(1))).thenReturn(emptyList()); - abstractManagerResource = new SimpleManagerResource(); - } - - @Test - public void shouldAcceptDefaultSortByParameter() { - abstractManagerResource.getAll(request, 0, 1, null, true); - - Comparator comparator = comparatorCaptor.getValue(); - assertTrue(comparator.compare(new Simple("1", null), new Simple("2", null)) > 0); - } - - @Test - public void shouldAcceptValidSortByParameter() { - abstractManagerResource.getAll(request, 0, 1, "data", true); - - Comparator comparator = comparatorCaptor.getValue(); - assertTrue(comparator.compare(new Simple("", "1"), new Simple("", "2")) > 0); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldFailForIllegalSortByParameter() { - abstractManagerResource.getAll(request, 0, 1, "x", true); - } - - @Test - public void testLocation() throws URISyntaxException { - URI uri = location("special-item"); - assertEquals(new URI("https://scm.scm-manager.org/simple/special-item"), uri); - } - - @Test - public void testLocationWithSpaces() throws URISyntaxException { - URI uri = location("Scm Special Group"); - assertEquals(new URI("https://scm.scm-manager.org/simple/Scm%20Special%20Group"), uri); - } - - private URI location(String id) throws URISyntaxException { - URI base = new URI("https://scm.scm-manager.org/"); - when(uriInfo.getAbsolutePath()).thenReturn(base); - - return abstractManagerResource.location(uriInfo, id); - } - - private class SimpleManagerResource extends AbstractManagerResource { - - { - disableCache = true; - } - - private SimpleManagerResource() { - super(AbstractManagerResourceTest.this.manager, Simple.class); - } - - @Override - protected GenericEntity> createGenericEntity(Collection items) { - return null; - } - - @Override - protected String getId(Simple item) { - return null; - } - - @Override - protected String getPathPart() { - return "simple"; - } - } - - public static class Simple implements ModelObject { - - private String id; - private String data; - - Simple(String id, String data) { - this.id = id; - this.data = data; - } - - public String getData() { - return data; - } - - @Override - public String getId() { - return id; - } - - @Override - public void setLastModified(Long timestamp) { - - } - - @Override - public Long getCreationDate() { - return null; - } - - @Override - public void setCreationDate(Long timestamp) { - - } - - @Override - public Long getLastModified() { - return null; - } - - @Override - public String getType() { - return null; - } - @Override - public boolean isValid() { - return false; - } - } -} diff --git a/scm-webapp/src/test/java/sonia/scm/api/rest/resources/Simple.java b/scm-webapp/src/test/java/sonia/scm/api/rest/resources/Simple.java new file mode 100644 index 0000000000..3887bc4a9c --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/rest/resources/Simple.java @@ -0,0 +1,52 @@ +package sonia.scm.api.rest.resources; + +import sonia.scm.ModelObject; + +public class Simple implements ModelObject { + + private String id; + private String data; + + public Simple(String id, String data) { + this.id = id; + this.data = data; + } + + public String getData() { + return data; + } + + @Override + public String getId() { + return id; + } + + @Override + public void setLastModified(Long timestamp) { + + } + + @Override + public Long getCreationDate() { + return null; + } + + @Override + public void setCreationDate(Long timestamp) { + + } + + @Override + public Long getLastModified() { + return null; + } + + @Override + public String getType() { + return null; + } + @Override + public boolean isValid() { + return false; + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/CollectionResourceManagerAdapterTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/CollectionResourceManagerAdapterTest.java new file mode 100644 index 0000000000..671f0e576c --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/CollectionResourceManagerAdapterTest.java @@ -0,0 +1,62 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.HalRepresentation; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.Manager; +import sonia.scm.api.rest.resources.Simple; + +import java.util.Comparator; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class CollectionResourceManagerAdapterTest { + + @Mock + private Manager manager; + @Captor + private ArgumentCaptor> comparatorCaptor; + + private CollectionResourceManagerAdapter abstractManagerResource; + + @Before + public void captureComparator() { + when(manager.getPage(comparatorCaptor.capture(), eq(0), eq(1))).thenReturn(null); + abstractManagerResource = new SimpleManagerResource(); + } + + @Test + public void shouldAcceptDefaultSortByParameter() { + abstractManagerResource.getAll(0, 1, null, true, r -> null); + + Comparator comparator = comparatorCaptor.getValue(); + assertTrue(comparator.compare(new Simple("1", null), new Simple("2", null)) > 0); + } + + @Test + public void shouldAcceptValidSortByParameter() { + abstractManagerResource.getAll(0, 1, "data", true, r -> null); + + Comparator comparator = comparatorCaptor.getValue(); + assertTrue(comparator.compare(new Simple("", "1"), new Simple("", "2")) > 0); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldFailForIllegalSortByParameter() { + abstractManagerResource.getAll(0, 1, "x", true, r -> null); + } + + private class SimpleManagerResource extends CollectionResourceManagerAdapter { + private SimpleManagerResource() { + super(CollectionResourceManagerAdapterTest.this.manager, Simple.class); + } + } +}