Merge with 2.0.0-m3

This commit is contained in:
René Pfeuffer
2018-09-21 10:29:21 +02:00
48 changed files with 1485 additions and 823 deletions

View File

@@ -0,0 +1,79 @@
package sonia.scm.it;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import sonia.scm.it.utils.ScmRequests;
import sonia.scm.it.utils.TestData;
import static org.assertj.core.api.Assertions.assertThat;
public class MeITCase {
@Before
public void init() {
TestData.cleanup();
}
@Test
public void adminShouldChangeOwnPassword() {
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()
.assertStatusCode(200)
.usingMeResponse()
.assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE))
.assertPassword(Assert::assertNull)
.assertType(s -> assertThat(s).isEqualTo("xml"))
.requestChangePassword(TestData.USER_SCM_ADMIN, newPassword)
.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()
.assertStatusCode(200)
.usingMeResponse()
.assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE))// still admin
.requestChangePassword(newPassword, TestData.USER_SCM_ADMIN)
.assertStatusCode(204);
}
@Test
public void shouldHidePasswordLinkIfUserTypeIsNotXML() {
String newUser = "user";
String password = "pass";
String type = "not XML Type";
TestData.createUser(newUser, password, true, type);
ScmRequests.start()
.given()
.url(TestData.getMeUrl())
.usernameAndPassword(newUser, password)
.getMeResource()
.assertStatusCode(200)
.usingMeResponse()
.assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE))
.assertPassword(Assert::assertNull)
.assertType(s -> assertThat(s).isEqualTo(type))
.assertPasswordLinkDoesNotExists();
}
@Test
public void shouldGet403IfUserIsNotAdmin() {
String newUser = "user";
String password = "pass";
String type = "xml";
TestData.createUser(newUser, password, false, type);
ScmRequests.start()
.given()
.url(TestData.getMeUrl())
.usernameAndPassword(newUser, password)
.getMeResource()
.assertStatusCode(403);
}
}

View File

@@ -39,6 +39,8 @@ import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import sonia.scm.it.utils.RepositoryUtil;
import sonia.scm.it.utils.TestData;
import sonia.scm.repository.PermissionType;
import sonia.scm.repository.client.api.RepositoryClient;
import sonia.scm.repository.client.api.RepositoryClientException;
@@ -51,11 +53,11 @@ import java.util.Objects;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static sonia.scm.it.RepositoryUtil.addAndCommitRandomFile;
import static sonia.scm.it.RestUtil.given;
import static sonia.scm.it.ScmTypes.availableScmTypes;
import static sonia.scm.it.TestData.USER_SCM_ADMIN;
import static sonia.scm.it.TestData.callRepository;
import static sonia.scm.it.utils.RepositoryUtil.addAndCommitRandomFile;
import static sonia.scm.it.utils.RestUtil.given;
import static sonia.scm.it.utils.ScmTypes.availableScmTypes;
import static sonia.scm.it.utils.TestData.USER_SCM_ADMIN;
import static sonia.scm.it.utils.TestData.callRepository;
@RunWith(Parameterized.class)
public class PermissionsITCase {

View File

@@ -42,6 +42,8 @@ import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import sonia.scm.it.utils.RepositoryUtil;
import sonia.scm.it.utils.TestData;
import sonia.scm.repository.client.api.RepositoryClient;
import sonia.scm.web.VndMediaType;
@@ -53,11 +55,11 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static sonia.scm.it.RegExMatcher.matchesPattern;
import static sonia.scm.it.RestUtil.createResourceUrl;
import static sonia.scm.it.RestUtil.given;
import static sonia.scm.it.ScmTypes.availableScmTypes;
import static sonia.scm.it.TestData.repositoryJson;
import static sonia.scm.it.utils.RegExMatcher.matchesPattern;
import static sonia.scm.it.utils.RestUtil.createResourceUrl;
import static sonia.scm.it.utils.RestUtil.given;
import static sonia.scm.it.utils.ScmTypes.availableScmTypes;
import static sonia.scm.it.utils.TestData.repositoryJson;
@RunWith(Parameterized.class)
public class RepositoriesITCase {

View File

@@ -4,7 +4,6 @@ import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import org.apache.http.HttpStatus;
import org.assertj.core.util.Lists;
import org.assertj.core.util.Maps;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
@@ -12,6 +11,9 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import sonia.scm.it.utils.RepositoryUtil;
import sonia.scm.it.utils.ScmRequests;
import sonia.scm.it.utils.TestData;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.client.api.ClientCommand;
import sonia.scm.repository.client.api.RepositoryClient;
@@ -29,10 +31,10 @@ import static java.lang.Thread.sleep;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertNotNull;
import static sonia.scm.it.RestUtil.ADMIN_PASSWORD;
import static sonia.scm.it.RestUtil.ADMIN_USERNAME;
import static sonia.scm.it.RestUtil.given;
import static sonia.scm.it.ScmTypes.availableScmTypes;
import static sonia.scm.it.utils.RestUtil.ADMIN_PASSWORD;
import static sonia.scm.it.utils.RestUtil.ADMIN_USERNAME;
import static sonia.scm.it.utils.RestUtil.given;
import static sonia.scm.it.utils.ScmTypes.availableScmTypes;
@RunWith(Parameterized.class)
public class RepositoryAccessITCase {
@@ -42,7 +44,7 @@ public class RepositoryAccessITCase {
private final String repositoryType;
private File folder;
private RepositoryRequests.AppliedRepositoryGetRequest repositoryGetRequest;
private ScmRequests.AppliedRepositoryRequest repositoryGetRequest;
public RepositoryAccessITCase(String repositoryType) {
this.repositoryType = repositoryType;
@@ -57,12 +59,17 @@ public class RepositoryAccessITCase {
public void init() {
TestData.createDefault();
folder = tempFolder.getRoot();
repositoryGetRequest = RepositoryRequests.start()
repositoryGetRequest = ScmRequests.start()
.given()
.url(TestData.getDefaultRepositoryUrl(repositoryType))
.usernameAndPassword(ADMIN_USERNAME, ADMIN_PASSWORD)
.get()
.getRepositoryResource()
.assertStatusCode(HttpStatus.SC_OK);
ScmRequests.AppliedMeRequest meGetRequest = ScmRequests.start()
.given()
.url(TestData.getMeUrl())
.usernameAndPassword(ADMIN_USERNAME, ADMIN_PASSWORD)
.getMeResource();
}
@Test

View File

@@ -1,293 +0,0 @@
package sonia.scm.it;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* Encapsulate rest requests of a repository in builder pattern
* <p>
* A Get Request can be applied with the methods request*()
* These methods return a AppliedGet*Request object
* This object can be used to apply general assertions over the rest Assured response
* In the AppliedGet*Request classes there is a using*Response() method
* that return the *Response class containing specific operations related to the specific response
* the *Response class contains also the request*() method to apply the next GET request from a link in the response.
*/
public class RepositoryRequests {
private String url;
private String username;
private String password;
static RepositoryRequests start() {
return new RepositoryRequests();
}
Given given() {
return new Given();
}
/**
* 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
* @return the response of the GET request using the given link
*/
private Response getResponseFromLink(Response response, String linkPropertyName) {
return getResponse(response
.then()
.extract()
.path(linkPropertyName));
}
/**
* Apply a GET Request to the given <code>url</code> and return the response.
*
* @param url the url of the GET request
* @return the response of the GET request using the given <code>url</code>
*/
private Response getResponse(String url) {
return RestAssured.given()
.auth().preemptive().basic(username, password)
.when()
.get(url);
}
private void setUrl(String url) {
this.url = url;
}
private void setUsername(String username) {
this.username = username;
}
private void setPassword(String password) {
this.password = password;
}
private String getUrl() {
return url;
}
private String getUsername() {
return username;
}
private String getPassword() {
return password;
}
class Given {
GivenUrl url(String url) {
setUrl(url);
return new GivenUrl();
}
}
class GivenWithUrlAndAuth {
AppliedRepositoryGetRequest get() {
return new AppliedRepositoryGetRequest(
getResponse(url)
);
}
}
class AppliedGetRequest<SELF extends AppliedGetRequest> {
private Response response;
public AppliedGetRequest(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
*/
SELF assertResponse(Consumer<Response> consumer) {
consumer.accept(response);
return (SELF) this;
}
/**
* special assertion of the status code
*
* @param expectedStatusCode the expected status code
* @return the self object
*/
SELF assertStatusCode(int expectedStatusCode) {
this.response.then().assertThat().statusCode(expectedStatusCode);
return (SELF) this;
}
}
class AppliedRepositoryGetRequest extends AppliedGetRequest<AppliedRepositoryGetRequest> {
AppliedRepositoryGetRequest(Response response) {
super(response);
}
RepositoryResponse usingRepositoryResponse() {
return new RepositoryResponse(super.response);
}
}
class RepositoryResponse {
private Response repositoryResponse;
public RepositoryResponse(Response repositoryResponse) {
this.repositoryResponse = repositoryResponse;
}
AppliedGetSourcesRequest requestSources() {
return new AppliedGetSourcesRequest(getResponseFromLink(repositoryResponse, "_links.sources.href"));
}
AppliedGetChangesetsRequest requestChangesets() {
return new AppliedGetChangesetsRequest(getResponseFromLink(repositoryResponse, "_links.changesets.href"));
}
}
class AppliedGetChangesetsRequest extends AppliedGetRequest<AppliedGetChangesetsRequest> {
AppliedGetChangesetsRequest(Response response) {
super(response);
}
ChangesetsResponse usingChangesetsResponse() {
return new ChangesetsResponse(super.response);
}
}
class ChangesetsResponse {
private Response changesetsResponse;
public ChangesetsResponse(Response changesetsResponse) {
this.changesetsResponse = changesetsResponse;
}
ChangesetsResponse assertChangesets(Consumer<List<Map>> changesetsConsumer) {
List<Map> changesets = changesetsResponse.then().extract().path("_embedded.changesets");
changesetsConsumer.accept(changesets);
return this;
}
AppliedGetDiffRequest requestDiff(String revision) {
return new AppliedGetDiffRequest(getResponseFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.diff.href"));
}
public AppliedGetModificationsRequest requestModifications(String revision) {
return new AppliedGetModificationsRequest(getResponseFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.modifications.href"));
}
}
class AppliedGetSourcesRequest extends AppliedGetRequest<AppliedGetSourcesRequest> {
public AppliedGetSourcesRequest(Response sourcesResponse) {
super(sourcesResponse);
}
SourcesResponse usingSourcesResponse() {
return new SourcesResponse(super.response);
}
}
class SourcesResponse {
private Response sourcesResponse;
SourcesResponse(Response sourcesResponse) {
this.sourcesResponse = sourcesResponse;
}
SourcesResponse assertRevision(Consumer<String> assertRevision) {
String revision = sourcesResponse.then().extract().path("revision");
assertRevision.accept(revision);
return this;
}
SourcesResponse assertFiles(Consumer<List> assertFiles) {
List files = sourcesResponse.then().extract().path("files");
assertFiles.accept(files);
return this;
}
AppliedGetChangesetsRequest requestFileHistory(String fileName) {
return new AppliedGetChangesetsRequest(getResponseFromLink(sourcesResponse, "_embedded.files.find{it.name=='" + fileName + "'}._links.history.href"));
}
AppliedGetSourcesRequest requestSelf(String fileName) {
return new AppliedGetSourcesRequest(getResponseFromLink(sourcesResponse, "_embedded.files.find{it.name=='" + fileName + "'}._links.self.href"));
}
}
class AppliedGetDiffRequest extends AppliedGetRequest<AppliedGetDiffRequest> {
AppliedGetDiffRequest(Response response) {
super(response);
}
}
class GivenUrl {
GivenWithUrlAndAuth usernameAndPassword(String username, String password) {
setUsername(username);
setPassword(password);
return new GivenWithUrlAndAuth();
}
}
class AppliedGetModificationsRequest extends AppliedGetRequest<AppliedGetModificationsRequest> {
public AppliedGetModificationsRequest(Response response) { super(response); }
ModificationsResponse usingModificationsResponse() {
return new ModificationsResponse(super.response);
}
}
class ModificationsResponse {
private Response resource;
public ModificationsResponse(Response resource) {
this.resource = resource;
}
ModificationsResponse assertRevision(Consumer<String> assertRevision) {
String revision = resource.then().extract().path("revision");
assertRevision.accept(revision);
return this;
}
ModificationsResponse assertAdded(Consumer<List<String>> assertAdded) {
List<String > added = resource.then().extract().path("added");
assertAdded.accept(added);
return this;
}
ModificationsResponse assertRemoved(Consumer<List<String>> assertRemoved) {
List<String > removed = resource.then().extract().path("removed");
assertRemoved.accept(removed);
return this;
}
ModificationsResponse assertModified(Consumer<List<String>> assertModified) {
List<String > modified = resource.then().extract().path("modified");
assertModified.accept(modified);
return this;
}
}
}

View File

@@ -0,0 +1,113 @@
package sonia.scm.it;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import sonia.scm.it.utils.ScmRequests;
import sonia.scm.it.utils.TestData;
import static org.assertj.core.api.Assertions.assertThat;
public class UserITCase {
@Before
public void init(){
TestData.cleanup();
}
@Test
public void adminShouldChangeOwnPassword() {
String newUser = "user";
String password = "pass";
TestData.createUser(newUser, password, true, "xml");
String newPassword = "new_password";
// admin change the own password
ScmRequests.start()
.given()
.url(TestData.getUserUrl(newUser))
.usernameAndPassword(newUser, password)
.getUserResource()
.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()
.assertStatusCode(200)
.usingUserResponse()
.assertAdmin(isAdmin -> assertThat(isAdmin).isEqualTo(Boolean.TRUE))
.assertPassword(Assert::assertNull);
}
@Test
public void adminShouldChangePasswordOfOtherUser() {
String newUser = "user";
String password = "pass";
TestData.createUser(newUser, password, true, "xml");
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()
.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()
.assertStatusCode(200);
}
@Test
public void shouldHidePasswordLinkIfUserTypeIsNotXML() {
String newUser = "user";
String password = "pass";
String type = "not XML Type";
TestData.createUser(newUser, password, true, type);
ScmRequests.start()
.given()
.url(TestData.getMeUrl())
.usernameAndPassword(newUser, password)
.getUserResource()
.assertStatusCode(200)
.usingUserResponse()
.assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE))
.assertPassword(Assert::assertNull)
.assertType(s -> assertThat(s).isEqualTo(type))
.assertPasswordLinkDoesNotExists();
}
@Test
public void shouldGet403IfUserIsNotAdmin() {
String newUser = "user";
String password = "pass";
String type = "xml";
TestData.createUser(newUser, password, false, type);
ScmRequests.start()
.given()
.url(TestData.getMeUrl())
.usernameAndPassword(newUser, password)
.getUserResource()
.assertStatusCode(403);
}
}

View File

@@ -0,0 +1,95 @@
package sonia.scm.it.utils;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonValue;
import java.math.BigDecimal;
import java.math.BigInteger;
public class NullAwareJsonObjectBuilder implements JsonObjectBuilder {
public static JsonObjectBuilder wrap(JsonObjectBuilder builder) {
if (builder == null) {
throw new IllegalArgumentException("Can't wrap nothing.");
}
return new NullAwareJsonObjectBuilder(builder);
}
private final JsonObjectBuilder builder;
private NullAwareJsonObjectBuilder(JsonObjectBuilder builder) {
this.builder = builder;
}
public JsonObjectBuilder add(String name, JsonValue value) {
return builder.add(name, (value == null) ? JsonValue.NULL : value);
}
@Override
public JsonObjectBuilder add(String name, String value) {
if (value != null){
return builder.add(name, value );
}else{
return builder.addNull(name);
}
}
@Override
public JsonObjectBuilder add(String name, BigInteger value) {
if (value != null){
return builder.add(name, value );
}else{
return builder.addNull(name);
}
}
@Override
public JsonObjectBuilder add(String name, BigDecimal value) {
if (value != null){
return builder.add(name, value );
}else{
return builder.addNull(name);
}
}
@Override
public JsonObjectBuilder add(String s, int i) {
return builder.add(s, i);
}
@Override
public JsonObjectBuilder add(String s, long l) {
return builder.add(s, l);
}
@Override
public JsonObjectBuilder add(String s, double v) {
return builder.add(s, v);
}
@Override
public JsonObjectBuilder add(String s, boolean b) {
return builder.add(s, b);
}
@Override
public JsonObjectBuilder addNull(String s) {
return builder.addNull(s);
}
@Override
public JsonObjectBuilder add(String s, JsonObjectBuilder jsonObjectBuilder) {
return builder.add(s, jsonObjectBuilder);
}
@Override
public JsonObjectBuilder add(String s, JsonArrayBuilder jsonArrayBuilder) {
return builder.add(s, jsonArrayBuilder);
}
@Override
public JsonObject build() {
return builder.build();
}
}

View File

@@ -1,4 +1,4 @@
package sonia.scm.it;
package sonia.scm.it.utils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
@@ -6,7 +6,7 @@ import org.hamcrest.Matcher;
import java.util.regex.Pattern;
class RegExMatcher extends BaseMatcher<String> {
public class RegExMatcher extends BaseMatcher<String> {
public static Matcher<String> matchesPattern(String pattern) {
return new RegExMatcher(pattern);
}

View File

@@ -1,4 +1,4 @@
package sonia.scm.it;
package sonia.scm.it.utils;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
@@ -24,11 +24,11 @@ public class RepositoryUtil {
private static final RepositoryClientFactory REPOSITORY_CLIENT_FACTORY = new RepositoryClientFactory();
static RepositoryClient createRepositoryClient(String repositoryType, File folder) throws IOException {
public static RepositoryClient createRepositoryClient(String repositoryType, File folder) throws IOException {
return createRepositoryClient(repositoryType, folder, "scmadmin", "scmadmin");
}
static RepositoryClient createRepositoryClient(String repositoryType, File folder, String username, String password) throws IOException {
public static RepositoryClient createRepositoryClient(String repositoryType, File folder, String username, String password) throws IOException {
String httpProtocolUrl = TestData.callRepository(username, password, repositoryType, HttpStatus.SC_OK)
.extract()
.path("_links.protocol.find{it.name=='http'}.href");
@@ -36,14 +36,14 @@ public class RepositoryUtil {
return REPOSITORY_CLIENT_FACTORY.create(repositoryType, httpProtocolUrl, username, password, folder);
}
static String addAndCommitRandomFile(RepositoryClient client, String username) throws IOException {
public static String addAndCommitRandomFile(RepositoryClient client, String username) throws IOException {
String uuid = UUID.randomUUID().toString();
String name = "file-" + uuid + ".uuid";
createAndCommitFile(client, username, name, uuid);
return name;
}
static Changeset createAndCommitFile(RepositoryClient repositoryClient, String username, String fileName, String content) throws IOException {
public static Changeset createAndCommitFile(RepositoryClient repositoryClient, String username, String fileName, String content) throws IOException {
writeAndAddFile(repositoryClient, fileName, content);
return commit(repositoryClient, username, "added " + fileName);
}
@@ -59,7 +59,7 @@ public class RepositoryUtil {
* @return the changeset with all modifications
* @throws IOException
*/
static Changeset commitMultipleFileModifications(RepositoryClient repositoryClient, String username, Map<String, String> addedFiles, Map<String, String> modifiedFiles, List<String> removedFiles) throws IOException {
public static Changeset commitMultipleFileModifications(RepositoryClient repositoryClient, String username, Map<String, String> addedFiles, Map<String, String> modifiedFiles, List<String> removedFiles) throws IOException {
for (String fileName : addedFiles.keySet()) {
writeAndAddFile(repositoryClient, fileName, addedFiles.get(fileName));
}
@@ -80,7 +80,7 @@ public class RepositoryUtil {
return file;
}
static Changeset removeAndCommitFile(RepositoryClient repositoryClient, String username, String fileName) throws IOException {
public static Changeset removeAndCommitFile(RepositoryClient repositoryClient, String username, String fileName) throws IOException {
deleteFileAndApplyRemoveCommand(repositoryClient, fileName);
return commit(repositoryClient, username, "removed " + fileName);
}
@@ -115,7 +115,7 @@ public class RepositoryUtil {
return changeset;
}
static Tag addTag(RepositoryClient repositoryClient, String revision, String tagName) throws IOException {
public static Tag addTag(RepositoryClient repositoryClient, String revision, String tagName) throws IOException {
if (repositoryClient.isCommandSupported(ClientCommand.TAG)) {
Tag tag = repositoryClient.getTagCommand().setRevision(revision).tag(tagName, TestData.USER_SCM_ADMIN);
if (repositoryClient.isCommandSupported(ClientCommand.PUSH)) {

View File

@@ -1,4 +1,4 @@
package sonia.scm.it;
package sonia.scm.it.utils;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;

View File

@@ -0,0 +1,465 @@
package sonia.scm.it.utils;
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;
import static org.hamcrest.Matchers.is;
import static sonia.scm.it.utils.TestData.createPasswordChangeJson;
/**
* Encapsulate rest requests of a repository in builder pattern
* <p>
* A Get Request can be applied with the methods request*()
* These methods return a AppliedGet*Request object
* This object can be used to apply general assertions over the rest Assured response
* In the AppliedGet*Request classes there is a using*Response() method
* that return the *Response class containing specific operations related to the specific response
* the *Response class contains also the request*() method to apply the next GET request from a link in the response.
*/
public class ScmRequests {
private String url;
private String username;
private String password;
public static ScmRequests start() {
return new ScmRequests();
}
public Given given() {
return new Given();
}
/**
* 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
* @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));
}
/**
* Apply a GET Request to the given <code>url</code> and return the response.
*
* @param url the url of the GET request
* @return the response of the GET request using the given <code>url</code>
*/
private Response applyGETRequest(String url) {
return RestAssured.given()
.auth().preemptive().basic(username, password)
.when()
.get(url);
}
/**
* Apply a PUT Request to the extracted url from the given link
*
* @param response the response containing the link
* @param linkPropertyName the property name of link
* @param body
* @return the response of the PUT request using the given link
*/
private Response applyPUTRequestFromLink(Response response, String linkPropertyName, String content, String body) {
return applyPUTRequest(response
.then()
.extract()
.path(linkPropertyName), content, body);
}
/**
* Apply a PUT Request to the given <code>url</code> and return the response.
*
* @param url the url of the PUT request
* @param mediaType
* @param body
* @return the response of the PUT request using the given <code>url</code>
*/
private Response applyPUTRequest(String url, String mediaType, String body) {
return RestAssured.given()
.auth().preemptive().basic(username, password)
.when()
.contentType(mediaType)
.accept(mediaType)
.body(body)
.put(url);
}
private void setUrl(String url) {
this.url = url;
}
private void setUsername(String username) {
this.username = username;
}
private void setPassword(String password) {
this.password = password;
}
private String getUrl() {
return url;
}
private String getUsername() {
return username;
}
private String getPassword() {
return password;
}
public class Given {
public GivenUrl url(String url) {
setUrl(url);
return new GivenUrl();
}
public GivenUrl url(URI url) {
setUrl(url.toString());
return new GivenUrl();
}
}
public class GivenWithUrlAndAuth {
public AppliedMeRequest getMeResource() {
return new AppliedMeRequest(applyGETRequest(url));
}
public AppliedUserRequest getUserResource() {
return new AppliedUserRequest(applyGETRequest(url));
}
public AppliedRepositoryRequest getRepositoryResource() {
return new AppliedRepositoryRequest(
applyGETRequest(url)
);
}
}
public class AppliedRequest<SELF extends 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<Response> 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 class AppliedRepositoryRequest extends AppliedRequest<AppliedRepositoryRequest> {
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<AppliedChangesetsRequest> {
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 assertChangesets(Consumer<List<Map>> changesetsConsumer) {
List<Map> changesets = changesetsResponse.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 AppliedModificationsRequest requestModifications(String revision) {
return new AppliedModificationsRequest(applyGETRequestFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.modifications.href"));
}
}
public class AppliedSourcesRequest extends AppliedRequest<AppliedSourcesRequest> {
public AppliedSourcesRequest(Response sourcesResponse) {
super(sourcesResponse);
}
public SourcesResponse usingSourcesResponse() {
return new SourcesResponse(super.response);
}
}
public class SourcesResponse {
private Response sourcesResponse;
public SourcesResponse(Response sourcesResponse) {
this.sourcesResponse = sourcesResponse;
}
public SourcesResponse assertRevision(Consumer<String> assertRevision) {
String revision = sourcesResponse.then().extract().path("revision");
assertRevision.accept(revision);
return this;
}
public SourcesResponse assertFiles(Consumer<List> assertFiles) {
List files = sourcesResponse.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 AppliedSourcesRequest requestSelf(String fileName) {
return new AppliedSourcesRequest(applyGETRequestFromLink(sourcesResponse, "_embedded.files.find{it.name=='" + fileName + "'}._links.self.href"));
}
}
public class AppliedDiffRequest extends AppliedRequest<AppliedDiffRequest> {
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<AppliedModificationsRequest> {
public AppliedModificationsRequest(Response response) {
super(response);
}
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<String> assertRevision) {
String revision = resource.then().extract().path("revision");
assertRevision.accept(revision);
return this;
}
public ModificationsResponse assertAdded(Consumer<List<String>> assertAdded) {
List<String> added = resource.then().extract().path("added");
assertAdded.accept(added);
return this;
}
public ModificationsResponse assertRemoved(Consumer<List<String>> assertRemoved) {
List<String> removed = resource.then().extract().path("removed");
assertRemoved.accept(removed);
return this;
}
public ModificationsResponse assertModified(Consumer<List<String>> assertModified) {
List<String> modified = resource.then().extract().path("modified");
assertModified.accept(modified);
return this;
}
}
public class AppliedMeRequest extends AppliedRequest<AppliedMeRequest> {
public AppliedMeRequest(Response response) {
super(response);
}
public MeResponse usingMeResponse() {
return new MeResponse(super.response);
}
}
public class MeResponse extends UserResponse<MeResponse> {
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 class UserResponse<SELF extends UserResponse> extends ModelResponse<SELF> {
public static final String LINKS_PASSWORD_HREF = "_links.password.href";
public UserResponse(Response response) {
super(response);
}
public SELF assertPassword(Consumer<String> assertPassword) {
return super.assertSingleProperty(assertPassword, "password");
}
public SELF assertType(Consumer<String> assertType) {
return assertSingleProperty(assertType, "type");
}
public SELF assertAdmin(Consumer<Boolean> assertAdmin) {
return assertSingleProperty(assertAdmin, "admin");
}
public SELF assertPasswordLinkDoesNotExists() {
return assertPropertyPathDoesNotExists(LINKS_PASSWORD_HREF);
}
public SELF 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)));
}
}
/**
* encapsulate standard assertions over model properties
*/
public class ModelResponse<SELF extends ModelResponse> {
protected Response response;
public ModelResponse(Response response) {
this.response = response;
}
public <T> SELF assertSingleProperty(Consumer<T> assertSingleProperty, String propertyJsonPath) {
T propertyValue = response.then().extract().path(propertyJsonPath);
assertSingleProperty.accept(propertyValue);
return (SELF) this;
}
public SELF assertPropertyPathExists(String propertyJsonPath) {
response.then().assertThat().body("any { it.containsKey('" + propertyJsonPath + "')}", is(true));
return (SELF) this;
}
public SELF assertPropertyPathDoesNotExists(String propertyJsonPath) {
response.then().assertThat().body("this.any { it.containsKey('" + propertyJsonPath + "')}", is(false));
return (SELF) this;
}
public SELF assertArrayProperty(Consumer<List> assertProperties, String propertyJsonPath) {
List properties = response.then().extract().path(propertyJsonPath);
assertProperties.accept(properties);
return (SELF) this;
}
}
public class AppliedChangePasswordRequest extends AppliedRequest<AppliedChangePasswordRequest> {
public AppliedChangePasswordRequest(Response response) {
super(response);
}
}
public class AppliedUserRequest extends AppliedRequest<AppliedUserRequest> {
public AppliedUserRequest(Response response) {
super(response);
}
public UserResponse usingUserResponse() {
return new UserResponse(super.response);
}
}
}

View File

@@ -1,12 +1,12 @@
package sonia.scm.it;
package sonia.scm.it.utils;
import sonia.scm.util.IOUtil;
import java.util.ArrayList;
import java.util.Collection;
class ScmTypes {
static Collection<String> availableScmTypes() {
public class ScmTypes {
public static Collection<String> availableScmTypes() {
Collection<String> params = new ArrayList<>();
params.add("git");

View File

@@ -1,4 +1,4 @@
package sonia.scm.it;
package sonia.scm.it.utils;
import io.restassured.response.ValidatableResponse;
import org.apache.http.HttpStatus;
@@ -8,14 +8,16 @@ import sonia.scm.repository.PermissionType;
import sonia.scm.web.VndMediaType;
import javax.json.Json;
import javax.json.JsonObjectBuilder;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Arrays.asList;
import static sonia.scm.it.RestUtil.createResourceUrl;
import static sonia.scm.it.RestUtil.given;
import static sonia.scm.it.ScmTypes.availableScmTypes;
import static sonia.scm.it.utils.RestUtil.createResourceUrl;
import static sonia.scm.it.utils.RestUtil.given;
import static sonia.scm.it.utils.ScmTypes.availableScmTypes;
public class TestData {
@@ -26,6 +28,7 @@ public class TestData {
private static final List<String> PROTECTED_USERS = asList(USER_SCM_ADMIN, USER_ANONYMOUS);
private static Map<String, String> DEFAULT_REPOSITORIES = new HashMap<>();
public static final JsonObjectBuilder JSON_BUILDER = NullAwareJsonObjectBuilder.wrap(Json.createObjectBuilder());
public static void createDefault() {
cleanup();
@@ -44,27 +47,31 @@ public class TestData {
}
public static void createUser(String username, String password) {
createUser(username, password, false, "xml");
}
public static void createUser(String username, String password, boolean isAdmin, String type) {
LOG.info("create user with username: {}", username);
String admin = isAdmin ? "true" : "false";
given(VndMediaType.USER)
.when()
.content(" {\n" +
" \"active\": true,\n" +
" \"admin\": false,\n" +
" \"creationDate\": \"2018-08-21T12:26:46.084Z\",\n" +
" \"displayName\": \"" + username + "\",\n" +
" \"mail\": \"user1@scm-manager.org\",\n" +
" \"name\": \"" + username + "\",\n" +
" \"password\": \"" + password + "\",\n" +
" \"type\": \"xml\"\n" +
" \n" +
" }")
.post(createResourceUrl("users"))
.content(new StringBuilder()
.append(" {\n")
.append(" \"active\": true,\n")
.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(" \"name\": \"").append(username).append("\",\n")
.append(" \"password\": \"").append(password).append("\",\n")
.append(" \"type\": \"").append(type).append("\"\n")
.append(" }").toString())
.post(getUsersUrl())
.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);
LOG.info("create permission with name {} and type: {} using the endpoint: {}", name, permissionType, defaultPermissionUrl);
@@ -183,7 +190,7 @@ public class TestData {
}
public static String repositoryJson(String repositoryType) {
return Json.createObjectBuilder()
return JSON_BUILDER
.add("contact", "zaphod.beeblebrox@hitchhiker.com")
.add("description", "Heart of Gold")
.add("name", "HeartOfGold-" + repositoryType)
@@ -192,6 +199,29 @@ public class TestData {
.build().toString();
}
public static URI getMeUrl() {
return RestUtil.createResourceUrl("me/");
}
public static URI getUsersUrl() {
return RestUtil.createResourceUrl("users/");
}
public static URI getUserUrl(String username) {
return getUsersUrl().resolve(username);
}
public static String createPasswordChangeJson(String oldPassword, String newPassword) {
return JSON_BUILDER
.add("oldPassword", oldPassword)
.add("newPassword", newPassword)
.build().toString();
}
public static void main(String[] args) {
cleanup();
}