Enhance unit tests and use guice for injection

This commit is contained in:
René Pfeuffer
2018-05-29 10:47:15 +02:00
parent 933e610daf
commit 89b0c08f70
9 changed files with 112 additions and 36 deletions

View File

@@ -510,6 +510,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<netbeans.hint.license>SCM-BSD</netbeans.hint.license> <netbeans.hint.license>SCM-BSD</netbeans.hint.license>
<jdk.classifier /> <jdk.classifier />
<org.mapstruct.version>1.2.0.Final</org.mapstruct.version>
</properties> </properties>
</project> </project>

View File

@@ -552,7 +552,6 @@
<sonar.issue.ignore.multicriteria.e1.ruleKey>javascript:S3827</sonar.issue.ignore.multicriteria.e1.ruleKey> <sonar.issue.ignore.multicriteria.e1.ruleKey>javascript:S3827</sonar.issue.ignore.multicriteria.e1.ruleKey>
<sonar.issue.ignore.multicriteria.e1.resourceKey>**.js</sonar.issue.ignore.multicriteria.e1.resourceKey> <sonar.issue.ignore.multicriteria.e1.resourceKey>**.js</sonar.issue.ignore.multicriteria.e1.resourceKey>
<sonar.exclusions>src/main/webapp/resources/extjs/**,src/main/webapp/resources/moment/**,src/main/webapp/resources/syntaxhighlighter/**</sonar.exclusions> <sonar.exclusions>src/main/webapp/resources/extjs/**,src/main/webapp/resources/moment/**,src/main/webapp/resources/syntaxhighlighter/**</sonar.exclusions>
<org.mapstruct.version>1.2.0.Final</org.mapstruct.version>
</properties> </properties>
<profiles> <profiles>

View File

@@ -39,34 +39,31 @@ import com.google.common.base.Throwables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
import java.util.Collections;
import org.apache.shiro.guice.web.ShiroWebModule; import org.apache.shiro.guice.web.ShiroWebModule;
import org.jboss.resteasy.plugins.guice.GuiceResteasyBootstrapServletContextListener;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.api.rest.resources.MapperModule;
import sonia.scm.cache.CacheManager; import sonia.scm.cache.CacheManager;
import sonia.scm.debug.DebugModule;
import sonia.scm.filter.WebElementModule;
import sonia.scm.group.GroupManager; import sonia.scm.group.GroupManager;
import sonia.scm.plugin.DefaultPluginLoader; import sonia.scm.plugin.DefaultPluginLoader;
import sonia.scm.plugin.ExtensionProcessor; import sonia.scm.plugin.ExtensionProcessor;
import sonia.scm.plugin.PluginWrapper; import sonia.scm.plugin.PluginWrapper;
import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryManager;
import sonia.scm.schedule.Scheduler;
import sonia.scm.upgrade.UpgradeManager; import sonia.scm.upgrade.UpgradeManager;
import sonia.scm.user.UserManager; import sonia.scm.user.UserManager;
import sonia.scm.util.IOUtil; import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------ import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.servlet.ServletContext; //~--- JDK imports ------------------------------------------------------------
import javax.servlet.ServletContextEvent;
import org.jboss.resteasy.plugins.guice.GuiceResteasyBootstrapServletContextListener;
import sonia.scm.debug.DebugModule;
import sonia.scm.filter.WebElementModule;
import sonia.scm.schedule.Scheduler;
/** /**
* *
@@ -148,6 +145,7 @@ public class ScmContextListener extends GuiceResteasyBootstrapServletContextList
if (SCMContext.getContext().getStage() == Stage.DEVELOPMENT){ if (SCMContext.getContext().getStage() == Stage.DEVELOPMENT){
moduleList.add(new DebugModule()); moduleList.add(new DebugModule());
} }
moduleList.add(new MapperModule());
return moduleList; return moduleList;
} }

View File

@@ -0,0 +1,12 @@
package sonia.scm.api.rest.resources;
import com.google.inject.AbstractModule;
import org.mapstruct.factory.Mappers;
public class MapperModule extends AbstractModule {
@Override
protected void configure() {
bind(UserDto2UserMapper.class).to(Mappers.getMapper(UserDto2UserMapper.class).getClass());
bind(User2UserDtoMapper.class).to(Mappers.getMapper(User2UserDtoMapper.class).getClass());
}
}

View File

@@ -4,7 +4,6 @@ import org.mapstruct.AfterMapping;
import org.mapstruct.Context; import org.mapstruct.Context;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget; import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
import sonia.scm.user.User; import sonia.scm.user.User;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
@@ -13,17 +12,16 @@ import java.util.Map;
@Mapper @Mapper
public abstract class User2UserDtoMapper { public abstract class User2UserDtoMapper {
public static User2UserDtoMapper INSTANCE = Mappers.getMapper(User2UserDtoMapper.class);
abstract public UserDto userToUserDto(User user, @Context UriInfo uriInfo); public abstract UserDto userToUserDto(User user, @Context UriInfo uriInfo);
@AfterMapping @AfterMapping
public void removePassword(User source, @MappingTarget UserDto target, @Context UriInfo uriInfo) { void removePassword(@MappingTarget UserDto target) {
target.setPassword(UserResource.DUMMY_PASSWORT); target.setPassword(UserResource.DUMMY_PASSWORT);
} }
@AfterMapping @AfterMapping
public void appendLinks(User source, @MappingTarget UserDto target, @Context UriInfo uriInfo) { void appendLinks(@MappingTarget UserDto target, @Context UriInfo uriInfo) {
Map<String, Link> links = new LinkedHashMap<>(); Map<String, Link> links = new LinkedHashMap<>();
links.put("self", new Link(uriInfo.getAbsolutePath())); links.put("self", new Link(uriInfo.getAbsolutePath()));
target.setLinks(links); target.setLinks(links);

View File

@@ -1,11 +1,11 @@
package sonia.scm.api.rest.resources; package sonia.scm.api.rest.resources;
import com.google.inject.Inject;
import org.apache.shiro.authc.credential.PasswordService; import org.apache.shiro.authc.credential.PasswordService;
import org.mapstruct.Context; import org.mapstruct.Context;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.Named; import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import sonia.scm.user.User; import sonia.scm.user.User;
import static sonia.scm.api.rest.resources.UserResource.DUMMY_PASSWORT; import static sonia.scm.api.rest.resources.UserResource.DUMMY_PASSWORT;
@@ -13,13 +13,14 @@ import static sonia.scm.api.rest.resources.UserResource.DUMMY_PASSWORT;
@Mapper @Mapper
public abstract class UserDto2UserMapper { public abstract class UserDto2UserMapper {
public static UserDto2UserMapper INSTANCE = Mappers.getMapper(UserDto2UserMapper.class); @Inject
private PasswordService passwordService;
@Mapping(source = "password", target = "password", qualifiedByName = "encrypt") @Mapping(source = "password", target = "password", qualifiedByName = "encrypt")
abstract public User userDtoToUser(UserDto userDto, @Context String originalPassword, @Context PasswordService passwordService); public abstract User userDtoToUser(UserDto userDto, @Context String originalPassword);
@Named("encrypt") @Named("encrypt")
public String encrypt(String password, @Context String originalPassword, @Context PasswordService passwordService) { String encrypt(String password, @Context String originalPassword) {
if (DUMMY_PASSWORT.equals(password)) if (DUMMY_PASSWORT.equals(password))
{ {

View File

@@ -7,7 +7,6 @@ import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint; import com.webcohesion.enunciate.metadata.rs.TypeHint;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.credential.PasswordService;
import sonia.scm.security.Role; import sonia.scm.security.Role;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.user.UserException; import sonia.scm.user.UserException;
@@ -26,12 +25,14 @@ public class UserNewResource extends AbstractManagerResource<User, UserException
/** Field description */ /** Field description */
public static final String PATH_PART = "usersnew"; public static final String PATH_PART = "usersnew";
private final PasswordService passwordService; private final UserDto2UserMapper dtoToUserMapper;
private final User2UserDtoMapper userToDtoMapper;
@Inject @Inject
public UserNewResource(UserManager userManager, PasswordService passwordService) { public UserNewResource(UserManager userManager, UserDto2UserMapper dtoToUserMapper, User2UserDtoMapper userToDtoMapper) {
super(userManager); super(userManager);
this.passwordService = passwordService; this.dtoToUserMapper = dtoToUserMapper;
this.userToDtoMapper = userToDtoMapper;
} }
@Override @Override
@@ -64,7 +65,7 @@ public class UserNewResource extends AbstractManagerResource<User, UserException
if (SecurityUtils.getSubject().hasRole(Role.ADMIN)) if (SecurityUtils.getSubject().hasRole(Role.ADMIN))
{ {
User user = manager.get(id); User user = manager.get(id);
UserDto userDto = User2UserDtoMapper.INSTANCE.userToUserDto(user, uriInfo); UserDto userDto = userToDtoMapper.userToUserDto(user, uriInfo);
return Response.ok(userDto).build(); return Response.ok(userDto).build();
} }
else else
@@ -99,7 +100,7 @@ public class UserNewResource extends AbstractManagerResource<User, UserException
@QueryParam("desc") boolean desc) @QueryParam("desc") boolean desc)
{ {
Collection<User> items = fetchItems(sortby, desc, start, limit); Collection<User> items = fetchItems(sortby, desc, start, limit);
items.stream().map(user -> User2UserDtoMapper.INSTANCE.userToUserDto(user, uriInfo)).collect(Collectors.toList()); items.stream().map(user -> userToDtoMapper.userToUserDto(user, uriInfo)).collect(Collectors.toList());
return Response.ok(new GenericEntity<Collection<User>>(items) {}).build(); return Response.ok(new GenericEntity<Collection<User>>(items) {}).build();
} }
@@ -116,7 +117,7 @@ public class UserNewResource extends AbstractManagerResource<User, UserException
@PathParam("id") String name, UserDto userDto) @PathParam("id") String name, UserDto userDto)
{ {
User o = manager.get(name); User o = manager.get(name);
User user = UserDto2UserMapper.INSTANCE.userDtoToUser(userDto, o.getPassword(), passwordService); User user = dtoToUserMapper.userDtoToUser(userDto, o.getPassword());
return super.update(name, user); return super.update(name, user);
} }
@@ -132,7 +133,7 @@ public class UserNewResource extends AbstractManagerResource<User, UserException
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response create(@Context UriInfo uriInfo, UserDto userDto) public Response create(@Context UriInfo uriInfo, UserDto userDto)
{ {
User user = UserDto2UserMapper.INSTANCE.userDtoToUser(userDto, "", passwordService); User user = dtoToUserMapper.userDtoToUser(userDto, "");
return super.create(uriInfo, user); return super.create(uriInfo, user);
} }

View File

@@ -1,23 +1,46 @@
package sonia.scm.api.rest.resources; package sonia.scm.api.rest.resources;
import org.junit.Test; import org.junit.Test;
import org.mapstruct.factory.Mappers;
import sonia.scm.user.User; import sonia.scm.user.User;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.net.URISyntaxException;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class User2UserDtoMapperTest { public class User2UserDtoMapperTest {
private final User2UserDtoMapper mapper = Mappers.getMapper(User2UserDtoMapper.class);
private final UriInfo uriInfo = mock(UriInfo.class);
@Test @Test
public void shouldMapLinks() { public void shouldMapLinks() throws URISyntaxException {
URI link = new URI("link");
when(uriInfo.getAbsolutePath()).thenReturn(link);
User user = new User(); User user = new User();
user.setName("abc");
UserDto userDto = User2UserDtoMapper.INSTANCE.userToUserDto(user, mock(UriInfo.class)); UserDto userDto = mapper.userToUserDto(user, uriInfo);
assertEquals("abc" , userDto.getName()); assertEquals("expected map with self links", link, userDto.getLinks().get("self").getHref());
assertNotNull("expected map with links", userDto.getLinks());
} }
@Test
public void shouldMapFields() {
User user = new User();
user.setName("abc");
UserDto userDto = mapper.userToUserDto(user, uriInfo);
assertEquals("abc" , userDto.getName());
}
@Test
public void shouldRemovePassword() {
User user = new User();
user.setPassword("password");
UserDto userDto = mapper.userToUserDto(user, uriInfo);
assertEquals(UserResource.DUMMY_PASSWORT , userDto.getPassword());
}
} }

View File

@@ -0,0 +1,43 @@
package sonia.scm.api.rest.resources;
import org.apache.shiro.authc.credential.PasswordService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import sonia.scm.user.User;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
public class UserDto2UserMapperTest {
@Mock
private PasswordService passwordService;
@InjectMocks
private UserDto2UserMapperImpl mapper;
@Test
public void shouldMapFields() {
UserDto dto = new UserDto();
dto.setName("abc");
User user = mapper.userDtoToUser(dto, "original password");
assertEquals("abc" , user.getName());
}
@Test
public void shouldEncodePassword() {
when(passwordService.encryptPassword("unencrypted")).thenReturn("encrypted");
UserDto dto = new UserDto();
dto.setPassword("unencrypted");
User user = mapper.userDtoToUser(dto, "original password");
assertEquals("encrypted" , user.getPassword());
}
@Before
public void init() {
initMocks(this);
}
}