diff --git a/.gitignore b/.gitignore deleted file mode 100644 index c745262..0000000 --- a/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -out/ -.DS_Store -/target -.idea -*.iws diff --git a/src/main/java/com/rallydev/rest/RallyRestApi.java b/src/main/java/com/rallydev/rest/RallyRestApi.java index 6a0eaa8..253adbd 100644 --- a/src/main/java/com/rallydev/rest/RallyRestApi.java +++ b/src/main/java/com/rallydev/rest/RallyRestApi.java @@ -1,15 +1,26 @@ package com.rallydev.rest; +import java.io.Closeable; +import java.io.IOException; +import java.net.URI; + import com.google.gson.JsonArray; import com.rallydev.rest.client.ApiKeyClient; import com.rallydev.rest.client.BasicAuthClient; import com.rallydev.rest.client.HttpClient; -import com.rallydev.rest.request.*; -import com.rallydev.rest.response.*; - -import java.io.Closeable; -import java.io.IOException; -import java.net.URI; +import com.rallydev.rest.request.BulkUserPermissionRequest; +import com.rallydev.rest.request.CollectionUpdateRequest; +import com.rallydev.rest.request.CreateRequest; +import com.rallydev.rest.request.DeleteRequest; +import com.rallydev.rest.request.GetRequest; +import com.rallydev.rest.request.QueryRequest; +import com.rallydev.rest.request.UpdateRequest; +import com.rallydev.rest.response.CollectionUpdateResponse; +import com.rallydev.rest.response.CreateResponse; +import com.rallydev.rest.response.DeleteResponse; +import com.rallydev.rest.response.GetResponse; +import com.rallydev.rest.response.QueryResponse; +import com.rallydev.rest.response.UpdateResponse; /** *

The main interface to the Rest API.

@@ -30,6 +41,19 @@ public class RallyRestApi implements Closeable { public RallyRestApi(URI server, String userName, String password) { this(new BasicAuthClient(server, userName, password)); } + + /** + * Creates a new instance for the specified server using the specified credentials. + * + * @param server The server to connect to, e.g. {@code new URI("https://rally1.rallydev.com")} + * @param userName The username to be used for authentication. + * @param password The password to be used for authentication. + * @param httpClient The pre-configured httpClient. + * @deprecated Use the api key constructor instead. + */ + public RallyRestApi(URI server, String userName, String password, org.apache.http.client.HttpClient httpClient) { + this(new BasicAuthClient(server, userName, password, httpClient)); + } /** * Creates a new instance for the specified server using the specified API Key. @@ -41,6 +65,17 @@ public RallyRestApi(URI server, String apiKey) { this(new ApiKeyClient(server, apiKey)); } + /** + * Creates a new instance for the specified server using the specified API Key and a pre-configured httpClient. + * + * @param server The server to connect to, e.g. {@code new URI("https://rally1.rallydev.com")} + * @param apiKey The API Key to be used for authentication. + * @param httpClient The pre-configured httpClient. + */ + public RallyRestApi(URI server, String apiKey, org.apache.http.client.HttpClient httpClient) { + this(new ApiKeyClient(server, apiKey, httpClient)); + } + protected RallyRestApi(HttpClient httpClient) { this.client = httpClient; } @@ -199,6 +234,17 @@ public GetResponse get(GetRequest request) throws IOException { return new GetResponse(client.doGet(request.toUrl())); } + /** + * Bulk update a given user's project permissions. + * + * @param request request the {@link BulkUserPermissionRequest} specifying the object to be retrieved. + * @return the resulting {@link CollectionUpdateResponse} + * @throws IOException if an error occurs during the retrieval. + */ + public CollectionUpdateResponse bulkUpdate(BulkUserPermissionRequest request) throws IOException { + return new CollectionUpdateResponse(client.doPost(request.toUrl(), "")); + } + /** * Release all resources associated with this instance. * diff --git a/src/main/java/com/rallydev/rest/client/ApiKeyClient.java b/src/main/java/com/rallydev/rest/client/ApiKeyClient.java index 2295824..80209f9 100644 --- a/src/main/java/com/rallydev/rest/client/ApiKeyClient.java +++ b/src/main/java/com/rallydev/rest/client/ApiKeyClient.java @@ -1,10 +1,10 @@ package com.rallydev.rest.client; -import org.apache.http.client.methods.HttpRequestBase; - import java.io.IOException; import java.net.URI; +import org.apache.http.client.methods.HttpRequestBase; + /** * A HttpClient which authenticates using an API Key. */ @@ -23,6 +23,17 @@ public ApiKeyClient(URI server, String apiKey) { this.apiKey = apiKey; } + /** + * Construct a new client with a pre-configured HttpClient. + * + * @param server the server to connect to + * @param apiKey the key to be used for authentication + */ + public ApiKeyClient(URI server, String apiKey, org.apache.http.client.HttpClient httpClient) { + super(server, httpClient); + this.apiKey = apiKey; + } + /** * Execute a request against the WSAPI * diff --git a/src/main/java/com/rallydev/rest/client/BasicAuthClient.java b/src/main/java/com/rallydev/rest/client/BasicAuthClient.java index 2b6d04a..36d0430 100644 --- a/src/main/java/com/rallydev/rest/client/BasicAuthClient.java +++ b/src/main/java/com/rallydev/rest/client/BasicAuthClient.java @@ -1,16 +1,18 @@ package com.rallydev.rest.client; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.rallydev.rest.response.GetResponse; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + import org.apache.http.auth.Credentials; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.auth.BasicScheme; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; + +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.rallydev.rest.response.GetResponse; /** * A HttpClient which authenticates using basic authentication (username/password). @@ -24,6 +26,8 @@ public class BasicAuthClient extends HttpClient { protected String securityToken; protected Credentials credentials; + private Object privateLock = new Object(); + /** * Construct a new client. * @param server the server to connect to @@ -34,17 +38,36 @@ public BasicAuthClient(URI server, String userName, String password) { super(server); credentials = setClientCredentials(server, userName, password); } + + /** + * Construct a new client with a pre-configured HttpClient. + * + * @param server the server to connect to + * @param userName the username to be used for authentication + * @param password the password to be used for authentication + */ + public BasicAuthClient(URI server, String userName, String password, org.apache.http.client.HttpClient client) { + super(server, client); + credentials = setClientCredentials(server, userName, password); + } /** - * Execute a request against the WSAPI + * Execute a request against the WSAPI. + * + * Always attaches the Basic Authentication header to avoid HTTP Spec handling. + * + * Traditionally, all requests are attempted without authorization, + * however we know that all resources are protected, so we can force pre-authentication. * * @param request the request to be executed * @return the JSON encoded string response * @throws java.io.IOException if a non-200 response code is returned or if some other - * problem occurs while executing the request + * problem occurs while executing the request */ @Override protected String doRequest(HttpRequestBase request) throws IOException { + request.addHeader(BasicScheme.authenticate(credentials, "utf-8", false)); + if(!request.getMethod().equals(HttpGet.METHOD_NAME) && !this.getWsapiVersion().matches("^1[.]\\d+")) { try { @@ -70,13 +93,14 @@ protected String doRequest(HttpRequestBase request) throws IOException { protected void attachSecurityInfo(HttpRequestBase request) throws IOException, URISyntaxException { if (!SECURITY_ENDPOINT_DOES_NOT_EXIST.equals(securityToken)) { try { - if (securityToken == null) { - HttpGet httpGet = new HttpGet(getWsapiUrl() + SECURITY_TOKEN_URL); - httpGet.addHeader(BasicScheme.authenticate(credentials, "utf-8", false)); - GetResponse getResponse = new GetResponse(doRequest(httpGet)); - JsonObject operationResult = getResponse.getObject(); - JsonPrimitive securityTokenPrimitive = operationResult.getAsJsonPrimitive(SECURITY_TOKEN_KEY); - securityToken = securityTokenPrimitive.getAsString(); + synchronized (privateLock) { + if (securityToken == null) { + HttpGet httpGet = new HttpGet(getWsapiUrl() + SECURITY_TOKEN_URL); + GetResponse getResponse = new GetResponse(doRequest(httpGet)); + JsonObject operationResult = getResponse.getObject(); + JsonPrimitive securityTokenPrimitive = operationResult.getAsJsonPrimitive(SECURITY_TOKEN_KEY); + securityToken = securityTokenPrimitive.getAsString(); + } } request.setURI(new URIBuilder(request.getURI()).addParameter(SECURITY_TOKEN_PARAM_KEY, securityToken).build()); } catch (IOException e) { diff --git a/src/main/java/com/rallydev/rest/client/HttpClient.java b/src/main/java/com/rallydev/rest/client/HttpClient.java index 3bc4a9a..d657088 100644 --- a/src/main/java/com/rallydev/rest/client/HttpClient.java +++ b/src/main/java/com/rallydev/rest/client/HttpClient.java @@ -1,24 +1,28 @@ package com.rallydev.rest.client; +import java.io.Closeable; +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.methods.*; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DecompressingHttpClient; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; -import java.io.Closeable; -import java.io.IOException; -import java.net.URI; -import java.util.HashMap; -import java.util.Map; - /** * A HttpClient implementation providing connectivity to Rally. This class does not * provide any authentication on its own but instead relies on a concrete subclass to do so. @@ -28,7 +32,7 @@ public class HttpClient extends DefaultHttpClient protected URI server; protected String wsapiVersion = "v2.0"; - protected DecompressingHttpClient client; + protected org.apache.http.client.HttpClient client; private enum Header { Library, @@ -51,6 +55,17 @@ protected HttpClient(URI server) { client = new DecompressingHttpClient(this); } + /** + * Allow the user to specify a compliant HttpClient + * + * @param server The URI of the remote server + * @param client A pre-configured HttpClient implementation + */ + public HttpClient(URI server, org.apache.http.client.HttpClient client) { + this.server = server; + this.client = client; + } + /** * Set the unauthenticated proxy server to use. By default no proxy is configured. * diff --git a/src/main/java/com/rallydev/rest/request/BulkUserPermissionRequest.java b/src/main/java/com/rallydev/rest/request/BulkUserPermissionRequest.java new file mode 100644 index 0000000..ffe2753 --- /dev/null +++ b/src/main/java/com/rallydev/rest/request/BulkUserPermissionRequest.java @@ -0,0 +1,66 @@ +package com.rallydev.rest.request; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.message.BasicNameValuePair; + +/** + * Represents a WSAPI request to bulk provision a user. + */ +public class BulkUserPermissionRequest extends Request { + + private static final String PROJECTPERMISSION_BULKUPDATE = "/projectpermission/bulkupdate"; + + private String userOID; + private Collection excludedRootProjectOIDs; + private String rootProjectOID; + private String permission; + private boolean forceDowngradePermissions; + + /** + * + * @param userOID + * The OID (ObjectID) of the User who will be granted new project permissions + * @param excludedRootProjectOIDs + * The OIDs of any child Project (or a child of a child, or any ancestor to any level) under the root project which are to be excluded from the + * permission change operation. + * @param rootProjectOID + * The OID of the root of the Project tree of which to change the permissions for the given user. The user's Project permission for all Projects + * rooted at this one will be changed, unless (see below for further explanation) + * the Project is on the exclusions list, or + * the operation would result in a downgrade but the force downgrade parameters was not set to tree. + * @param permission + * The permission to grant. Must be one of No Access, Viewer, Editor, or Project Admin. + * @param forceDowngradePermissions + * If you intend to downgrade any existing project permissions, set this to true. + */ + public BulkUserPermissionRequest(String userOID, Collection excludedRootProjectOIDs, String rootProjectOID, String permission, + boolean forceDowngradePermissions) { + super(); + this.userOID = userOID; + this.excludedRootProjectOIDs = excludedRootProjectOIDs; + this.rootProjectOID = rootProjectOID; + this.permission = permission; + this.forceDowngradePermissions = forceDowngradePermissions; + } + + @Override + public String toUrl() { + List params = new ArrayList(getParams()); + params.add(new BasicNameValuePair("userOID", userOID)); + params.add(new BasicNameValuePair("rootProjectOID", rootProjectOID)); + params.add(new BasicNameValuePair("permission", permission)); + params.add(new BasicNameValuePair("forceDowngradePermissions", Boolean.toString(forceDowngradePermissions))); + + if (excludedRootProjectOIDs != null && !excludedRootProjectOIDs.isEmpty()) { + params.add(new BasicNameValuePair("excludedRootProjectOIDs", String.join(",", excludedRootProjectOIDs))); + } + + return String.format("%s?%s", PROJECTPERMISSION_BULKUPDATE, URLEncodedUtils.format(params, "utf-8")); + } + +} diff --git a/src/main/java/com/rallydev/rest/response/Response.java b/src/main/java/com/rallydev/rest/response/Response.java index de1123a..30190d0 100644 --- a/src/main/java/com/rallydev/rest/response/Response.java +++ b/src/main/java/com/rallydev/rest/response/Response.java @@ -1,17 +1,20 @@ package com.rallydev.rest.response; +import java.util.ArrayList; +import java.util.List; + import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import java.util.ArrayList; -import java.util.List; - /** * Represents a WSAPI response. */ public abstract class Response { + private static final String ERRORS = "Errors"; + private static final String WARNINGS = "Warnings"; + protected JsonObject result; protected String raw; @@ -40,7 +43,7 @@ public boolean wasSuccessful() { * @return the response errors */ public String[] getErrors() { - return parseArray("Errors"); + return result.has(ERRORS) ? parseArray(ERRORS) : new String[0]; } /** @@ -49,7 +52,7 @@ public String[] getErrors() { * @return the response warnings */ public String[] getWarnings() { - return parseArray("Warnings"); + return result.has(WARNINGS) ? parseArray(WARNINGS) : new String[0]; } /** diff --git a/src/test/java/com/rallydev/rest/RallyRestApiTest.java b/src/test/java/com/rallydev/rest/RallyRestApiTest.java index eba2d1c..b5ccda1 100644 --- a/src/test/java/com/rallydev/rest/RallyRestApiTest.java +++ b/src/test/java/com/rallydev/rest/RallyRestApiTest.java @@ -1,25 +1,37 @@ package com.rallydev.rest; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.rallydev.rest.client.ApiKeyClient; -import com.rallydev.rest.client.BasicAuthClient; -import com.rallydev.rest.request.*; -import com.rallydev.rest.response.*; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import java.net.URI; - -import static org.mockito.Mockito.anyString; +import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.testng.Assert.assertEquals; +import java.net.URI; + +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.rallydev.rest.client.ApiKeyClient; +import com.rallydev.rest.client.BasicAuthClient; +import com.rallydev.rest.request.BulkUserPermissionRequest; +import com.rallydev.rest.request.CollectionUpdateRequest; +import com.rallydev.rest.request.CreateRequest; +import com.rallydev.rest.request.DeleteRequest; +import com.rallydev.rest.request.GetRequest; +import com.rallydev.rest.request.QueryRequest; +import com.rallydev.rest.request.UpdateRequest; +import com.rallydev.rest.response.CollectionUpdateResponse; +import com.rallydev.rest.response.CreateResponse; +import com.rallydev.rest.response.DeleteResponse; +import com.rallydev.rest.response.GetResponse; +import com.rallydev.rest.response.QueryResponse; +import com.rallydev.rest.response.UpdateResponse; + @Test public class RallyRestApiTest { private RallyRestApi api; @@ -125,6 +137,24 @@ public void shouldUpdate() throws Exception { assertEquals(obj.get("_ref").getAsString(), "/defect/1234"); } + public void shouldBulkUserPermissionUpdate() throws Exception { + JsonObject response = new JsonObject(); + JsonObject updateResult = new JsonObject(); + response.add("OperationResult", updateResult); + JsonArray results = new JsonArray(); + JsonObject tag = new JsonObject(); + tag.addProperty("_ref", "/tag/23456"); + results.add(tag); + response.add("Results", results); + + BulkUserPermissionRequest request = new BulkUserPermissionRequest("1234,", null, "111", "Viewer", false); + doReturn(new Gson().toJson(response)).when(api.client).doPost(request.toUrl(), ""); + CollectionUpdateResponse collectionUpdateResponse = api.bulkUpdate(request); + + verify(api.client).doPost(request.toUrl(), ""); + Assert.assertTrue(collectionUpdateResponse.wasSuccessful()); + } + public void shouldUpdateCollection() throws Exception { JsonObject response = new JsonObject(); JsonObject result = new JsonObject(); diff --git a/src/test/java/com/rallydev/rest/client/ApiKeyClientTest.java b/src/test/java/com/rallydev/rest/client/ApiKeyClientTest.java index 84ca9e6..93ea0b7 100644 --- a/src/test/java/com/rallydev/rest/client/ApiKeyClientTest.java +++ b/src/test/java/com/rallydev/rest/client/ApiKeyClientTest.java @@ -1,18 +1,23 @@ package com.rallydev.rest.client; -import com.rallydev.rest.matchers.HttpRequestHeaderMatcher; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import java.net.URI; +import java.net.URISyntaxException; + import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.impl.client.DefaultHttpClient; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.net.URI; -import java.net.URISyntaxException; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.*; +import com.rallydev.rest.matchers.HttpRequestHeaderMatcher; public class ApiKeyClientTest { @@ -31,10 +36,25 @@ public void shouldIntialize() { Assert.assertEquals(client.getServer(), server); } + @SuppressWarnings("resource") + @Test + public void shouldIntializePreConfiguredClient() throws URISyntaxException { + HttpClient mockClient = mock(HttpClient.class); + ApiKeyClient client = new ApiKeyClient(new URI(server), apiKey, mockClient); + Assert.assertEquals(client.getServer(), server); + } + @Test public void shouldIncludeApiKeyOnRequest() throws Exception { doReturn("").when(client).executeRequest(any(HttpRequestBase.class)); client.doRequest(new HttpGet()); verify(client).doRequest(argThat(new HttpRequestHeaderMatcher("zsessionid", apiKey))); } + + @Test + public void shouldReturnPreConfiguredClient() throws Exception { + DefaultHttpClient mockClient = mock(DefaultHttpClient.class); + ApiKeyClient spiedClient = spy(new ApiKeyClient(new URI(server), apiKey, mockClient)); + Assert.assertEquals(spiedClient.client, mockClient); + } } diff --git a/src/test/java/com/rallydev/rest/client/BasicAuthClientTest.java b/src/test/java/com/rallydev/rest/client/BasicAuthClientTest.java index e661892..51a7798 100644 --- a/src/test/java/com/rallydev/rest/client/BasicAuthClientTest.java +++ b/src/test/java/com/rallydev/rest/client/BasicAuthClientTest.java @@ -1,18 +1,28 @@ package com.rallydev.rest.client; -import com.rallydev.rest.matchers.HttpRequestHeaderMatcher; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.net.URI; +import java.net.URISyntaxException; + import org.apache.http.Header; -import org.apache.http.client.methods.*; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.impl.auth.BasicScheme; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.net.URI; -import java.net.URISyntaxException; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; +import com.rallydev.rest.matchers.HttpRequestHeaderMatcher; public class BasicAuthClientTest { @@ -36,11 +46,31 @@ public void shouldIntialize() { Assert.assertEquals(client.credentials.getUserPrincipal().getName(), userName); } + @SuppressWarnings("resource") + @Test + public void shouldIntializePreConfiguredClient() throws URISyntaxException { + HttpClient mockClient = mock(HttpClient.class); + BasicAuthClient client = new BasicAuthClient(new URI(server), userName, password, mockClient); + Assert.assertEquals(client.getServer(), server); + Assert.assertEquals(client.credentials.getPassword(), password); + Assert.assertEquals(client.credentials.getUserPrincipal().getName(), userName); + } + + @Test + public void shouldIncludeAuthHeaderOnGet() throws Exception { + doReturn("").when(client).executeRequest(any(HttpRequestBase.class)); + client.doRequest(new HttpGet()); + Header authHeader = BasicScheme.authenticate(client.credentials, "utf-8", false); + verify(client).executeRequest(argThat(new HttpRequestHeaderMatcher(authHeader.getName(), authHeader.getValue()))); + } + @Test public void shouldNotIncludeCSRFTokenOnGet() throws Exception { doReturn("").when(client).executeRequest(any(HttpRequestBase.class)); client.doRequest(new HttpGet()); verify(client, times(0)).attachSecurityInfo(any(HttpRequestBase.class)); + Header authHeader = BasicScheme.authenticate(client.credentials, "utf-8", false); + verify(client).executeRequest(argThat(new HttpRequestHeaderMatcher(authHeader.getName(), authHeader.getValue()))); } @Test @@ -57,7 +87,7 @@ public void shouldRequestCSRFToken() throws Exception { doReturn(SECURITY_TOKEN_RESPONSE).when(client).executeRequest(any(HttpGet.class)); client.doRequest(new HttpPost(server)); Header authHeader = BasicScheme.authenticate(client.credentials, "utf-8", false); - verify(client).executeRequest(argThat(new HttpRequestHeaderMatcher(authHeader.getName(), authHeader.getValue()))); + verify(client, times(2)).executeRequest(argThat(new HttpRequestHeaderMatcher(authHeader.getName(), authHeader.getValue()))); } @Test diff --git a/src/test/java/com/rallydev/rest/request/BulkUserPermissionRequestTest.java b/src/test/java/com/rallydev/rest/request/BulkUserPermissionRequestTest.java new file mode 100644 index 0000000..084f2fc --- /dev/null +++ b/src/test/java/com/rallydev/rest/request/BulkUserPermissionRequestTest.java @@ -0,0 +1,28 @@ +package com.rallydev.rest.request; + +import java.util.Arrays; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class BulkUserPermissionRequestTest { + + @Test + public void shouldConstructCorrectURL_NoExcludes_Viewer() { + BulkUserPermissionRequest req = new BulkUserPermissionRequest("1234", null, "12345", "Viewer", false); + Assert.assertEquals(req.toUrl(), "/projectpermission/bulkupdate?userOID=1234&rootProjectOID=12345&permission=Viewer&forceDowngradePermissions=false"); + } + + @Test + public void shouldConstructCorrectURL_NoExcludes_Editor() { + BulkUserPermissionRequest req = new BulkUserPermissionRequest("1234", null, "12345", "Editor", false); + Assert.assertEquals(req.toUrl(), "/projectpermission/bulkupdate?userOID=1234&rootProjectOID=12345&permission=Editor&forceDowngradePermissions=false"); + } + + @Test + public void shouldConstructCorrectURL_Editor() { + BulkUserPermissionRequest req = new BulkUserPermissionRequest("1234", Arrays.asList("1122", "1133"), "12345", "Editor", false); + Assert.assertEquals(req.toUrl(), + "/projectpermission/bulkupdate?userOID=1234&rootProjectOID=12345&permission=Editor&forceDowngradePermissions=false&excludedRootProjectOIDs=1122%2C1133"); + } +}