merge + use the old search methods in the autocomplete feature

This commit is contained in:
Mohamed Karray
2018-10-09 11:11:25 +02:00
28 changed files with 120 additions and 475 deletions

View File

@@ -115,12 +115,4 @@ public interface GenericDAO<T>
*/
public Collection<T> getAll();
/**
* Returns items containing the searched string
*
* @param searched the search character
* @param limit the max count of the result entities. if limit is <= 0 return all filtered entities
* @return searched items
*/
Collection<T> getFiltered(String searched, int limit);
}

View File

@@ -47,6 +47,9 @@ public interface Manager<T extends ModelObject>
extends HandlerBase<T>, LastModifiedAware
{
int DEFAULT_LIMIT = 5;
/**
* Reloads a object from store and overwrites all changes.
*
@@ -77,15 +80,6 @@ public interface Manager<T extends ModelObject>
*/
Collection<T> getAll();
/**
* Returns a {@link java.util.Collection} of filtered objects
*
* @param filter the searched string
* @param limit the max count of the result entities. if limit is <= 0 return all filtered entities
* @return all object in the store
*/
Collection<T> getFiltered(String filter, int limit);
/**
* Returns all object of the store sorted by the given {@link java.util.Comparator}
*

View File

@@ -91,11 +91,6 @@ public class ManagerDecorator<T extends ModelObject> implements Manager<T> {
decorated.refresh(object);
}
@Override
public Collection<T> getFiltered(String filter, int limit) {
return decorated.getFiltered(filter, limit);
}
@Override
public T get(String id)
{

View File

@@ -44,7 +44,7 @@ import java.io.Serializable;
*/
public interface ModelObject
extends TypedObject, LastModifiedAware, Cloneable, Validateable,
Serializable, ReducedModelObject
Serializable
{
/**

View File

@@ -1,125 +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.filter;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.Priority;
import sonia.scm.util.WebUtil;
import sonia.scm.web.filter.HttpFilter;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Filter for gzip encoding.
*
* @author Sebastian Sdorra
* @since 1.15
*/
@Priority(Filters.PRIORITY_PRE_BASEURL)
@WebElement(value = Filters.PATTERN_RESOURCE_REGEX, regex = true)
public class GZipFilter extends HttpFilter
{
/**
* the logger for GZipFilter
*/
private static final Logger logger =
LoggerFactory.getLogger(GZipFilter.class);
//~--- get methods ----------------------------------------------------------
/**
* Return the configuration for the gzip filter.
*
*
* @return gzip filter configuration
*/
public GZipFilterConfig getConfig()
{
return config;
}
//~--- methods --------------------------------------------------------------
/**
* Encodes the response, if the request has support for gzip encoding.
*
*
* @param request http request
* @param response http response
* @param chain filter chain
*
* @throws IOException
* @throws ServletException
*/
@Override
protected void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException
{
if (WebUtil.isGzipSupported(request))
{
if (logger.isTraceEnabled())
{
logger.trace("compress output with gzip");
}
GZipResponseWrapper wrappedResponse = new GZipResponseWrapper(response,
config);
chain.doFilter(request, wrappedResponse);
wrappedResponse.finishResponse();
}
else
{
chain.doFilter(request, response);
}
}
//~--- fields ---------------------------------------------------------------
/** gzip filter configuration */
private GZipFilterConfig config = new GZipFilterConfig();
}

View File

@@ -0,0 +1,24 @@
package sonia.scm.filter;
import lombok.extern.slf4j.Slf4j;
import sonia.scm.util.WebUtil;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
@Provider
@Slf4j
public class GZipResponseFilter implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
if (WebUtil.isGzipSupported(requestContext::getHeaderString)) {
log.trace("compress output with gzip");
GZIPOutputStream wrappedResponse = new GZIPOutputStream(responseContext.getEntityStream());
responseContext.getHeaders().add("Content-Encoding", "gzip");
responseContext.setEntityStream(wrappedResponse);
}
}
}

View File

@@ -42,6 +42,7 @@ import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import sonia.scm.BasicPropertiesAware;
import sonia.scm.ModelObject;
import sonia.scm.ReducedModelObject;
import sonia.scm.util.Util;
import sonia.scm.util.ValidationUtil;
@@ -64,7 +65,7 @@ import java.util.List;
@XmlRootElement(name = "groups")
@XmlAccessorType(XmlAccessType.FIELD)
public class Group extends BasicPropertiesAware
implements ModelObject, PermissionObject
implements ModelObject, PermissionObject, ReducedModelObject
{
/** Field description */

View File

@@ -61,4 +61,14 @@ public interface GroupManager
* @return all groups assigned to the given member
*/
public Collection<Group> getGroupsForMember(String member);
/**
* Returns a {@link java.util.Collection} of filtered objects
*
* @param filter the searched string
* @return filtered object from the store
*/
Collection<Group> autocomplete(String filter);
}

View File

@@ -109,6 +109,11 @@ public class GroupManagerDecorator
return decorated.getGroupsForMember(member);
}
@Override
public Collection<Group> autocomplete(String filter) {
return decorated.autocomplete(filter);
}
//~--- fields ---------------------------------------------------------------
/** Field description */

View File

@@ -256,11 +256,6 @@ public class Changeset extends BasicPropertiesAware implements ModelObject {
return id;
}
@Override
public String getDisplayName() {
return id;
}
@Override
public void setLastModified(Long timestamp) {
throw new UnsupportedOperationException("changesets are immutable");

View File

@@ -60,8 +60,7 @@ import java.util.List;
*/
@StaticPermissions(
value = "repository",
permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"},
globalPermissions = {"create", "autocomplete"}
permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"}
)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "repositories")
@@ -184,11 +183,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
return id;
}
@Override
public String getDisplayName() {
return getNamespace() + "/" + getName();
}
@Override
public Long getLastModified() {
return lastModified;

View File

@@ -70,6 +70,12 @@ public class SearchRequest
this.ignoreCase = ignoreCase;
}
public SearchRequest(String query, boolean ignoreCase, int maxResults) {
this.query = query;
this.ignoreCase = ignoreCase;
this.maxResults = maxResults;
}
//~--- get methods ----------------------------------------------------------
/**

View File

@@ -41,6 +41,7 @@ import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import sonia.scm.BasicPropertiesAware;
import sonia.scm.ModelObject;
import sonia.scm.ReducedModelObject;
import sonia.scm.util.Util;
import sonia.scm.util.ValidationUtil;
@@ -58,7 +59,7 @@ import java.security.Principal;
@StaticPermissions(value = "user", globalPermissions = {"create", "list", "autocomplete"})
@XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD)
public class User extends BasicPropertiesAware implements Principal, ModelObject, PermissionObject
public class User extends BasicPropertiesAware implements Principal, ModelObject, PermissionObject, ReducedModelObject
{
/** Field description */

View File

@@ -39,6 +39,7 @@ import sonia.scm.Manager;
import sonia.scm.search.Searchable;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.function.Consumer;
import static sonia.scm.user.ChangePasswordNotAllowedException.WRONG_USER_TYPE;
@@ -90,5 +91,13 @@ public interface UserManager
return getDefaultType().equals(user.getType());
}
/**
* Returns a {@link java.util.Collection} of filtered objects
*
* @param filter the searched string
* @return filtered object from the store
*/
Collection<User> autocomplete(String filter);
}

View File

@@ -121,6 +121,11 @@ public class UserManagerDecorator extends ManagerDecorator<User>
return decorated.getDefaultType();
}
@Override
public Collection<User> autocomplete(String filter) {
return decorated.autocomplete(filter);
}
//~--- fields ---------------------------------------------------------------
/** Field description */

View File

@@ -49,6 +49,7 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.function.Function;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -266,7 +267,12 @@ public final class WebUtil
*/
public static boolean isGzipSupported(HttpServletRequest request)
{
String enc = request.getHeader(HEADER_ACCEPTENCODING);
return isGzipSupported(request::getHeader);
}
public static boolean isGzipSupported(Function<String, String> headerResolver)
{
String enc = headerResolver.apply(HEADER_ACCEPTENCODING);
return (enc != null) && enc.contains("gzip");
}

View File

@@ -78,11 +78,6 @@ public class ManagerTest {
return IntStream.range(0, givenItemCount).boxed().collect(toList());
}
@Override
public Collection getFiltered(String filter, int limit) {
return null;
}
@Override
public Collection getAll(Comparator comparator) { return getAll(); }

View File

@@ -237,16 +237,6 @@ public abstract class AbstractXmlDAO<I extends ModelObject,
return ImmutableList.copyOf(db.values());
}
@Override
public Collection<I> getFiltered(String searched, int limit) {
int size = db.values().size();
AssertUtil.assertIsNotEmpty(searched);
return ImmutableList.copyOf(db.values().stream()
.filter(item -> StringUtils.containsIgnoreCase(item.getId(), searched) || (item.getDisplayName() != null && StringUtils.containsIgnoreCase(item.getDisplayName() , searched)))
.limit(limit <= 0 ? size : limit)
.collect(Collectors.toList()));
}
/**
* Method description
*

View File

@@ -32,122 +32,45 @@
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.filter.GZipFilter;
import sonia.scm.filter.GZipFilterConfig;
import sonia.scm.filter.GZipResponseWrapper;
import sonia.scm.repository.Repository;
import sonia.scm.repository.SvnRepositoryHandler;
import sonia.scm.repository.spi.ScmProviderHttpServlet;
import sonia.scm.util.WebUtil;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
*/
public class SvnGZipFilter extends GZipFilter implements ScmProviderHttpServlet
{
class SvnGZipFilter implements ScmProviderHttpServlet {
private static final Logger logger = LoggerFactory.getLogger(SvnGZipFilter.class);
private final SvnRepositoryHandler handler;
private final ScmProviderHttpServlet delegate;
//~--- constructors ---------------------------------------------------------
private GZipFilterConfig config = new GZipFilterConfig();
/**
* Constructs ...
*
*
* @param handler
*/
public SvnGZipFilter(SvnRepositoryHandler handler, ScmProviderHttpServlet delegate)
{
SvnGZipFilter(SvnRepositoryHandler handler, ScmProviderHttpServlet delegate) {
this.handler = handler;
this.delegate = delegate;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param filterConfig
*
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
super.init(filterConfig);
getConfig().setBufferResponse(false);
}
/**
* Method description
*
*
* @param request
* @param response
* @param chain
*
* @throws IOException
* @throws ServletException
*/
@Override
protected void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException
{
if (handler.getConfig().isEnabledGZip())
{
if (logger.isTraceEnabled())
{
logger.trace("encode svn request with gzip");
}
super.doFilter(request, response, chain);
}
else
{
if (logger.isTraceEnabled())
{
logger.trace("skip gzip encoding");
}
chain.doFilter(request, response);
}
config.setBufferResponse(false);
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException {
if (handler.getConfig().isEnabledGZip())
{
if (logger.isTraceEnabled())
{
logger.trace("encode svn request with gzip");
}
super.doFilter(request, response, (servletRequest, servletResponse) -> delegate.service((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, repository));
}
else
{
if (logger.isTraceEnabled())
{
logger.trace("skip gzip encoding");
}
if (handler.getConfig().isEnabledGZip() && WebUtil.isGzipSupported(request)) {
logger.trace("compress svn response with gzip");
GZipResponseWrapper wrappedResponse = new GZipResponseWrapper(response, config);
delegate.service(request, wrappedResponse, repository);
wrappedResponse.finishResponse();
} else {
logger.trace("skip gzip encoding");
delegate.service(request, response, repository);
}
}

View File

@@ -58,8 +58,10 @@ public class WebResourceServlet extends HttpServlet {
LOG.trace("try to load {}", uri);
URL url = webResourceLoader.getResource(uri);
if (url != null) {
LOG.trace("found {} -- serve as resource {}", uri, url);
serveResource(request, response, url);
} else {
LOG.trace("could not find {} -- dispatch", uri);
dispatch(request, response, uri);
}
}
@@ -79,6 +81,7 @@ public class WebResourceServlet extends HttpServlet {
private void serveResource(HttpServletRequest request, HttpServletResponse response, URL url) {
try {
LOG.debug("using sender to serve {}", request.getRequestURI());
sender.resource(url).send(request, response);
} catch (IOException ex) {
LOG.warn("failed to serve resource: {}", url);

View File

@@ -3,26 +3,25 @@ package sonia.scm.api.v2.resources;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import org.hibernate.validator.constraints.NotEmpty;
import sonia.scm.ReducedModelObject;
import sonia.scm.group.GroupManager;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.user.UserManager;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.validation.constraints.Size;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.Collection;
import java.util.stream.Collectors;
@Path(AutoCompleteResource.PATH)
public class AutoCompleteResource {
public static final String PATH = "v2/autocomplete/";
public static final String DEFAULT_LIMIT = "5";
public static final int MIN_SEARCHED_CHARS = 2;
public static final String PARAMETER_IS_REQUIRED = "The parameter is required.";
@@ -33,14 +32,12 @@ public class AutoCompleteResource {
private UserManager userManager;
private GroupManager groupManager;
private RepositoryManager repositoryManager;
@Inject
public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserManager userManager, GroupManager groupManager, RepositoryManager repositoryManager) {
public AutoCompleteResource(ReducedObjectModelToDtoMapper mapper, UserManager userManager, GroupManager groupManager) {
this.mapper = mapper;
this.userManager = userManager;
this.groupManager = groupManager;
this.repositoryManager = repositoryManager;
}
@GET
@@ -53,13 +50,8 @@ public class AutoCompleteResource {
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"user:autocomplete\" privilege"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter,
@DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) {
return Response.ok(userManager.getFiltered(filter, limit)
.stream()
.map(mapper::map)
.collect(Collectors.toList()))
.build();
public Response searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter) {
return map(userManager.autocomplete(filter));
}
@GET
@@ -72,28 +64,12 @@ public class AutoCompleteResource {
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"group:autocomplete\" privilege"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter,
@DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) {
return Response.ok(groupManager.getFiltered(filter, limit)
.stream()
.map(mapper::map)
.collect(Collectors.toList()))
.build();
public Response searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter) {
return map(groupManager.autocomplete(filter));
}
@GET
@Path("repository")
@Produces(VndMediaType.AUTOCOMPLETE)
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 400, condition = "if the searched string contains less than 2 characters"),
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"repository:autocomplete\" privilege"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response searchRepo(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("filter") String filter,
@DefaultValue(DEFAULT_LIMIT) @QueryParam("limit") Integer limit) {
return Response.ok(repositoryManager.getFiltered(filter, limit)
private <T extends ReducedModelObject> Response map(Collection<T> autocomplete) {
return Response.ok(autocomplete
.stream()
.map(mapper::map)
.collect(Collectors.toList()))

View File

@@ -243,10 +243,11 @@ public class DefaultGroupManager extends AbstractGroupManager
}
@Override
public Collection<Group> getFiltered(String filter, int limit) {
public Collection<Group> autocomplete(String filter) {
GroupPermissions.autocomplete().check();
return groupDAO.getFiltered(filter, limit);
return search(new SearchRequest(filter,true, DEFAULT_LIMIT));
}
/**
* Method description
*

View File

@@ -243,12 +243,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
return repository;
}
@Override
public Collection<Repository> getFiltered(String filter, int limit) {
RepositoryPermissions.autocomplete().check();
return repositoryDAO.getFiltered(filter, limit);
}
@Override
public Collection<Repository> getAll(Comparator<Repository> comparator) {
List<Repository> repositories = Lists.newArrayList();

View File

@@ -260,7 +260,6 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
builder.add(canReadOwnUser(user));
builder.add(getUserAutocompletePermission());
builder.add(getGroupAutocompletePermission());
builder.add(getRepoAutocompletePermission());
permissions = builder.build();
}
@@ -269,10 +268,6 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
return info;
}
private String getRepoAutocompletePermission() {
return RepositoryPermissions.autocomplete().asShiroString();
}
private String getGroupAutocompletePermission() {
return GroupPermissions.autocomplete().asShiroString();
}

View File

@@ -301,9 +301,9 @@ public class DefaultUserManager extends AbstractUserManager
}
@Override
public Collection<User> getFiltered(String filter, int limit) {
public Collection<User> autocomplete(String filter) {
UserPermissions.autocomplete().check();
return userDAO.getFiltered(filter, limit);
return search(new SearchRequest(filter,true, DEFAULT_LIMIT));
}
/**

View File

@@ -105,11 +105,6 @@ public class AbstractManagerResourceTest {
return id;
}
@Override
public String getDisplayName() {
return id;
}
@Override
public void setLastModified(Long timestamp) {

View File

@@ -14,18 +14,11 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import sonia.scm.SCMContextProvider;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.Manager;
import sonia.scm.group.DefaultGroupManager;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import sonia.scm.group.xml.XmlGroupDAO;
import sonia.scm.repository.DefaultRepositoryManager;
import sonia.scm.repository.NamespaceStrategy;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.xml.XmlRepositoryDAO;
import sonia.scm.security.KeyGenerator;
import sonia.scm.store.ConfigurationStore;
import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.user.DefaultUserManager;
@@ -37,7 +30,6 @@ import sonia.scm.xml.XmlDatabase;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -45,10 +37,8 @@ import java.util.stream.IntStream;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
@@ -57,22 +47,17 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
public class AutoCompleteResourceTest {
public static final String URL = "/" + AutoCompleteResource.PATH;
private final Integer defaultLimit = Integer.valueOf(AutoCompleteResource.DEFAULT_LIMIT);
private final Integer defaultLimit = Manager.DEFAULT_LIMIT;
private Dispatcher dispatcher;
private final Subject subject = mock(Subject.class);
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
private XmlUserDAO userDaoMock;
private XmlGroupDAO groupDaoMock;
private XmlRepositoryDAO repoDaoMock;
private XmlUserDAO userDao;
private XmlGroupDAO groupDao;
private XmlDatabase xmlDB;
private ObjectMapper jsonObjectMapper = new ObjectMapper();
@Before
public void prepareEnvironment() {
initMocks(this);
@@ -82,16 +67,13 @@ public class AutoCompleteResourceTest {
when(storeConfig.get()).thenReturn(xmlDB);
when(storeFactory.getStore(any(), any())).thenReturn(storeConfig);
XmlUserDAO userDao = new XmlUserDAO(storeFactory);
userDaoMock = spy(userDao);
this.userDao = spy(userDao);
XmlGroupDAO groupDAO = new XmlGroupDAO(storeFactory);
groupDaoMock = spy(groupDAO);
XmlRepositoryDAO repoDao = new XmlRepositoryDAO(storeFactory);
repoDaoMock = spy(repoDao);
groupDao = spy(groupDAO);
ReducedObjectModelToDtoMapperImpl mapper = new ReducedObjectModelToDtoMapperImpl();
UserManager userManager = new DefaultUserManager(userDaoMock);
GroupManager groupManager = new DefaultGroupManager(groupDaoMock);
RepositoryManager repositoryManager = new DefaultRepositoryManager(mock(ScmConfiguration.class), mock(SCMContextProvider.class), mock(KeyGenerator.class), repoDaoMock, new HashSet<>(), mock(NamespaceStrategy.class));
AutoCompleteResource autoCompleteResource = new AutoCompleteResource(mapper, userManager, groupManager, repositoryManager);
UserManager userManager = new DefaultUserManager(this.userDao);
GroupManager groupManager = new DefaultGroupManager(groupDao);
AutoCompleteResource autoCompleteResource = new AutoCompleteResource(mapper, userManager, groupManager);
dispatcher = createDispatcher(autoCompleteResource);
subjectThreadState.bind();
ThreadContext.bind(subject);
@@ -151,23 +133,6 @@ public class AutoCompleteResourceTest {
assertTrue(response.getContentAsString().contains("\"displayName\":\"User 2\""));
}
@Test
public void shouldSearchUsersWithLimitLength() throws Exception {
List<User> users = IntStream.range(0, 10).boxed().map(i -> createMockUser("user" + i, "User " + i)).collect(Collectors.toList());
when(xmlDB.values()).thenReturn(users);
MockHttpRequest request = MockHttpRequest
.get("/" + AutoCompleteResource.PATH + "user?filter=user&limit=1")
.contentType(VndMediaType.AUTOCOMPLETE)
.accept(VndMediaType.AUTOCOMPLETE);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
verify(userDaoMock).getFiltered(eq("user"), eq(1));
assertResultSize(response, 1);
}
@Test
public void shouldSearchUsersWithDefaultLimitLength() throws Exception {
List<User> userList = IntStream.range(0, 10).boxed().map(i -> createMockUser("user" + i, "User " + i)).collect(Collectors.toList());
@@ -181,7 +146,6 @@ public class AutoCompleteResourceTest {
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
verify(userDaoMock).getFiltered(eq("user"), eq(defaultLimit));
assertResultSize(response, defaultLimit);
}
@@ -232,23 +196,6 @@ public class AutoCompleteResourceTest {
assertTrue(response.getContentAsString().contains("\"displayName\":\"group_2\""));
}
@Test
public void shouldSearchGroupsWithLimitLength() throws Exception {
List<Group> groups = IntStream.range(0, 10).boxed().map(i -> createMockGroup("group_" + i)).collect(Collectors.toList());
when(xmlDB.values()).thenReturn(groups);
MockHttpRequest request = MockHttpRequest
.get("/" + AutoCompleteResource.PATH + "group?filter=group&limit=1")
.contentType(VndMediaType.AUTOCOMPLETE)
.accept(VndMediaType.AUTOCOMPLETE);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
verify(groupDaoMock).getFiltered(eq("group"), eq(1));
assertResultSize(response, 1);
}
@Test
public void shouldSearchGroupsWithDefaultLimitLength() throws Exception {
List<Group> groups = IntStream.range(0, 10).boxed().map(i -> createMockGroup("group_" + i)).collect(Collectors.toList());
@@ -262,107 +209,21 @@ public class AutoCompleteResourceTest {
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
verify(groupDaoMock).getFiltered(eq("group"), eq(defaultLimit));
assertResultSize(response, defaultLimit);
}
@Test
public void shouldGet400OnFailedParameterForRepoSearch() throws Exception {
MockHttpRequest request = MockHttpRequest
.get("/" + AutoCompleteResource.PATH + "repository")
.contentType(VndMediaType.AUTOCOMPLETE)
.accept(VndMediaType.AUTOCOMPLETE);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
}
@Test
public void shouldGet400IfParameterLengthLessThan2CharsForRepoSearch() throws Exception {
MockHttpRequest request = MockHttpRequest
.get("/" + AutoCompleteResource.PATH + "repository?filter=a")
.contentType(VndMediaType.AUTOCOMPLETE)
.accept(VndMediaType.AUTOCOMPLETE);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(400, response.getStatus());
}
@Test
public void shouldSearchRepos() throws Exception {
List<Repository> repos = Lists.newArrayList(createMockRepo("YCannotFindMe"), createMockRepo("repo1"), createMockRepo("repo2"));
when(xmlDB.values()).thenReturn(repos);
MockHttpRequest request = MockHttpRequest
.get("/" + AutoCompleteResource.PATH + "repository?filter=repo")
.contentType(VndMediaType.AUTOCOMPLETE)
.accept(VndMediaType.AUTOCOMPLETE);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertResultSize(response, 2);
assertTrue(response.getContentAsString().contains("\"displayName\":\"space/repo1\""));
assertTrue(response.getContentAsString().contains("\"displayName\":\"space/repo2\""));
}
@Test
public void shouldSearchReposWithLimitLength() throws Exception {
List<Repository> repositories = IntStream.range(0, 10).boxed().map(i -> createMockRepo("repo" + i)).collect(Collectors.toList());
when(xmlDB.values()).thenReturn(repositories);
MockHttpRequest request = MockHttpRequest
.get("/" + AutoCompleteResource.PATH + "repository?filter=repo&limit=1")
.contentType(VndMediaType.AUTOCOMPLETE)
.accept(VndMediaType.AUTOCOMPLETE);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
verify(repoDaoMock).getFiltered(eq("repo"), eq(1));
assertResultSize(response, 1);
}
@Test
public void shouldSearchReposWithDefaultLimitLength() throws Exception {
List<Repository> repositories = IntStream.range(0, 10).boxed().map(i -> createMockRepo("repo" + i)).collect(Collectors.toList());
when(xmlDB.values()).thenReturn(repositories);
MockHttpRequest request = MockHttpRequest
.get("/" + AutoCompleteResource.PATH + "repository?filter=repo")
.contentType(VndMediaType.AUTOCOMPLETE)
.accept(VndMediaType.AUTOCOMPLETE);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
verify(repoDaoMock).getFiltered(eq("repo"), eq(defaultLimit));
assertResultSize(response, defaultLimit);
}
private User createMockUser(String id, String name) {
return new User(id, name, "em@l.de");
}
private Group createMockGroup(String name) {
Group group = new Group("type", name);
group.setDescription(name);
return group;
}
private Repository createMockRepo(String repository) {
return new Repository("id", "git", "space", repository);
}
private void assertResultSize(MockHttpResponse response, int size) throws java.io.IOException {
ReducedObjectModelDto[] reducedObjectModelDtos = jsonObjectMapper.readValue(response.getContentAsString(), ReducedObjectModelDto[].class);
assertTrue(reducedObjectModelDtos.length == size);
assertEquals(reducedObjectModelDtos.length, size);
}
}

View File

@@ -161,8 +161,8 @@ public class DefaultAuthorizationCollectorTest {
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.contains(Role.USER));
assertThat(authInfo.getStringPermissions(), hasSize(4));
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("user:autocomplete", "group:autocomplete", "repository:autocomplete", "user:read:trillian"));
assertThat(authInfo.getStringPermissions(), hasSize(3));
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("user:autocomplete", "group:autocomplete", "user:read:trillian"));
assertThat(authInfo.getObjectPermissions(), nullValue());
}
@@ -209,7 +209,7 @@ public class DefaultAuthorizationCollectorTest {
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
assertThat(authInfo.getObjectPermissions(), nullValue());
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("user:autocomplete", "group:autocomplete","repository:autocomplete", "repository:read,pull:one", "repository:read,pull,push:two", "user:read:trillian"));
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("user:autocomplete", "group:autocomplete", "repository:read,pull:one", "repository:read,pull,push:two", "user:read:trillian"));
}
/**
@@ -230,7 +230,7 @@ public class DefaultAuthorizationCollectorTest {
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
assertThat(authInfo.getObjectPermissions(), nullValue());
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("one:one", "two:two", "user:read:trillian", "user:autocomplete" , "group:autocomplete", "repository:autocomplete"));
assertThat(authInfo.getStringPermissions(), containsInAnyOrder("one:one", "two:two", "user:read:trillian", "user:autocomplete" , "group:autocomplete" ));
}
private void authenticate(User user, String group, String... groups) {