From 4e3e0637a4c70f7832c526400aee481cde54f5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maren=20S=C3=BCwer?= Date: Thu, 11 Oct 2018 14:16:34 +0200 Subject: [PATCH 1/6] add table header line for delete button --- scm-ui/src/repos/permissions/containers/Permissions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scm-ui/src/repos/permissions/containers/Permissions.js b/scm-ui/src/repos/permissions/containers/Permissions.js index d29359ed0b..e70e02f443 100644 --- a/scm-ui/src/repos/permissions/containers/Permissions.js +++ b/scm-ui/src/repos/permissions/containers/Permissions.js @@ -121,6 +121,7 @@ class Permissions extends React.Component { {t("permission.group-permission")} {t("permission.type")} + From c7b8a3fedd45104508aab3bab1e176c3e7f8bdb9 Mon Sep 17 00:00:00 2001 From: Mohamed Karray Date: Fri, 12 Oct 2018 11:06:53 +0200 Subject: [PATCH 2/6] fix autocomplete for user without admin permission + integration tests --- .../java/sonia/scm/it/AutoCompleteITCase.java | 103 ++++++++++++++++++ .../src/test/java/sonia/scm/it/MeITCase.java | 2 +- .../java/sonia/scm/it/PermissionsITCase.java | 8 +- .../test/java/sonia/scm/it/UserITCase.java | 6 +- .../java/sonia/scm/it/utils/ScmRequests.java | 31 ++++++ .../java/sonia/scm/it/utils/TestData.java | 38 ++++++- .../v2/resources/AutoCompleteResource.java | 8 +- .../sonia/scm/group/DefaultGroupManager.java | 6 +- .../sonia/scm/user/DefaultUserManager.java | 17 +-- .../resources/AutoCompleteResourceTest.java | 16 +-- 10 files changed, 199 insertions(+), 36 deletions(-) create mode 100644 scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java diff --git a/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java b/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java new file mode 100644 index 0000000000..a0579eee6f --- /dev/null +++ b/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java @@ -0,0 +1,103 @@ +package sonia.scm.it; + +import org.junit.Before; +import org.junit.Test; +import sonia.scm.it.utils.ScmRequests; +import sonia.scm.it.utils.TestData; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AutoCompleteITCase { + + + public static final String CREATED_USER_PREFIX = "user"; + public static final String CREATED_GROUP_PREFIX = "group_"; + + @Before + public void init() { + TestData.cleanup(); + } + + @Test + public void adminShouldAutoCompleteUsers() { + createUsers(); + ScmRequests.start() + .given() + .url(TestData.getUsersAutoCompleteUrl("user*")) + .usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) + .getAutoCompleteResource() + .assertStatusCode(200) + .usingAutoCompleteResponse() + .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX)); + } + + @Test + public void userShouldAutoCompleteUsersWithoutAdminPermission() { + String username = "nonAdmin"; + String password = "pass"; + TestData.createUser(username, password, false, "xml", "email@e.de"); + createUsers(); + ScmRequests.start() + .given() + .url(TestData.getUsersAutoCompleteUrl("user*")) + .usernameAndPassword(username, password) + .getAutoCompleteResource() + .assertStatusCode(200) + .usingAutoCompleteResponse() + .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX)); + } + + @Test + public void adminShouldAutoCompleteGroups() { + createGroups(); + ScmRequests.start() + .given() + .url(TestData.getGroupsAutoCompleteUrl("group*")) + .usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) + .getAutoCompleteResource() + .assertStatusCode(200) + .usingAutoCompleteResponse() + .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)); + } + + @Test + public void userShouldAutoCompleteGroupsWithoutAdminPermission() { + String username = "nonAdminUser"; + String password = "pass"; + TestData.createNotAdminUser(username, password); + createGroups(); + ScmRequests.start() + .given() + .url(TestData.getGroupsAutoCompleteUrl("group*")) + .usernameAndPassword(username, password) + .getAutoCompleteResource() + .assertStatusCode(200) + .usingAutoCompleteResponse() + .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)); + } + + @SuppressWarnings("unchecked") + private Consumer> assertAutoCompleteResult(String id) { + return autoCompleteDtos -> { + IntStream.range(0, 5).forEach(i -> { + assertThat(autoCompleteDtos).as("return maximum 5 entries").hasSize(5); + assertThat(autoCompleteDtos.get(i)).containsEntry("id", id + (i + 1)); + assertThat(autoCompleteDtos.get(i)).containsEntry("displayName", id + (i + 1)); + }); + }; + } + + private void createUsers() { + IntStream.range(0, 6).forEach(i -> TestData.createUser(CREATED_USER_PREFIX + (i + 1), "pass", false, "xml", CREATED_USER_PREFIX + (i + 1) + "@scm-manager.org")); + } + + private void createGroups() { + IntStream.range(0, 6).forEach(i -> TestData.createGroup(CREATED_GROUP_PREFIX + (i + 1), CREATED_GROUP_PREFIX + (i + 1))); + } + +} diff --git a/scm-it/src/test/java/sonia/scm/it/MeITCase.java b/scm-it/src/test/java/sonia/scm/it/MeITCase.java index 64f06765ea..5a1df060c8 100644 --- a/scm-it/src/test/java/sonia/scm/it/MeITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/MeITCase.java @@ -49,7 +49,7 @@ public class MeITCase { String newUser = "user"; String password = "pass"; String type = "not XML Type"; - TestData.createUser(newUser, password, true, type); + TestData.createUser(newUser, password, true, type, "user@scm-manager.org"); ScmRequests.start() .given() .url(TestData.getMeUrl()) diff --git a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java index f288d4891c..8785f1d8ce 100644 --- a/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/PermissionsITCase.java @@ -87,13 +87,13 @@ public class PermissionsITCase { @Before public void prepareEnvironment() { TestData.createDefault(); - TestData.createUser(USER_READ, USER_PASS); + TestData.createNotAdminUser(USER_READ, USER_PASS); TestData.createUserPermission(USER_READ, PermissionType.READ, repositoryType); - TestData.createUser(USER_WRITE, USER_PASS); + TestData.createNotAdminUser(USER_WRITE, USER_PASS); TestData.createUserPermission(USER_WRITE, PermissionType.WRITE, repositoryType); - TestData.createUser(USER_OWNER, USER_PASS); + TestData.createNotAdminUser(USER_OWNER, USER_PASS); TestData.createUserPermission(USER_OWNER, PermissionType.OWNER, repositoryType); - TestData.createUser(USER_OTHER, USER_PASS); + TestData.createNotAdminUser(USER_OTHER, USER_PASS); createdPermissions = 3; } diff --git a/scm-it/src/test/java/sonia/scm/it/UserITCase.java b/scm-it/src/test/java/sonia/scm/it/UserITCase.java index 33fbe0cc5d..3b220da00c 100644 --- a/scm-it/src/test/java/sonia/scm/it/UserITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/UserITCase.java @@ -19,7 +19,7 @@ public class UserITCase { public void adminShouldChangeOwnPassword() { String newUser = "user"; String password = "pass"; - TestData.createUser(newUser, password, true, "xml"); + TestData.createUser(newUser, password, true, "xml", "user@scm-manager.org"); String newPassword = "new_password"; // admin change the own password ScmRequests.start() @@ -50,7 +50,7 @@ public class UserITCase { public void adminShouldChangePasswordOfOtherUser() { String newUser = "user"; String password = "pass"; - TestData.createUser(newUser, password, true, "xml"); + TestData.createUser(newUser, password, true, "xml", "user@scm-manager.org"); String newPassword = "new_password"; // admin change the password of the user ScmRequests.start() @@ -80,7 +80,7 @@ public class UserITCase { String newUser = "user"; String password = "pass"; String type = "not XML Type"; - TestData.createUser(newUser, password, true, type); + TestData.createUser(newUser, password, true, type, "user@scm-manager.org"); ScmRequests.start() .given() .url(TestData.getMeUrl()) diff --git a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java index 41fd9a1290..8b4eb34188 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java @@ -154,6 +154,12 @@ public class ScmRequests { applyGETRequest(url) ); } + + public AppliedAutoCompleteRequest getAutoCompleteResource() { + return new AppliedAutoCompleteRequest( + applyGETRequest(url) + ); + } } public class AppliedRequest { @@ -462,4 +468,29 @@ public class ScmRequests { } } + + public class AppliedAutoCompleteRequest extends AppliedRequest { + public AppliedAutoCompleteRequest(Response response) { + super(response); + } + + public AutoCompleteResponse usingAutoCompleteResponse() { + return new AutoCompleteResponse(super.response); + } + + } + + public class AutoCompleteResponse extends ModelResponse{ + + public AutoCompleteResponse(Response response) { + super(response); + } + + public AutoCompleteResponse assertAutoCompleteResults(Consumer> checker){ + List result = response.then().extract().path(""); + checker.accept(result); + return this; + } + + } } diff --git a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java index 03da80ea3b..af9032e62e 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java @@ -46,11 +46,11 @@ public class TestData { return DEFAULT_REPOSITORIES.get(repositoryType); } - public static void createUser(String username, String password) { - createUser(username, password, false, "xml"); + public static void createNotAdminUser(String username, String password) { + createUser(username, password, false, "xml", "user1@scm-manager.org"); } - public static void createUser(String username, String password, boolean isAdmin, String type) { + public static void createUser(String username, String password, boolean isAdmin, String type, final String email) { LOG.info("create user with username: {}", username); String admin = isAdmin ? "true" : "false"; given(VndMediaType.USER) @@ -61,7 +61,7 @@ public class TestData { .append(" \"admin\": ").append(admin).append(",\n") .append(" \"creationDate\": \"2018-08-21T12:26:46.084Z\",\n") .append(" \"displayName\": \"").append(username).append("\",\n") - .append(" \"mail\": \"user1@scm-manager.org\",\n") + .append(" \"mail\": \"" + email + "\",\n") .append(" \"name\": \"").append(username).append("\",\n") .append(" \"password\": \"").append(password).append("\",\n") .append(" \"type\": \"").append(type).append("\"\n") @@ -71,6 +71,16 @@ public class TestData { .statusCode(HttpStatus.SC_CREATED) ; } + public static void createGroup(String groupName, String desc) { + LOG.info("create group with group name: {} and description {}", groupName, desc); + given(VndMediaType.GROUP) + .when() + .content(getGroupJson(groupName,desc)) + .post(getGroupsUrl()) + .then() + .statusCode(HttpStatus.SC_CREATED) + ; + } public static void createUserPermission(String name, PermissionType permissionType, String repositoryType) { String defaultPermissionUrl = TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType); @@ -199,21 +209,36 @@ public class TestData { .build().toString(); } + public static String getGroupJson(String groupname , String desc) { + return JSON_BUILDER + .add("name", groupname) + .add("description", desc) + .build().toString(); + } + public static URI getMeUrl() { return RestUtil.createResourceUrl("me/"); + } + public static URI getGroupsUrl() { + return RestUtil.createResourceUrl("groups/"); } public static URI getUsersUrl() { return RestUtil.createResourceUrl("users/"); - } public static URI getUserUrl(String username) { return getUsersUrl().resolve(username); - } + public static URI getUsersAutoCompleteUrl(String query ) { + return RestUtil.createResourceUrl("autocomplete/users?q="+query); + } + + public static URI getGroupsAutoCompleteUrl(String query ) { + return RestUtil.createResourceUrl("autocomplete/groups?q="+query); + } public static String createPasswordChangeJson(String oldPassword, String newPassword) { return JSON_BUILDER @@ -225,4 +250,5 @@ public class TestData { public static void main(String[] args) { cleanup(); } + } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java index 70192973cb..97a1fcccf9 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java @@ -41,7 +41,7 @@ public class AutoCompleteResource { } @GET - @Path("user") + @Path("users") @Produces(VndMediaType.AUTOCOMPLETE) @StatusCodes({ @ResponseCode(code = 200, condition = "success"), @@ -50,12 +50,12 @@ 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) { + public Response searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) { return map(userManager.autocomplete(filter)); } @GET - @Path("group") + @Path("groups") @Produces(VndMediaType.AUTOCOMPLETE) @StatusCodes({ @ResponseCode(code = 200, condition = "success"), @@ -64,7 +64,7 @@ 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) { + public Response searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) { return map(groupManager.autocomplete(filter)); } diff --git a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java index 327415ec22..bdd51836b9 100644 --- a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java +++ b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java @@ -50,6 +50,7 @@ import sonia.scm.SCMContextProvider; import sonia.scm.TransformFilter; import sonia.scm.search.SearchRequest; import sonia.scm.search.SearchUtil; +import sonia.scm.user.UserPermissions; import sonia.scm.util.CollectionAppender; import sonia.scm.util.Util; @@ -244,8 +245,9 @@ public class DefaultGroupManager extends AbstractGroupManager @Override public Collection autocomplete(String filter) { - GroupPermissions.autocomplete().check(); - return search(new SearchRequest(filter,true, DEFAULT_LIMIT)); + UserPermissions.autocomplete().check(); + SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT); + return SearchUtil.search(searchRequest, groupDAO.getAll(), group -> matches(searchRequest,group)?group:null); } /** diff --git a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java index 19802902b8..21cd4cc319 100644 --- a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java +++ b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java @@ -229,6 +229,13 @@ public class DefaultUserManager extends AbstractUserManager fresh.copyProperties(user); } + @Override + public Collection autocomplete(String filter) { + UserPermissions.autocomplete().check(); + SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT); + return SearchUtil.search(searchRequest, userDAO.getAll(), user -> matches(searchRequest,user)?user:null); + } + /** * Method description * @@ -258,7 +265,7 @@ public class DefaultUserManager extends AbstractUserManager } }); } - + private boolean matches(SearchRequest searchRequest, User user) { return SearchUtil.matchesOne(searchRequest, user.getName(), user.getDisplayName(), user.getMail()); } @@ -277,7 +284,7 @@ public class DefaultUserManager extends AbstractUserManager public User get(String id) { UserPermissions.read().check(id); - + User user = userDAO.get(id); if (user != null) @@ -300,12 +307,6 @@ public class DefaultUserManager extends AbstractUserManager return getAll(null); } - @Override - public Collection autocomplete(String filter) { - UserPermissions.autocomplete().check(); - return search(new SearchRequest(filter,true, DEFAULT_LIMIT)); - } - /** * Method description * diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java index adc396458c..68bb165140 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java @@ -88,7 +88,7 @@ public class AutoCompleteResourceTest { @Test public void shouldGet400OnFailedParameterForUserSearch() throws Exception { MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "user") + .get("/" + AutoCompleteResource.PATH + "users") .contentType(VndMediaType.AUTOCOMPLETE) .accept(VndMediaType.AUTOCOMPLETE); MockHttpResponse response = new MockHttpResponse(); @@ -101,7 +101,7 @@ public class AutoCompleteResourceTest { @Test public void shouldGet400IfParameterLengthLessThan2CharsForUserSearch() throws Exception { MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "user?filter=a") + .get("/" + AutoCompleteResource.PATH + "users?q=a") .contentType(VndMediaType.AUTOCOMPLETE) .accept(VndMediaType.AUTOCOMPLETE); MockHttpResponse response = new MockHttpResponse(); @@ -117,7 +117,7 @@ public class AutoCompleteResourceTest { String searched = "user"; when(xmlDB.values()).thenReturn(users); MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "user?filter=" + searched) + .get("/" + AutoCompleteResource.PATH + "users?q=" + searched) .contentType(VndMediaType.AUTOCOMPLETE) .accept(VndMediaType.AUTOCOMPLETE); MockHttpResponse response = new MockHttpResponse(); @@ -138,7 +138,7 @@ public class AutoCompleteResourceTest { List userList = IntStream.range(0, 10).boxed().map(i -> createMockUser("user" + i, "User " + i)).collect(Collectors.toList()); when(xmlDB.values()).thenReturn(userList); MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "user?filter=user") + .get("/" + AutoCompleteResource.PATH + "users?q=user") .contentType(VndMediaType.AUTOCOMPLETE) .accept(VndMediaType.AUTOCOMPLETE); MockHttpResponse response = new MockHttpResponse(); @@ -152,7 +152,7 @@ public class AutoCompleteResourceTest { @Test public void shouldGet400OnFailedParameterForGroupSearch() throws Exception { MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "group") + .get("/" + AutoCompleteResource.PATH + "groups") .contentType(VndMediaType.AUTOCOMPLETE) .accept(VndMediaType.AUTOCOMPLETE); MockHttpResponse response = new MockHttpResponse(); @@ -165,7 +165,7 @@ public class AutoCompleteResourceTest { @Test public void shouldGet400IfParameterLengthLessThan2CharsForGroupSearch() throws Exception { MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "group?filter=a") + .get("/" + AutoCompleteResource.PATH + "groups?q=a") .contentType(VndMediaType.AUTOCOMPLETE) .accept(VndMediaType.AUTOCOMPLETE); MockHttpResponse response = new MockHttpResponse(); @@ -181,7 +181,7 @@ public class AutoCompleteResourceTest { String searched = "group"; when(xmlDB.values()).thenReturn(groups); MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "group?filter=" + searched) + .get("/" + AutoCompleteResource.PATH + "groups?q=" + searched) .contentType(VndMediaType.AUTOCOMPLETE) .accept(VndMediaType.AUTOCOMPLETE); MockHttpResponse response = new MockHttpResponse(); @@ -201,7 +201,7 @@ public class AutoCompleteResourceTest { List 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") + .get("/" + AutoCompleteResource.PATH + "groups?q=group") .contentType(VndMediaType.AUTOCOMPLETE) .accept(VndMediaType.AUTOCOMPLETE); MockHttpResponse response = new MockHttpResponse(); From 27ca8860d3af7bc3cfa2917b4ab3aa1efe68abc3 Mon Sep 17 00:00:00 2001 From: Mohamed Karray Date: Mon, 15 Oct 2018 08:41:46 +0200 Subject: [PATCH 3/6] add the autoComplete link to the index resource --- .../java/sonia/scm/it/AutoCompleteITCase.java | 30 ++++--- .../java/sonia/scm/it/utils/ScmRequests.java | 79 ++++++++++++++++--- .../v2/resources/AutoCompleteResource.java | 13 ++- .../api/v2/resources/IndexDtoGenerator.java | 6 ++ .../scm/api/v2/resources/ResourceLinks.java | 20 +++++ .../sonia/scm/group/DefaultGroupManager.java | 3 +- .../api/v2/resources/IndexResourceTest.java | 20 ++++- .../api/v2/resources/ResourceLinksMock.java | 1 + .../test/resources/sonia/scm/shiro-002.ini | 9 +++ 9 files changed, 147 insertions(+), 34 deletions(-) create mode 100644 scm-webapp/src/test/resources/sonia/scm/shiro-002.ini diff --git a/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java b/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java index a0579eee6f..f15acdb6f4 100644 --- a/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java @@ -15,7 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class AutoCompleteITCase { - public static final String CREATED_USER_PREFIX = "user"; + public static final String CREATED_USER_PREFIX = "user_"; public static final String CREATED_GROUP_PREFIX = "group_"; @Before @@ -28,9 +28,10 @@ public class AutoCompleteITCase { createUsers(); ScmRequests.start() .given() - .url(TestData.getUsersAutoCompleteUrl("user*")) - .usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) - .getAutoCompleteResource() + .requestIndexResource(TestData.USER_SCM_ADMIN,TestData.USER_SCM_ADMIN) + .assertStatusCode(200) + .usingIndexResponse() + .requestAutoCompleteUsers("user*") .assertStatusCode(200) .usingAutoCompleteResponse() .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX)); @@ -44,9 +45,10 @@ public class AutoCompleteITCase { createUsers(); ScmRequests.start() .given() - .url(TestData.getUsersAutoCompleteUrl("user*")) - .usernameAndPassword(username, password) - .getAutoCompleteResource() + .requestIndexResource(username,password) + .assertStatusCode(200) + .usingIndexResponse() + .requestAutoCompleteUsers("user*") .assertStatusCode(200) .usingAutoCompleteResponse() .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX)); @@ -57,9 +59,10 @@ public class AutoCompleteITCase { createGroups(); ScmRequests.start() .given() - .url(TestData.getGroupsAutoCompleteUrl("group*")) - .usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) - .getAutoCompleteResource() + .requestIndexResource(TestData.USER_SCM_ADMIN,TestData.USER_SCM_ADMIN) + .assertStatusCode(200) + .usingIndexResponse() + .applyAutoCompleteGroups("group*") .assertStatusCode(200) .usingAutoCompleteResponse() .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)); @@ -73,9 +76,10 @@ public class AutoCompleteITCase { createGroups(); ScmRequests.start() .given() - .url(TestData.getGroupsAutoCompleteUrl("group*")) - .usernameAndPassword(username, password) - .getAutoCompleteResource() + .requestIndexResource(username,password) + .assertStatusCode(200) + .usingIndexResponse() + .applyAutoCompleteGroups("group*") .assertStatusCode(200) .usingAutoCompleteResponse() .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)); diff --git a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java index 8b4eb34188..7ea52ba58d 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java @@ -46,24 +46,46 @@ public class ScmRequests { * @return the response of the GET request using the given link */ private Response applyGETRequestFromLink(Response response, String linkPropertyName) { - return applyGETRequest(response - .then() - .extract() - .path(linkPropertyName)); + return applyGETRequestFromLinkWithParams(response, linkPropertyName, ""); } + /** + * Apply a GET Request to the extracted url from the given link + * + * @param linkPropertyName the property name of link + * @param response the response containing the link + * @param queryParams query params eg. ?q=xyz&count=12 + * @return the response of the GET request using the given link + */ + private Response applyGETRequestFromLinkWithParams(Response response, String linkPropertyName, String queryParams) { + return applyGETRequestWithQueryParams(response + .then() + .extract() + .path(linkPropertyName), queryParams); + } + + /** + * Apply a GET Request to the given url and return the response. + * + * @param url the url of the GET request + * @param htmlQueryParams query params eg. ?q=xyz&count=12 + * @return the response of the GET request using the given url + */ + private Response applyGETRequestWithQueryParams(String url, String htmlQueryParams) { + return RestAssured.given() + .auth().preemptive().basic(username, password) + .when() + .get(url + htmlQueryParams); + } /** * Apply a GET Request to the given url and return the response. * * @param url the url of the GET request * @return the response of the GET request using the given url - */ + **/ private Response applyGETRequest(String url) { - return RestAssured.given() - .auth().preemptive().basic(username, password) - .when() - .get(url); + return applyGETRequestWithQueryParams(url, ""); } @@ -133,6 +155,12 @@ public class ScmRequests { return new GivenUrl(); } + public AppliedIndexResource requestIndexResource(String username, String password) { + setUsername(username); + setPassword(password); + return new AppliedIndexResource(applyGETRequest(RestUtil.REST_BASE_URL.toString())); + } + public GivenUrl url(URI url) { setUrl(url.toString()); return new GivenUrl(); @@ -480,17 +508,46 @@ public class ScmRequests { } - public class AutoCompleteResponse extends ModelResponse{ + public class AutoCompleteResponse extends ModelResponse { public AutoCompleteResponse(Response response) { super(response); } - public AutoCompleteResponse assertAutoCompleteResults(Consumer> checker){ + public AutoCompleteResponse assertAutoCompleteResults(Consumer> checker) { List result = response.then().extract().path(""); checker.accept(result); return this; } } + + public class AppliedIndexResource extends AppliedRequest { + public AppliedIndexResource(Response response) { + super(response); + } + + public IndexResponse usingIndexResponse() { + return new IndexResponse(super.response); + } + + } + + public class IndexResponse extends ModelResponse { + + public static final String AUTOCOMPLETE_USERS = "_links.autocompleteUsers.href"; + public static final String AUTOCOMPLETE_GROUPS = "_links.autocompleteGroups.href"; + + public IndexResponse(Response response) { + super(response); + } + + public AppliedAutoCompleteRequest requestAutoCompleteUsers(String q) { + return new AppliedAutoCompleteRequest(applyGETRequestFromLinkWithParams(response, AUTOCOMPLETE_USERS, "?q="+q)); + } + + public AppliedAutoCompleteRequest applyAutoCompleteGroups(String q) { + return new AppliedAutoCompleteRequest(applyGETRequestFromLinkWithParams(response, AUTOCOMPLETE_GROUPS, "?q="+q)); + } + } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java index 97a1fcccf9..005e29e9ea 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/AutoCompleteResource.java @@ -14,8 +14,8 @@ 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.List; import java.util.stream.Collectors; @@ -50,7 +50,7 @@ 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("q") String filter) { + public List searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) { return map(userManager.autocomplete(filter)); } @@ -64,16 +64,15 @@ 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("q") String filter) { + public List searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) { return map(groupManager.autocomplete(filter)); } - private Response map(Collection autocomplete) { - return Response.ok(autocomplete + private List map(Collection autocomplete) { + return autocomplete .stream() .map(mapper::map) - .collect(Collectors.toList())) - .build(); + .collect(Collectors.toList()); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java index c8159f072c..4b78c19cc0 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java @@ -34,6 +34,12 @@ public class IndexDtoGenerator { if (UserPermissions.list().isPermitted()) { builder.single(link("users", resourceLinks.userCollection().self())); } + if (UserPermissions.autocomplete().isPermitted()) { + builder.single(link("autocompleteUsers", resourceLinks.autoComplete().users())); + } + if (GroupPermissions.autocomplete().isPermitted()) { + builder.single(link("autocompleteGroups", resourceLinks.autoComplete().groups())); + } if (GroupPermissions.list().isPermitted()) { builder.single(link("groups", resourceLinks.groupCollection().self())); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java index 488577618c..820e722814 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java @@ -142,6 +142,26 @@ class ResourceLinks { } } + AutoCompleteLinks autoComplete() { + return new AutoCompleteLinks (scmPathInfoStore.get()); + } + + static class AutoCompleteLinks { + private final LinkBuilder linkBuilder; + + AutoCompleteLinks (ScmPathInfo pathInfo) { + linkBuilder = new LinkBuilder(pathInfo, AutoCompleteResource.class); + } + + String users() { + return linkBuilder.method("searchUser").parameters().href(); + } + + String groups() { + return linkBuilder.method("searchGroup").parameters().href(); + } + } + ConfigLinks config() { return new ConfigLinks(scmPathInfoStore.get()); } diff --git a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java index bdd51836b9..655e0001ce 100644 --- a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java +++ b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java @@ -50,7 +50,6 @@ import sonia.scm.SCMContextProvider; import sonia.scm.TransformFilter; import sonia.scm.search.SearchRequest; import sonia.scm.search.SearchUtil; -import sonia.scm.user.UserPermissions; import sonia.scm.util.CollectionAppender; import sonia.scm.util.Util; @@ -245,7 +244,7 @@ public class DefaultGroupManager extends AbstractGroupManager @Override public Collection autocomplete(String filter) { - UserPermissions.autocomplete().check(); + GroupPermissions.autocomplete().check(); SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT); return SearchUtil.search(searchRequest, groupDAO.getAll(), group -> matches(searchRequest,group)?group:null); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IndexResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IndexResourceTest.java index 83697a3c4a..f2b1da057f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IndexResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IndexResourceTest.java @@ -13,7 +13,7 @@ import java.util.Optional; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@SubjectAware(configuration = "classpath:sonia/scm/shiro-001.ini") +@SubjectAware(configuration = "classpath:sonia/scm/shiro-002.ini") public class IndexResourceTest { @Rule @@ -94,6 +94,24 @@ public class IndexResourceTest { Assertions.assertThat(index.getLinks().getLinkBy("config")).matches(o -> !o.isPresent()); } + @Test + @SubjectAware(username = "trillian", password = "secret") + public void shouldRenderAutoCompleteLinks() { + IndexDto index = indexResource.getIndex(); + + Assertions.assertThat(index.getLinks().getLinkBy("autocompleteUsers")).matches(Optional::isPresent); + Assertions.assertThat(index.getLinks().getLinkBy("autocompleteGroups")).matches(Optional::isPresent); + } + + @Test + @SubjectAware(username = "user_without_autocomplete_permission", password = "secret") + public void userWithoutAutocompletePermissionShouldNotSeeAutoCompleteLinks() { + IndexDto index = indexResource.getIndex(); + + Assertions.assertThat(index.getLinks().getLinkBy("autocompleteUsers")).matches(o -> !o.isPresent()); + Assertions.assertThat(index.getLinks().getLinkBy("autocompleteGroups")).matches(o -> !o.isPresent()); + } + @Test @SubjectAware(username = "dent", password = "secret") public void shouldRenderAdminLinksIfAuthorized() { diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java index eed46a1f6e..c2dc685306 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java @@ -16,6 +16,7 @@ public class ResourceLinksMock { when(resourceLinks.user()).thenReturn(userLinks); when(resourceLinks.me()).thenReturn(new ResourceLinks.MeLinks(uriInfo,userLinks)); when(resourceLinks.userCollection()).thenReturn(new ResourceLinks.UserCollectionLinks(uriInfo)); + when(resourceLinks.autoComplete()).thenReturn(new ResourceLinks.AutoCompleteLinks(uriInfo)); when(resourceLinks.group()).thenReturn(new ResourceLinks.GroupLinks(uriInfo)); when(resourceLinks.groupCollection()).thenReturn(new ResourceLinks.GroupCollectionLinks(uriInfo)); when(resourceLinks.repository()).thenReturn(new ResourceLinks.RepositoryLinks(uriInfo)); diff --git a/scm-webapp/src/test/resources/sonia/scm/shiro-002.ini b/scm-webapp/src/test/resources/sonia/scm/shiro-002.ini new file mode 100644 index 0000000000..58ad2aa813 --- /dev/null +++ b/scm-webapp/src/test/resources/sonia/scm/shiro-002.ini @@ -0,0 +1,9 @@ +[users] +user_without_autocomplete_permission = secret +trillian = secret, user_ac, group_ac +dent = secret, admin + +[roles] +admin = * +user_ac = user:autocomplete +group_ac = group:autocomplete From e891ce985088f57bbd80e22a47c378a4b2f1f3f0 Mon Sep 17 00:00:00 2001 From: Mohamed Karray Date: Mon, 15 Oct 2018 13:57:55 +0200 Subject: [PATCH 4/6] modify the autocomplete link structure of the index resources --- .../src/test/java/sonia/scm/it/utils/ScmRequests.java | 5 ++--- .../sonia/scm/api/v2/resources/IndexDtoGenerator.java | 9 +++++++-- .../sonia/scm/api/v2/resources/IndexResourceTest.java | 10 ++++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java index 7ea52ba58d..6abbc6f2bd 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java @@ -534,9 +534,8 @@ public class ScmRequests { } public class IndexResponse extends ModelResponse { - - public static final String AUTOCOMPLETE_USERS = "_links.autocompleteUsers.href"; - public static final String AUTOCOMPLETE_GROUPS = "_links.autocompleteGroups.href"; + public static final String AUTOCOMPLETE_USERS = "_links.autocomplete.find{it.name=='users'}.href"; + public static final String AUTOCOMPLETE_GROUPS = "_links.autocomplete.find{it.name=='groups'}.href"; public IndexResponse(Response response) { super(response); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java index 4b78c19cc0..da4368d9b9 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IndexDtoGenerator.java @@ -1,5 +1,7 @@ package sonia.scm.api.v2.resources; +import com.google.common.collect.Lists; +import de.otto.edison.hal.Link; import de.otto.edison.hal.Links; import org.apache.shiro.SecurityUtils; import sonia.scm.SCMContextProvider; @@ -8,6 +10,7 @@ import sonia.scm.group.GroupPermissions; import sonia.scm.user.UserPermissions; import javax.inject.Inject; +import java.util.List; import static de.otto.edison.hal.Link.link; @@ -24,6 +27,7 @@ public class IndexDtoGenerator { public IndexDto generate() { Links.Builder builder = Links.linkingTo(); + List autoCompleteLinks = Lists.newArrayList(); builder.self(resourceLinks.index().self()); builder.single(link("uiPlugins", resourceLinks.uiPluginCollection().self())); if (SecurityUtils.getSubject().isAuthenticated()) { @@ -35,11 +39,12 @@ public class IndexDtoGenerator { builder.single(link("users", resourceLinks.userCollection().self())); } if (UserPermissions.autocomplete().isPermitted()) { - builder.single(link("autocompleteUsers", resourceLinks.autoComplete().users())); + autoCompleteLinks.add(Link.linkBuilder("autocomplete", resourceLinks.autoComplete().users()).withName("users").build()); } if (GroupPermissions.autocomplete().isPermitted()) { - builder.single(link("autocompleteGroups", resourceLinks.autoComplete().groups())); + autoCompleteLinks.add(Link.linkBuilder("autocomplete", resourceLinks.autoComplete().groups()).withName("groups").build()); } + builder.array(autoCompleteLinks); if (GroupPermissions.list().isPermitted()) { builder.single(link("groups", resourceLinks.groupCollection().self())); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IndexResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IndexResourceTest.java index f2b1da057f..93099cf5ea 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IndexResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/IndexResourceTest.java @@ -99,8 +99,9 @@ public class IndexResourceTest { public void shouldRenderAutoCompleteLinks() { IndexDto index = indexResource.getIndex(); - Assertions.assertThat(index.getLinks().getLinkBy("autocompleteUsers")).matches(Optional::isPresent); - Assertions.assertThat(index.getLinks().getLinkBy("autocompleteGroups")).matches(Optional::isPresent); + Assertions.assertThat(index.getLinks().getLinksBy("autocomplete")) + .extracting("name") + .containsExactlyInAnyOrder("users", "groups"); } @Test @@ -108,8 +109,9 @@ public class IndexResourceTest { public void userWithoutAutocompletePermissionShouldNotSeeAutoCompleteLinks() { IndexDto index = indexResource.getIndex(); - Assertions.assertThat(index.getLinks().getLinkBy("autocompleteUsers")).matches(o -> !o.isPresent()); - Assertions.assertThat(index.getLinks().getLinkBy("autocompleteGroups")).matches(o -> !o.isPresent()); + Assertions.assertThat(index.getLinks().getLinksBy("autocomplete")) + .extracting("name") + .doesNotContainSequence("users", "groups"); } @Test From 356b84f4cd08e0c6336c72ab9e041d4648602df3 Mon Sep 17 00:00:00 2001 From: Mohamed Karray Date: Mon, 15 Oct 2018 18:35:45 +0200 Subject: [PATCH 5/6] refactor the integration test lib to use the index resource & add unit tests for autoComplete permission --- .../java/sonia/scm/it/AutoCompleteITCase.java | 60 +-- .../src/test/java/sonia/scm/it/MeITCase.java | 21 +- .../sonia/scm/it/RepositoryAccessITCase.java | 50 +-- .../test/java/sonia/scm/it/UserITCase.java | 39 +- .../java/sonia/scm/it/utils/ScmRequests.java | 398 ++++++------------ .../java/sonia/scm/it/utils/TestData.java | 22 +- .../resources/AutoCompleteResourceTest.java | 78 +++- 7 files changed, 229 insertions(+), 439 deletions(-) diff --git a/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java b/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java index f15acdb6f4..f343f322a3 100644 --- a/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/AutoCompleteITCase.java @@ -24,67 +24,33 @@ public class AutoCompleteITCase { } @Test - public void adminShouldAutoCompleteUsers() { - createUsers(); - ScmRequests.start() - .given() - .requestIndexResource(TestData.USER_SCM_ADMIN,TestData.USER_SCM_ADMIN) - .assertStatusCode(200) - .usingIndexResponse() - .requestAutoCompleteUsers("user*") - .assertStatusCode(200) - .usingAutoCompleteResponse() - .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX)); + public void adminShouldAutoComplete() { + shouldAutocomplete(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN); } @Test - public void userShouldAutoCompleteUsersWithoutAdminPermission() { + public void userShouldAutoComplete() { String username = "nonAdmin"; String password = "pass"; TestData.createUser(username, password, false, "xml", "email@e.de"); + shouldAutocomplete(username, password); + } + + public void shouldAutocomplete(String username, String password) { createUsers(); + createGroups(); ScmRequests.start() - .given() - .requestIndexResource(username,password) + .requestIndexResource(username, password) .assertStatusCode(200) - .usingIndexResponse() + .requestAutoCompleteGroups("group*") + .assertStatusCode(200) + .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)) + .returnToPrevious() .requestAutoCompleteUsers("user*") .assertStatusCode(200) - .usingAutoCompleteResponse() .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX)); } - @Test - public void adminShouldAutoCompleteGroups() { - createGroups(); - ScmRequests.start() - .given() - .requestIndexResource(TestData.USER_SCM_ADMIN,TestData.USER_SCM_ADMIN) - .assertStatusCode(200) - .usingIndexResponse() - .applyAutoCompleteGroups("group*") - .assertStatusCode(200) - .usingAutoCompleteResponse() - .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)); - } - - @Test - public void userShouldAutoCompleteGroupsWithoutAdminPermission() { - String username = "nonAdminUser"; - String password = "pass"; - TestData.createNotAdminUser(username, password); - createGroups(); - ScmRequests.start() - .given() - .requestIndexResource(username,password) - .assertStatusCode(200) - .usingIndexResponse() - .applyAutoCompleteGroups("group*") - .assertStatusCode(200) - .usingAutoCompleteResponse() - .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)); - } - @SuppressWarnings("unchecked") private Consumer> assertAutoCompleteResult(String id) { return autoCompleteDtos -> { diff --git a/scm-it/src/test/java/sonia/scm/it/MeITCase.java b/scm-it/src/test/java/sonia/scm/it/MeITCase.java index 5a1df060c8..5809f883ca 100644 --- a/scm-it/src/test/java/sonia/scm/it/MeITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/MeITCase.java @@ -20,12 +20,9 @@ public class MeITCase { String newPassword = TestData.USER_SCM_ADMIN + "1"; // admin change the own password ScmRequests.start() - .given() - .url(TestData.getMeUrl()) - .usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) - .getMeResource() + .requestIndexResource(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) + .requestMe() .assertStatusCode(200) - .usingMeResponse() .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE)) .assertPassword(Assert::assertNull) .assertType(s -> assertThat(s).isEqualTo("xml")) @@ -33,12 +30,9 @@ public class MeITCase { .assertStatusCode(204); // assert password is changed -> login with the new Password than undo changes ScmRequests.start() - .given() - .url(TestData.getUserUrl(TestData.USER_SCM_ADMIN)) - .usernameAndPassword(TestData.USER_SCM_ADMIN, newPassword) - .getMeResource() + .requestIndexResource(TestData.USER_SCM_ADMIN, newPassword) + .requestMe() .assertStatusCode(200) - .usingMeResponse() .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE))// still admin .requestChangePassword(newPassword, TestData.USER_SCM_ADMIN) .assertStatusCode(204); @@ -51,12 +45,9 @@ public class MeITCase { String type = "not XML Type"; TestData.createUser(newUser, password, true, type, "user@scm-manager.org"); ScmRequests.start() - .given() - .url(TestData.getMeUrl()) - .usernameAndPassword(newUser, password) - .getMeResource() + .requestIndexResource(newUser, password) + .requestMe() .assertStatusCode(200) - .usingMeResponse() .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE)) .assertPassword(Assert::assertNull) .assertType(s -> assertThat(s).isEqualTo(type)) diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java index 3f8832a3f5..334274b7b0 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java @@ -44,7 +44,7 @@ public class RepositoryAccessITCase { private final String repositoryType; private File folder; - private ScmRequests.AppliedRepositoryRequest repositoryGetRequest; + private ScmRequests.RepositoryResponse repositoryResponse; public RepositoryAccessITCase(String repositoryType) { this.repositoryType = repositoryType; @@ -59,17 +59,13 @@ public class RepositoryAccessITCase { public void init() { TestData.createDefault(); folder = tempFolder.getRoot(); - repositoryGetRequest = ScmRequests.start() - .given() - .url(TestData.getDefaultRepositoryUrl(repositoryType)) - .usernameAndPassword(ADMIN_USERNAME, ADMIN_PASSWORD) - .getRepositoryResource() + String namespace = ADMIN_USERNAME; + String repo = TestData.getDefaultRepoName(repositoryType); + repositoryResponse = + ScmRequests.start() + .requestIndexResource(ADMIN_USERNAME, ADMIN_PASSWORD) + .requestRepository(namespace, repo) .assertStatusCode(HttpStatus.SC_OK); - ScmRequests.AppliedMeRequest meGetRequest = ScmRequests.start() - .given() - .url(TestData.getMeUrl()) - .usernameAndPassword(ADMIN_USERNAME, ADMIN_PASSWORD) - .getMeResource(); } @Test @@ -306,17 +302,12 @@ public class RepositoryAccessITCase { public void shouldFindFileHistory() throws IOException { RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder); Changeset changeset = RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "folder/subfolder/a.txt", "a"); - repositoryGetRequest - .usingRepositoryResponse() + repositoryResponse .requestSources() - .usingSourcesResponse() .requestSelf("folder") - .usingSourcesResponse() .requestSelf("subfolder") - .usingSourcesResponse() .requestFileHistory("a.txt") .assertStatusCode(HttpStatus.SC_OK) - .usingChangesetsResponse() .assertChangesets(changesets -> { assertThat(changesets).hasSize(1); assertThat(changesets.get(0)).containsEntry("id", changeset.getId()); @@ -332,14 +323,11 @@ public class RepositoryAccessITCase { String fileName = "a.txt"; Changeset changeset = RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "a"); String revision = changeset.getId(); - repositoryGetRequest - .usingRepositoryResponse() + repositoryResponse .requestChangesets() .assertStatusCode(HttpStatus.SC_OK) - .usingChangesetsResponse() .requestModifications(revision) .assertStatusCode(HttpStatus.SC_OK) - .usingModificationsResponse() .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) .assertAdded(addedFiles -> assertThat(addedFiles) .hasSize(1) @@ -359,14 +347,11 @@ public class RepositoryAccessITCase { Changeset changeset = RepositoryUtil.removeAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName); String revision = changeset.getId(); - repositoryGetRequest - .usingRepositoryResponse() + repositoryResponse .requestChangesets() .assertStatusCode(HttpStatus.SC_OK) - .usingChangesetsResponse() .requestModifications(revision) .assertStatusCode(HttpStatus.SC_OK) - .usingModificationsResponse() .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) .assertRemoved(removedFiles -> assertThat(removedFiles) .hasSize(1) @@ -386,14 +371,11 @@ public class RepositoryAccessITCase { Changeset changeset = RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "new Content"); String revision = changeset.getId(); - repositoryGetRequest - .usingRepositoryResponse() + repositoryResponse .requestChangesets() .assertStatusCode(HttpStatus.SC_OK) - .usingChangesetsResponse() .requestModifications(revision) .assertStatusCode(HttpStatus.SC_OK) - .usingModificationsResponse() .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) .assertModified(modifiedFiles -> assertThat(modifiedFiles) .hasSize(1) @@ -423,14 +405,11 @@ public class RepositoryAccessITCase { Changeset changeset = RepositoryUtil.commitMultipleFileModifications(repositoryClient, ADMIN_USERNAME, addedFiles, modifiedFiles, removedFiles); String revision = changeset.getId(); - repositoryGetRequest - .usingRepositoryResponse() + repositoryResponse .requestChangesets() .assertStatusCode(HttpStatus.SC_OK) - .usingChangesetsResponse() .requestModifications(revision) .assertStatusCode(HttpStatus.SC_OK) - .usingModificationsResponse() .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) .assertAdded(a -> assertThat(a) .hasSize(1) @@ -463,14 +442,11 @@ public class RepositoryAccessITCase { Changeset changeset = RepositoryUtil.commitMultipleFileModifications(repositoryClient, ADMIN_USERNAME, addedFiles, modifiedFiles, removedFiles); String revision = changeset.getId(); - repositoryGetRequest - .usingRepositoryResponse() + repositoryResponse .requestChangesets() .assertStatusCode(HttpStatus.SC_OK) - .usingChangesetsResponse() .requestModifications(revision) .assertStatusCode(HttpStatus.SC_OK) - .usingModificationsResponse() .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) .assertAdded(a -> assertThat(a) .hasSize(3) diff --git a/scm-it/src/test/java/sonia/scm/it/UserITCase.java b/scm-it/src/test/java/sonia/scm/it/UserITCase.java index 3b220da00c..a4bc4e412f 100644 --- a/scm-it/src/test/java/sonia/scm/it/UserITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/UserITCase.java @@ -23,27 +23,21 @@ public class UserITCase { String newPassword = "new_password"; // admin change the own password ScmRequests.start() - .given() - .url(TestData.getUserUrl(newUser)) - .usernameAndPassword(newUser, password) - .getUserResource() + .requestIndexResource(newUser, password) + .assertStatusCode(200) + .requestUser(newUser) .assertStatusCode(200) - .usingUserResponse() .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE)) .assertPassword(Assert::assertNull) .requestChangePassword(newPassword) // the oldPassword is not needed in the user resource .assertStatusCode(204); // assert password is changed -> login with the new Password ScmRequests.start() - .given() - .url(TestData.getUserUrl(newUser)) - .usernameAndPassword(newUser, newPassword) - .getUserResource() + .requestIndexResource(newUser, newPassword) .assertStatusCode(200) - .usingUserResponse() + .requestUser(newUser) .assertAdmin(isAdmin -> assertThat(isAdmin).isEqualTo(Boolean.TRUE)) .assertPassword(Assert::assertNull); - } @Test @@ -54,22 +48,19 @@ public class UserITCase { String newPassword = "new_password"; // admin change the password of the user ScmRequests.start() - .given() - .url(TestData.getUserUrl(newUser))// the admin get the user object - .usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) - .getUserResource() + .requestIndexResource(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) + .assertStatusCode(200) + .requestUser(newUser) .assertStatusCode(200) - .usingUserResponse() .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE)) // the user anonymous is not an admin .assertPassword(Assert::assertNull) .requestChangePassword(newPassword) // the oldPassword is not needed in the user resource .assertStatusCode(204); // assert password is changed ScmRequests.start() - .given() - .url(TestData.getUserUrl(newUser)) - .usernameAndPassword(newUser, newPassword) - .getUserResource() + .requestIndexResource(newUser, newPassword) + .assertStatusCode(200) + .requestUser(newUser) .assertStatusCode(200); } @@ -82,12 +73,10 @@ public class UserITCase { String type = "not XML Type"; TestData.createUser(newUser, password, true, type, "user@scm-manager.org"); ScmRequests.start() - .given() - .url(TestData.getMeUrl()) - .usernameAndPassword(newUser, password) - .getUserResource() + .requestIndexResource(newUser, password) + .assertStatusCode(200) + .requestUser(newUser) .assertStatusCode(200) - .usingUserResponse() .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE)) .assertPassword(Assert::assertNull) .assertType(s -> assertThat(s).isEqualTo(type)) diff --git a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java index 6abbc6f2bd..bcfbe93b3e 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java @@ -4,7 +4,6 @@ import io.restassured.RestAssured; import io.restassured.response.Response; import sonia.scm.web.VndMediaType; -import java.net.URI; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -33,8 +32,10 @@ public class ScmRequests { return new ScmRequests(); } - public Given given() { - return new Given(); + public IndexResponse requestIndexResource(String username, String password) { + setUsername(username); + setPassword(password); + return new IndexResponse(applyGETRequest(RestUtil.REST_BASE_URL.toString())); } @@ -54,28 +55,28 @@ public class ScmRequests { * * @param linkPropertyName the property name of link * @param response the response containing the link - * @param queryParams query params eg. ?q=xyz&count=12 + * @param params query params eg. ?q=xyz&count=12 or path params eg. namespace/name * @return the response of the GET request using the given link */ - private Response applyGETRequestFromLinkWithParams(Response response, String linkPropertyName, String queryParams) { + private Response applyGETRequestFromLinkWithParams(Response response, String linkPropertyName, String params) { return applyGETRequestWithQueryParams(response .then() .extract() - .path(linkPropertyName), queryParams); + .path(linkPropertyName), params); } /** * Apply a GET Request to the given url and return the response. * - * @param url the url of the GET request - * @param htmlQueryParams query params eg. ?q=xyz&count=12 + * @param url the url of the GET request + * @param params query params eg. ?q=xyz&count=12 or path params eg. namespace/name * @return the response of the GET request using the given url */ - private Response applyGETRequestWithQueryParams(String url, String htmlQueryParams) { + private Response applyGETRequestWithQueryParams(String url, String params) { return RestAssured.given() .auth().preemptive().basic(username, password) .when() - .get(url + htmlQueryParams); + .get(url + params); } /** @@ -123,11 +124,6 @@ public class ScmRequests { .put(url); } - - private void setUrl(String url) { - this.url = url; - } - private void setUsername(String username) { this.username = username; } @@ -136,308 +132,185 @@ public class ScmRequests { this.password = password; } - private String getUrl() { - return url; - } - private String getUsername() { - return username; - } + public class IndexResponse extends ModelResponse { + public static final String LINK_AUTOCOMPLETE_USERS = "_links.autocomplete.find{it.name=='users'}.href"; + public static final String LINK_AUTOCOMPLETE_GROUPS = "_links.autocomplete.find{it.name=='groups'}.href"; + public static final String LINK_REPOSITORIES = "_links.repositories.href"; + private static final String LINK_ME = "_links.me.href"; + private static final String LINK_USERS = "_links.users.href"; - private String getPassword() { - return password; - } - - public class Given { - - public GivenUrl url(String url) { - setUrl(url); - return new GivenUrl(); + public IndexResponse(Response response) { + super(response, null); } - public AppliedIndexResource requestIndexResource(String username, String password) { - setUsername(username); - setPassword(password); - return new AppliedIndexResource(applyGETRequest(RestUtil.REST_BASE_URL.toString())); + public AutoCompleteResponse requestAutoCompleteUsers(String q) { + return new AutoCompleteResponse<>(applyGETRequestFromLinkWithParams(response, LINK_AUTOCOMPLETE_USERS, "?q=" + q), this); } - public GivenUrl url(URI url) { - setUrl(url.toString()); - return new GivenUrl(); + public AutoCompleteResponse requestAutoCompleteGroups(String q) { + return new AutoCompleteResponse<>(applyGETRequestFromLinkWithParams(response, LINK_AUTOCOMPLETE_GROUPS, "?q=" + q), this); + } + + public RepositoryResponse requestRepository(String namespace, String name) { + return new RepositoryResponse<>(applyGETRequestFromLinkWithParams(response, LINK_REPOSITORIES, namespace + "/" + name), this); + } + + public MeResponse requestMe() { + return new MeResponse<>(applyGETRequestFromLink(response, LINK_ME), this); + } + + public UserResponse requestUser(String username) { + return new UserResponse<>(applyGETRequestFromLinkWithParams(response, LINK_USERS, username), this); } } - public class GivenWithUrlAndAuth { - public AppliedMeRequest getMeResource() { - return new AppliedMeRequest(applyGETRequest(url)); + public class RepositoryResponse extends ModelResponse, PREV> { + + + public static final String LINKS_SOURCES = "_links.sources.href"; + public static final String LINKS_CHANGESETS = "_links.changesets.href"; + + public RepositoryResponse(Response response, PREV previousResponse) { + super(response, previousResponse); } - public AppliedUserRequest getUserResource() { - return new AppliedUserRequest(applyGETRequest(url)); + public SourcesResponse requestSources() { + return new SourcesResponse<>(applyGETRequestFromLink(response, LINKS_SOURCES), this); } - public AppliedRepositoryRequest getRepositoryResource() { - return new AppliedRepositoryRequest( - applyGETRequest(url) - ); - } - - public AppliedAutoCompleteRequest getAutoCompleteResource() { - return new AppliedAutoCompleteRequest( - applyGETRequest(url) - ); - } - } - - public class AppliedRequest { - private Response response; - - public AppliedRequest(Response response) { - this.response = response; - } - - /** - * apply custom assertions to the actual response - * - * @param consumer consume the response in order to assert the content. the header, the payload etc.. - * @return the self object - */ - public SELF assertResponse(Consumer consumer) { - consumer.accept(response); - return (SELF) this; - } - - /** - * special assertion of the status code - * - * @param expectedStatusCode the expected status code - * @return the self object - */ - public SELF assertStatusCode(int expectedStatusCode) { - this.response.then().assertThat().statusCode(expectedStatusCode); - return (SELF) this; + public ChangesetsResponse requestChangesets() { + return new ChangesetsResponse<>(applyGETRequestFromLink(response, LINKS_CHANGESETS), this); } } - public class AppliedRepositoryRequest extends AppliedRequest { + public class ChangesetsResponse extends ModelResponse, PREV> { - public AppliedRepositoryRequest(Response response) { - super(response); - } - - public RepositoryResponse usingRepositoryResponse() { - return new RepositoryResponse(super.response); - } - } - - public class RepositoryResponse { - - private Response repositoryResponse; - - public RepositoryResponse(Response repositoryResponse) { - this.repositoryResponse = repositoryResponse; - } - - public AppliedSourcesRequest requestSources() { - return new AppliedSourcesRequest(applyGETRequestFromLink(repositoryResponse, "_links.sources.href")); - } - - public AppliedChangesetsRequest requestChangesets() { - return new AppliedChangesetsRequest(applyGETRequestFromLink(repositoryResponse, "_links.changesets.href")); - } - } - - public class AppliedChangesetsRequest extends AppliedRequest { - - public AppliedChangesetsRequest(Response response) { - super(response); - } - - public ChangesetsResponse usingChangesetsResponse() { - return new ChangesetsResponse(super.response); - } - } - - public class ChangesetsResponse { - private Response changesetsResponse; - - public ChangesetsResponse(Response changesetsResponse) { - this.changesetsResponse = changesetsResponse; + public ChangesetsResponse(Response response, PREV previousResponse) { + super(response, previousResponse); } public ChangesetsResponse assertChangesets(Consumer> changesetsConsumer) { - List changesets = changesetsResponse.then().extract().path("_embedded.changesets"); + List changesets = response.then().extract().path("_embedded.changesets"); changesetsConsumer.accept(changesets); return this; } - public AppliedDiffRequest requestDiff(String revision) { - return new AppliedDiffRequest(applyGETRequestFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.diff.href")); + public DiffResponse requestDiff(String revision) { + return new DiffResponse<>(applyGETRequestFromLink(response, "_embedded.changesets.find{it.id=='" + revision + "'}._links.diff.href"), this); } - public AppliedModificationsRequest requestModifications(String revision) { - return new AppliedModificationsRequest(applyGETRequestFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.modifications.href")); + public ModificationsResponse requestModifications(String revision) { + return new ModificationsResponse<>(applyGETRequestFromLink(response, "_embedded.changesets.find{it.id=='" + revision + "'}._links.modifications.href"), this); } } - public class AppliedSourcesRequest extends AppliedRequest { - public AppliedSourcesRequest(Response sourcesResponse) { - super(sourcesResponse); - } + public class SourcesResponse extends ModelResponse, PREV> { - public SourcesResponse usingSourcesResponse() { - return new SourcesResponse(super.response); - } - } - - public class SourcesResponse { - - private Response sourcesResponse; - - public SourcesResponse(Response sourcesResponse) { - this.sourcesResponse = sourcesResponse; + public SourcesResponse(Response response, PREV previousResponse) { + super(response, previousResponse); } public SourcesResponse assertRevision(Consumer assertRevision) { - String revision = sourcesResponse.then().extract().path("revision"); + String revision = response.then().extract().path("revision"); assertRevision.accept(revision); return this; } public SourcesResponse assertFiles(Consumer assertFiles) { - List files = sourcesResponse.then().extract().path("files"); + List files = response.then().extract().path("files"); assertFiles.accept(files); return this; } - public AppliedChangesetsRequest requestFileHistory(String fileName) { - return new AppliedChangesetsRequest(applyGETRequestFromLink(sourcesResponse, "_embedded.files.find{it.name=='" + fileName + "'}._links.history.href")); + public ChangesetsResponse requestFileHistory(String fileName) { + return new ChangesetsResponse<>(applyGETRequestFromLink(response, "_embedded.files.find{it.name=='" + fileName + "'}._links.history.href"), this); } - public AppliedSourcesRequest requestSelf(String fileName) { - return new AppliedSourcesRequest(applyGETRequestFromLink(sourcesResponse, "_embedded.files.find{it.name=='" + fileName + "'}._links.self.href")); + public SourcesResponse requestSelf(String fileName) { + return new SourcesResponse<>(applyGETRequestFromLink(response, "_embedded.files.find{it.name=='" + fileName + "'}._links.self.href"), this); } } - public class AppliedDiffRequest extends AppliedRequest { + public class ModificationsResponse extends ModelResponse, PREV> { - public AppliedDiffRequest(Response response) { - super(response); - } - } - - public class GivenUrl { - - public GivenWithUrlAndAuth usernameAndPassword(String username, String password) { - setUsername(username); - setPassword(password); - return new GivenWithUrlAndAuth(); - } - } - - public class AppliedModificationsRequest extends AppliedRequest { - public AppliedModificationsRequest(Response response) { - super(response); + public ModificationsResponse(Response response, PREV previousResponse) { + super(response, previousResponse); } - public ModificationsResponse usingModificationsResponse() { - return new ModificationsResponse(super.response); - } - - } - - public class ModificationsResponse { - private Response resource; - - public ModificationsResponse(Response resource) { - this.resource = resource; - } - - public ModificationsResponse assertRevision(Consumer assertRevision) { - String revision = resource.then().extract().path("revision"); + public ModificationsResponse assertRevision(Consumer assertRevision) { + String revision = response.then().extract().path("revision"); assertRevision.accept(revision); return this; } - public ModificationsResponse assertAdded(Consumer> assertAdded) { - List added = resource.then().extract().path("added"); + public ModificationsResponse assertAdded(Consumer> assertAdded) { + List added = response.then().extract().path("added"); assertAdded.accept(added); return this; } - public ModificationsResponse assertRemoved(Consumer> assertRemoved) { - List removed = resource.then().extract().path("removed"); + public ModificationsResponse assertRemoved(Consumer> assertRemoved) { + List removed = response.then().extract().path("removed"); assertRemoved.accept(removed); return this; } - public ModificationsResponse assertModified(Consumer> assertModified) { - List modified = resource.then().extract().path("modified"); + public ModificationsResponse assertModified(Consumer> assertModified) { + List modified = response.then().extract().path("modified"); assertModified.accept(modified); return this; } } - public class AppliedMeRequest extends AppliedRequest { - - public AppliedMeRequest(Response response) { - super(response); - } - - public MeResponse usingMeResponse() { - return new MeResponse(super.response); - } - - } - - public class MeResponse extends UserResponse { + public class MeResponse extends UserResponse { - public MeResponse(Response response) { - super(response); - } - - public AppliedChangePasswordRequest requestChangePassword(String oldPassword, String newPassword) { - return new AppliedChangePasswordRequest(applyPUTRequestFromLink(super.response, "_links.password.href", VndMediaType.PASSWORD_CHANGE, createPasswordChangeJson(oldPassword, newPassword))); + public MeResponse(Response response, PREV previousResponse) { + super(response, previousResponse); } } - public class UserResponse extends ModelResponse { + public class UserResponse extends ModelResponse, PREV> { public static final String LINKS_PASSWORD_HREF = "_links.password.href"; - public UserResponse(Response response) { - super(response); + public UserResponse(Response response, PREV previousResponse) { + super(response, previousResponse); } - public SELF assertPassword(Consumer assertPassword) { + public UserResponse assertPassword(Consumer assertPassword) { return super.assertSingleProperty(assertPassword, "password"); } - public SELF assertType(Consumer assertType) { + public UserResponse assertType(Consumer assertType) { return assertSingleProperty(assertType, "type"); } - public SELF assertAdmin(Consumer assertAdmin) { + public UserResponse assertAdmin(Consumer assertAdmin) { return assertSingleProperty(assertAdmin, "admin"); } - public SELF assertPasswordLinkDoesNotExists() { + public UserResponse assertPasswordLinkDoesNotExists() { return assertPropertyPathDoesNotExists(LINKS_PASSWORD_HREF); } - public SELF assertPasswordLinkExists() { + public UserResponse assertPasswordLinkExists() { return assertPropertyPathExists(LINKS_PASSWORD_HREF); } - public AppliedChangePasswordRequest requestChangePassword(String newPassword) { - return new AppliedChangePasswordRequest(applyPUTRequestFromLink(super.response, LINKS_PASSWORD_HREF, VndMediaType.PASSWORD_CHANGE, createPasswordChangeJson(null, newPassword))); + public ChangePasswordResponse requestChangePassword(String newPassword) { + return requestChangePassword(null, newPassword); + } + + public ChangePasswordResponse requestChangePassword(String oldPassword, String newPassword) { + return new ChangePasswordResponse<>(applyPUTRequestFromLink(super.response, LINKS_PASSWORD_HREF, VndMediaType.PASSWORD_CHANGE, createPasswordChangeJson(oldPassword, newPassword)), this); } } @@ -446,12 +319,18 @@ public class ScmRequests { /** * encapsulate standard assertions over model properties */ - public class ModelResponse { + public class ModelResponse, PREV extends ModelResponse> { + protected PREV previousResponse; protected Response response; - public ModelResponse(Response response) { + public ModelResponse(Response response, PREV previousResponse) { this.response = response; + this.previousResponse = previousResponse; + } + + public PREV returnToPrevious() { + return previousResponse; } public SELF assertSingleProperty(Consumer assertSingleProperty, String propertyJsonPath) { @@ -475,46 +354,26 @@ public class ScmRequests { assertProperties.accept(properties); return (SELF) this; } + + /** + * special assertion of the status code + * + * @param expectedStatusCode the expected status code + * @return the self object + */ + public SELF assertStatusCode(int expectedStatusCode) { + this.response.then().assertThat().statusCode(expectedStatusCode); + return (SELF) this; + } } - public class AppliedChangePasswordRequest extends AppliedRequest { + public class AutoCompleteResponse extends ModelResponse, PREV> { - public AppliedChangePasswordRequest(Response response) { - super(response); + public AutoCompleteResponse(Response response, PREV previousResponse) { + super(response, previousResponse); } - } - - public class AppliedUserRequest extends AppliedRequest { - - public AppliedUserRequest(Response response) { - super(response); - } - - public UserResponse usingUserResponse() { - return new UserResponse(super.response); - } - - } - - public class AppliedAutoCompleteRequest extends AppliedRequest { - public AppliedAutoCompleteRequest(Response response) { - super(response); - } - - public AutoCompleteResponse usingAutoCompleteResponse() { - return new AutoCompleteResponse(super.response); - } - - } - - public class AutoCompleteResponse extends ModelResponse { - - public AutoCompleteResponse(Response response) { - super(response); - } - - public AutoCompleteResponse assertAutoCompleteResults(Consumer> checker) { + public AutoCompleteResponse assertAutoCompleteResults(Consumer> checker) { List result = response.then().extract().path(""); checker.accept(result); return this; @@ -522,31 +381,18 @@ public class ScmRequests { } - public class AppliedIndexResource extends AppliedRequest { - public AppliedIndexResource(Response response) { - super(response); - } - public IndexResponse usingIndexResponse() { - return new IndexResponse(super.response); - } + public class DiffResponse extends ModelResponse, PREV> { + public DiffResponse(Response response, PREV previousResponse) { + super(response, previousResponse); + } } - public class IndexResponse extends ModelResponse { - public static final String AUTOCOMPLETE_USERS = "_links.autocomplete.find{it.name=='users'}.href"; - public static final String AUTOCOMPLETE_GROUPS = "_links.autocomplete.find{it.name=='groups'}.href"; + public class ChangePasswordResponse extends ModelResponse, PREV> { - public IndexResponse(Response response) { - super(response); - } - - public AppliedAutoCompleteRequest requestAutoCompleteUsers(String q) { - return new AppliedAutoCompleteRequest(applyGETRequestFromLinkWithParams(response, AUTOCOMPLETE_USERS, "?q="+q)); - } - - public AppliedAutoCompleteRequest applyAutoCompleteGroups(String q) { - return new AppliedAutoCompleteRequest(applyGETRequestFromLinkWithParams(response, AUTOCOMPLETE_GROUPS, "?q="+q)); + public ChangePasswordResponse(Response response, PREV previousResponse) { + super(response, previousResponse); } } } diff --git a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java index af9032e62e..a164fc6649 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java @@ -203,12 +203,16 @@ public class TestData { return JSON_BUILDER .add("contact", "zaphod.beeblebrox@hitchhiker.com") .add("description", "Heart of Gold") - .add("name", "HeartOfGold-" + repositoryType) + .add("name", getDefaultRepoName(repositoryType)) .add("archived", false) .add("type", repositoryType) .build().toString(); } + public static String getDefaultRepoName(String repositoryType) { + return "HeartOfGold-" + repositoryType; + } + public static String getGroupJson(String groupname , String desc) { return JSON_BUILDER .add("name", groupname) @@ -216,10 +220,6 @@ public class TestData { .build().toString(); } - public static URI getMeUrl() { - return RestUtil.createResourceUrl("me/"); - } - public static URI getGroupsUrl() { return RestUtil.createResourceUrl("groups/"); } @@ -228,18 +228,6 @@ public class TestData { return RestUtil.createResourceUrl("users/"); } - public static URI getUserUrl(String username) { - return getUsersUrl().resolve(username); - } - - public static URI getUsersAutoCompleteUrl(String query ) { - return RestUtil.createResourceUrl("autocomplete/users?q="+query); - } - - public static URI getGroupsAutoCompleteUrl(String query ) { - return RestUtil.createResourceUrl("autocomplete/groups?q="+query); - } - public static String createPasswordChangeJson(String oldPassword, String newPassword) { return JSON_BUILDER .add("oldPassword", oldPassword) diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java index 68bb165140..2cab41bfbf 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AutoCompleteResourceTest.java @@ -1,16 +1,16 @@ package sonia.scm.api.v2.resources; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.shiro.subject.Subject; -import org.apache.shiro.subject.support.SubjectThreadState; +import com.github.sdorra.shiro.ShiroRule; +import com.github.sdorra.shiro.SubjectAware; import org.apache.shiro.util.ThreadContext; -import org.apache.shiro.util.ThreadState; import org.assertj.core.util.Lists; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @@ -43,16 +43,17 @@ import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; +@SubjectAware(configuration = "classpath:sonia/scm/shiro-002.ini") @RunWith(MockitoJUnitRunner.Silent.class) public class AutoCompleteResourceTest { + @Rule + public final ShiroRule shiroRule = new ShiroRule(); + public static final String URL = "/" + AutoCompleteResource.PATH; 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 userDao; private XmlGroupDAO groupDao; private XmlDatabase xmlDB; @@ -75,9 +76,6 @@ public class AutoCompleteResourceTest { GroupManager groupManager = new DefaultGroupManager(groupDao); AutoCompleteResource autoCompleteResource = new AutoCompleteResource(mapper, userManager, groupManager); dispatcher = createDispatcher(autoCompleteResource); - subjectThreadState.bind(); - ThreadContext.bind(subject); - when(subject.isPermitted(any(String.class))).thenReturn(true); } @After @@ -85,19 +83,6 @@ public class AutoCompleteResourceTest { ThreadContext.unbindSubject(); } - @Test - public void shouldGet400OnFailedParameterForUserSearch() throws Exception { - MockHttpRequest request = MockHttpRequest - .get("/" + AutoCompleteResource.PATH + "users") - .contentType(VndMediaType.AUTOCOMPLETE) - .accept(VndMediaType.AUTOCOMPLETE); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(400, response.getStatus()); - } - @Test public void shouldGet400IfParameterLengthLessThan2CharsForUserSearch() throws Exception { MockHttpRequest request = MockHttpRequest @@ -112,6 +97,21 @@ public class AutoCompleteResourceTest { } @Test + @SubjectAware(username = "trillian", password = "secret") + public void shouldGet400OnFailedParameterForUserSearch() throws Exception { + MockHttpRequest request = MockHttpRequest + .get("/" + AutoCompleteResource.PATH + "users") + .contentType(VndMediaType.AUTOCOMPLETE) + .accept(VndMediaType.AUTOCOMPLETE); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(400, response.getStatus()); + } + + @Test + @SubjectAware(username = "trillian", password = "secret") public void shouldSearchUsers() throws Exception { ArrayList users = Lists.newArrayList(createMockUser("YuCantFindMe", "ha ha"), createMockUser("user1", "User 1"), createMockUser("user2", "User 2")); String searched = "user"; @@ -134,6 +134,22 @@ public class AutoCompleteResourceTest { } @Test + @SubjectAware(username = "user_without_autocomplete_permission", password = "secret") + public void shouldGet403OnAutoCompleteUsers() throws Exception { + MockHttpRequest request = MockHttpRequest + .get("/" + AutoCompleteResource.PATH + "users?q=user" ) + .contentType(VndMediaType.AUTOCOMPLETE) + .accept(VndMediaType.AUTOCOMPLETE); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); + } + + + @Test + @SubjectAware(username = "trillian", password = "secret") public void shouldSearchUsersWithDefaultLimitLength() throws Exception { List userList = IntStream.range(0, 10).boxed().map(i -> createMockUser("user" + i, "User " + i)).collect(Collectors.toList()); when(xmlDB.values()).thenReturn(userList); @@ -150,6 +166,7 @@ public class AutoCompleteResourceTest { } @Test + @SubjectAware(username = "trillian", password = "secret") public void shouldGet400OnFailedParameterForGroupSearch() throws Exception { MockHttpRequest request = MockHttpRequest .get("/" + AutoCompleteResource.PATH + "groups") @@ -163,6 +180,7 @@ public class AutoCompleteResourceTest { } @Test + @SubjectAware(username = "trillian", password = "secret") public void shouldGet400IfParameterLengthLessThan2CharsForGroupSearch() throws Exception { MockHttpRequest request = MockHttpRequest .get("/" + AutoCompleteResource.PATH + "groups?q=a") @@ -176,6 +194,7 @@ public class AutoCompleteResourceTest { } @Test + @SubjectAware(username = "trillian", password = "secret") public void shouldSearchGroups() throws Exception { ArrayList groups = Lists.newArrayList(createMockGroup("YuCantFindMe"), createMockGroup("group_1"), createMockGroup("group_2")); String searched = "group"; @@ -197,6 +216,21 @@ public class AutoCompleteResourceTest { } @Test + @SubjectAware(username = "user_without_autocomplete_permission", password = "secret") + public void shouldGet403OnAutoCompleteGroups() throws Exception { + MockHttpRequest request = MockHttpRequest + .get("/" + AutoCompleteResource.PATH + "groups?q=user" ) + .contentType(VndMediaType.AUTOCOMPLETE) + .accept(VndMediaType.AUTOCOMPLETE); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); + } + + @Test + @SubjectAware(username = "trillian", password = "secret") public void shouldSearchGroupsWithDefaultLimitLength() throws Exception { List groups = IntStream.range(0, 10).boxed().map(i -> createMockGroup("group_" + i)).collect(Collectors.toList()); when(xmlDB.values()).thenReturn(groups); From 548820dd78f2db2d36545db9e3c829641f9f89eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 16 Oct 2018 11:49:03 +0000 Subject: [PATCH 6/6] Close branch feature/autocomplete_v2