diff --git a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java
index af772dce6b60..b641fa74b584 100644
--- a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java
+++ b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java
@@ -147,8 +147,6 @@ public static ProjectListOption pageToken(String pageToken) {
*
*
The server can return fewer projects than requested. When there are more results than the
* page size, the server will return a page token that can be used to fetch other results.
- * Note: pagination is not yet supported; the server currently ignores this field and returns
- * all results.
*/
public static ProjectListOption pageSize(int pageSize) {
return new ProjectListOption(ResourceManagerRpc.Option.PAGE_SIZE, pageSize);
@@ -228,8 +226,7 @@ public static ProjectListOption fields(ProjectField... fields) {
*
*
This method returns projects in an unspecified order. New projects do not necessarily appear
* at the end of the list. Use {@link ProjectListOption} to filter this list, set page size, and
- * set page tokens. Note that pagination is currently not implemented by the Cloud Resource
- * Manager API.
+ * set page tokens.
*
* @see Cloud
diff --git a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/LocalResourceManagerHelper.java b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/LocalResourceManagerHelper.java
index 25c763276b3b..4c26a44cd4e6 100644
--- a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/LocalResourceManagerHelper.java
+++ b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/LocalResourceManagerHelper.java
@@ -34,7 +34,7 @@
import java.util.Map;
import java.util.Random;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;
@@ -71,7 +71,7 @@ public class LocalResourceManagerHelper {
ImmutableSet.of('-', '\'', '"', ' ', '!');
private final HttpServer server;
- private final ConcurrentHashMap projects = new ConcurrentHashMap<>();
+ private final ConcurrentSkipListMap projects = new ConcurrentSkipListMap<>();
private final int port;
private static class Response {
@@ -228,7 +228,7 @@ private static String[] parseFields(String query) {
return null;
}
- private static Map parseListOptions(String query) {
+ private static Map parseListOptions(String query) throws IOException {
Map options = new HashMap<>();
if (query != null) {
String[] args = query.split("&");
@@ -245,10 +245,14 @@ private static Map parseListOptions(String query) {
options.put("filter", argEntry[1].split(" "));
break;
case "pageToken":
- // support pageToken when Cloud Resource Manager supports this (#421)
+ options.put("pageToken", argEntry[1]);
break;
case "pageSize":
- // support pageSize when Cloud Resource Manager supports this (#421)
+ int pageSize = Integer.valueOf(argEntry[1]);
+ if (pageSize < 1) {
+ throw new IOException("Page size must be greater than 0.");
+ }
+ options.put("pageSize", pageSize);
break;
}
}
@@ -353,16 +357,28 @@ Response get(String projectId, String[] fields) {
}
Response list(Map options) {
- // Use pageSize and pageToken options when Cloud Resource Manager does so (#421)
List projectsSerialized = new ArrayList<>();
String[] filters = (String[]) options.get("filter");
if (filters != null && !isValidFilter(filters)) {
return Error.INVALID_ARGUMENT.response("Could not parse the filter.");
}
String[] fields = (String[]) options.get("fields");
- for (Project p : projects.values()) {
+ int count = 0;
+ String pageToken = (String) options.get("pageToken");
+ Integer pageSize = (Integer) options.get("pageSize");
+ String nextPageToken = null;
+ Map projectsToScan = projects;
+ if (pageToken != null) {
+ projectsToScan = projects.tailMap(pageToken);
+ }
+ for (Project p : projectsToScan.values()) {
+ if (pageSize != null && count >= pageSize) {
+ nextPageToken = p.getProjectId();
+ break;
+ }
boolean includeProject = includeProject(p, filters);
if (includeProject) {
+ count++;
try {
projectsSerialized.add(jsonFactory.toString(extractFields(p, fields)));
} catch (IOException e) {
@@ -374,7 +390,13 @@ Response list(Map options) {
StringBuilder responseBody = new StringBuilder();
responseBody.append("{\"projects\": [");
Joiner.on(",").appendTo(responseBody, projectsSerialized);
- responseBody.append("]}");
+ responseBody.append(']');
+ if (nextPageToken != null) {
+ responseBody.append(", \"nextPageToken\": \"");
+ responseBody.append(nextPageToken);
+ responseBody.append('"');
+ }
+ responseBody.append('}');
return new Response(HTTP_OK, responseBody.toString());
}
diff --git a/gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/LocalResourceManagerHelperTest.java b/gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/LocalResourceManagerHelperTest.java
index 7eb0156d4e56..6c20c4f1ae0e 100644
--- a/gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/LocalResourceManagerHelperTest.java
+++ b/gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/LocalResourceManagerHelperTest.java
@@ -19,6 +19,7 @@
import org.junit.Test;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
public class LocalResourceManagerHelperTest {
@@ -278,7 +279,7 @@ public void testGetWithOptions() {
public void testList() {
Tuple> projects =
rpc.list(EMPTY_RPC_OPTIONS);
- assertNull(projects.x()); // change this when #421 is resolved
+ assertNull(projects.x());
assertFalse(projects.y().iterator().hasNext());
rpc.create(COMPLETE_PROJECT);
RESOURCE_MANAGER_HELPER.changeLifecycleState(
@@ -296,12 +297,43 @@ public void testList() {
}
}
+ @Test
+ public void testInvalidListPaging() {
+ Map rpcOptions = new HashMap<>();
+ rpcOptions.put(ResourceManagerRpc.Option.PAGE_SIZE, -1);
+ try {
+ rpc.list(rpcOptions);
+ } catch (ResourceManagerException e) {
+ assertEquals("Page size must be greater than 0.", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testListPaging() {
+ Map rpcOptions = new HashMap<>();
+ rpcOptions.put(ResourceManagerRpc.Option.PAGE_SIZE, 1);
+ rpc.create(PARTIAL_PROJECT);
+ rpc.create(COMPLETE_PROJECT);
+ Tuple> projects =
+ rpc.list(rpcOptions);
+ assertNotNull(projects.x());
+ Iterator iterator =
+ projects.y().iterator();
+ compareReadWriteFields(COMPLETE_PROJECT, iterator.next());
+ assertFalse(iterator.hasNext());
+ rpcOptions = new HashMap<>();
+ rpcOptions.put(ResourceManagerRpc.Option.PAGE_TOKEN, projects.x());
+ projects = rpc.list(rpcOptions);
+ iterator = projects.y().iterator();
+ compareReadWriteFields(PARTIAL_PROJECT, iterator.next());
+ assertFalse(iterator.hasNext());
+ assertNull(projects.x());
+ }
+
@Test
public void testListFieldOptions() {
Map rpcOptions = new HashMap<>();
rpcOptions.put(ResourceManagerRpc.Option.FIELDS, "projects(projectId,name,labels)");
- rpcOptions.put(ResourceManagerRpc.Option.PAGE_TOKEN, "somePageToken");
- rpcOptions.put(ResourceManagerRpc.Option.PAGE_SIZE, 1);
rpc.create(PROJECT_WITH_PARENT);
Tuple> projects =
rpc.list(rpcOptions);
diff --git a/gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/ResourceManagerImplTest.java b/gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/ResourceManagerImplTest.java
index 37c54718fb4a..8d64652a0696 100644
--- a/gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/ResourceManagerImplTest.java
+++ b/gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/ResourceManagerImplTest.java
@@ -42,6 +42,7 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import java.util.Iterator;
import java.util.Map;
public class ResourceManagerImplTest {
@@ -166,7 +167,7 @@ public void testGetWithOptions() {
@Test
public void testList() {
Page projects = RESOURCE_MANAGER.list();
- assertFalse(projects.values().iterator().hasNext()); // TODO: change this when #421 is resolved
+ assertFalse(projects.values().iterator().hasNext());
RESOURCE_MANAGER.create(PARTIAL_PROJECT);
RESOURCE_MANAGER.create(COMPLETE_PROJECT);
for (Project p : RESOURCE_MANAGER.list().values()) {
@@ -181,6 +182,22 @@ public void testList() {
}
}
+ @Test
+ public void testListPaging() {
+ RESOURCE_MANAGER.create(PARTIAL_PROJECT);
+ RESOURCE_MANAGER.create(COMPLETE_PROJECT);
+ Page page = RESOURCE_MANAGER.list(ProjectListOption.pageSize(1));
+ assertNotNull(page.nextPageCursor());
+ Iterator iterator = page.values().iterator();
+ compareReadWriteFields(COMPLETE_PROJECT, iterator.next());
+ assertFalse(iterator.hasNext());
+ page = page.nextPage();
+ iterator = page.values().iterator();
+ compareReadWriteFields(PARTIAL_PROJECT, iterator.next());
+ assertFalse(iterator.hasNext());
+ assertNull(page.nextPageCursor());
+ }
+
@Test
public void testListFieldOptions() {
RESOURCE_MANAGER.create(COMPLETE_PROJECT);