Skip to content

Commit 7194201

Browse files
committed
Merge pull request #668 from mziccard/page-token-fields-option
Add pageToken to list fields option for storage and resourcemanager
2 parents 119ccdf + a439628 commit 7194201

File tree

6 files changed

+150
-19
lines changed

6 files changed

+150
-19
lines changed

gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public static ProjectListOption pageSize(int pageSize) {
162162
*/
163163
public static ProjectListOption fields(ProjectField... fields) {
164164
StringBuilder builder = new StringBuilder();
165-
builder.append("projects(").append(ProjectField.selector(fields)).append(")");
165+
builder.append("projects(").append(ProjectField.selector(fields)).append("),nextPageToken");
166166
return new ProjectListOption(ResourceManagerRpc.Option.FIELDS, builder.toString());
167167
}
168168
}

gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/LocalResourceManagerHelper.java

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import java.util.concurrent.ConcurrentSkipListMap;
3838
import java.util.logging.Level;
3939
import java.util.logging.Logger;
40+
import java.util.regex.Matcher;
41+
import java.util.regex.Pattern;
4042
import java.util.zip.GZIPInputStream;
4143

4244
/**
@@ -56,6 +58,9 @@ public class LocalResourceManagerHelper {
5658
private static final URI BASE_CONTEXT;
5759
private static final Set<String> SUPPORTED_COMPRESSION_ENCODINGS =
5860
ImmutableSet.of("gzip", "x-gzip");
61+
private static final Pattern LIST_FIELDS_PATTERN =
62+
Pattern.compile("(.*?)projects\\((.*?)\\)(.*?)");
63+
private static final String[] NO_FIELDS = {};
5964

6065
static {
6166
try {
@@ -236,10 +241,15 @@ private static Map<String, Object> parseListOptions(String query) throws IOExcep
236241
String[] argEntry = arg.split("=");
237242
switch (argEntry[0]) {
238243
case "fields":
239-
// List fields are in the form "projects(field1, field2, ...)"
240-
options.put(
241-
"fields",
242-
argEntry[1].substring("projects(".length(), argEntry[1].length() - 1).split(","));
244+
// List fields are in the form "projects(field1, field2, ...),nextPageToken"
245+
Matcher matcher = LIST_FIELDS_PATTERN.matcher(argEntry[1]);
246+
if (matcher.matches()) {
247+
options.put("projectFields", matcher.group(2).split(","));
248+
options.put("listFields", (matcher.group(1) + matcher.group(3)).split(","));
249+
} else {
250+
options.put("projectFields", NO_FIELDS);
251+
options.put("listFields", argEntry[1].split(","));
252+
}
243253
break;
244254
case "filter":
245255
options.put("filter", argEntry[1].split(" "));
@@ -362,7 +372,7 @@ Response list(Map<String, Object> options) {
362372
if (filters != null && !isValidFilter(filters)) {
363373
return Error.INVALID_ARGUMENT.response("Could not parse the filter.");
364374
}
365-
String[] fields = (String[]) options.get("fields");
375+
String[] projectFields = (String[]) options.get("projectFields");
366376
int count = 0;
367377
String pageToken = (String) options.get("pageToken");
368378
Integer pageSize = (Integer) options.get("pageSize");
@@ -380,19 +390,28 @@ Response list(Map<String, Object> options) {
380390
if (includeProject) {
381391
count++;
382392
try {
383-
projectsSerialized.add(jsonFactory.toString(extractFields(p, fields)));
393+
projectsSerialized.add(jsonFactory.toString(extractFields(p, projectFields)));
384394
} catch (IOException e) {
385395
return Error.INTERNAL_ERROR.response(
386396
"Error when serializing project " + p.getProjectId());
387397
}
388398
}
389399
}
400+
String[] listFields = (String[]) options.get("listFields");
390401
StringBuilder responseBody = new StringBuilder();
391-
responseBody.append("{\"projects\": [");
392-
Joiner.on(",").appendTo(responseBody, projectsSerialized);
393-
responseBody.append(']');
394-
if (nextPageToken != null) {
395-
responseBody.append(", \"nextPageToken\": \"");
402+
responseBody.append('{');
403+
// If fields parameter is set but no project field is selected we must return no projects.
404+
if (!(projectFields != null && projectFields.length == 0)) {
405+
responseBody.append("\"projects\": [");
406+
Joiner.on(",").appendTo(responseBody, projectsSerialized);
407+
responseBody.append(']');
408+
}
409+
if (nextPageToken != null && (listFields == null
410+
|| ImmutableSet.copyOf(listFields).contains("nextPageToken"))) {
411+
if (responseBody.length() > 1) {
412+
responseBody.append(',');
413+
}
414+
responseBody.append("\"nextPageToken\": \"");
396415
responseBody.append(nextPageToken);
397416
responseBody.append('"');
398417
}

gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/LocalResourceManagerHelperTest.java

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ public void testListPaging() {
333333
@Test
334334
public void testListFieldOptions() {
335335
Map<ResourceManagerRpc.Option, Object> rpcOptions = new HashMap<>();
336-
rpcOptions.put(ResourceManagerRpc.Option.FIELDS, "projects(projectId,name,labels)");
336+
rpcOptions.put(ResourceManagerRpc.Option.FIELDS,
337+
"projects(projectId,name,labels),nextPageToken");
337338
rpc.create(PROJECT_WITH_PARENT);
338339
Tuple<String, Iterable<com.google.api.services.cloudresourcemanager.model.Project>> projects =
339340
rpc.list(rpcOptions);
@@ -349,6 +350,81 @@ public void testListFieldOptions() {
349350
assertNull(returnedProject.getCreateTime());
350351
}
351352

353+
@Test
354+
public void testListPageTokenFieldOptions() {
355+
Map<ResourceManagerRpc.Option, Object> rpcOptions = new HashMap<>();
356+
rpcOptions.put(ResourceManagerRpc.Option.PAGE_SIZE, 1);
357+
rpcOptions.put(ResourceManagerRpc.Option.FIELDS, "nextPageToken,projects(projectId,name)");
358+
rpc.create(PARTIAL_PROJECT);
359+
rpc.create(COMPLETE_PROJECT);
360+
Tuple<String, Iterable<com.google.api.services.cloudresourcemanager.model.Project>> projects =
361+
rpc.list(rpcOptions);
362+
assertNotNull(projects.x());
363+
Iterator<com.google.api.services.cloudresourcemanager.model.Project> iterator =
364+
projects.y().iterator();
365+
com.google.api.services.cloudresourcemanager.model.Project returnedProject = iterator.next();
366+
assertEquals(COMPLETE_PROJECT.getProjectId(), returnedProject.getProjectId());
367+
assertEquals(COMPLETE_PROJECT.getName(), returnedProject.getName());
368+
assertNull(returnedProject.getLabels());
369+
assertNull(returnedProject.getParent());
370+
assertNull(returnedProject.getProjectNumber());
371+
assertNull(returnedProject.getLifecycleState());
372+
assertNull(returnedProject.getCreateTime());
373+
assertFalse(iterator.hasNext());
374+
rpcOptions.put(ResourceManagerRpc.Option.PAGE_TOKEN, projects.x());
375+
projects = rpc.list(rpcOptions);
376+
iterator = projects.y().iterator();
377+
returnedProject = iterator.next();
378+
assertEquals(PARTIAL_PROJECT.getProjectId(), returnedProject.getProjectId());
379+
assertEquals(PARTIAL_PROJECT.getName(), returnedProject.getName());
380+
assertNull(returnedProject.getLabels());
381+
assertNull(returnedProject.getParent());
382+
assertNull(returnedProject.getProjectNumber());
383+
assertNull(returnedProject.getLifecycleState());
384+
assertNull(returnedProject.getCreateTime());
385+
assertNull(projects.x());
386+
}
387+
388+
@Test
389+
public void testListNoPageTokenFieldOptions() {
390+
Map<ResourceManagerRpc.Option, Object> rpcOptions = new HashMap<>();
391+
rpcOptions.put(ResourceManagerRpc.Option.PAGE_SIZE, 1);
392+
rpcOptions.put(ResourceManagerRpc.Option.FIELDS, "projects(projectId,name)");
393+
rpc.create(PARTIAL_PROJECT);
394+
rpc.create(COMPLETE_PROJECT);
395+
Tuple<String, Iterable<com.google.api.services.cloudresourcemanager.model.Project>> projects =
396+
rpc.list(rpcOptions);
397+
assertNull(projects.x());
398+
Iterator<com.google.api.services.cloudresourcemanager.model.Project> iterator =
399+
projects.y().iterator();
400+
com.google.api.services.cloudresourcemanager.model.Project returnedProject = iterator.next();
401+
assertEquals(COMPLETE_PROJECT.getProjectId(), returnedProject.getProjectId());
402+
assertEquals(COMPLETE_PROJECT.getName(), returnedProject.getName());
403+
assertNull(returnedProject.getLabels());
404+
assertNull(returnedProject.getParent());
405+
assertNull(returnedProject.getProjectNumber());
406+
assertNull(returnedProject.getLifecycleState());
407+
assertNull(returnedProject.getCreateTime());
408+
assertFalse(iterator.hasNext());
409+
}
410+
411+
@Test
412+
public void testListPageTokenNoFieldsOptions() {
413+
Map<ResourceManagerRpc.Option, Object> rpcOptions = new HashMap<>();
414+
rpcOptions.put(ResourceManagerRpc.Option.PAGE_SIZE, 1);
415+
rpcOptions.put(ResourceManagerRpc.Option.FIELDS, "nextPageToken");
416+
rpc.create(PARTIAL_PROJECT);
417+
rpc.create(COMPLETE_PROJECT);
418+
Tuple<String, Iterable<com.google.api.services.cloudresourcemanager.model.Project>> projects =
419+
rpc.list(rpcOptions);
420+
assertNotNull(projects.x());
421+
assertNull(projects.y());
422+
rpcOptions.put(ResourceManagerRpc.Option.PAGE_TOKEN, projects.x());
423+
projects = rpc.list(rpcOptions);
424+
assertNull(projects.x());
425+
assertNull(projects.y());
426+
}
427+
352428
@Test
353429
public void testListFilterOptions() {
354430
Map<ResourceManagerRpc.Option, Object> rpcFilterOptions = new HashMap<>();

gcloud-java-resourcemanager/src/test/java/com/google/gcloud/resourcemanager/ResourceManagerImplTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,38 @@ public void testListFieldOptions() {
213213
assertSame(RESOURCE_MANAGER, returnedProject.resourceManager());
214214
}
215215

216+
@Test
217+
public void testListPagingWithFieldOptions() {
218+
RESOURCE_MANAGER.create(PARTIAL_PROJECT);
219+
RESOURCE_MANAGER.create(COMPLETE_PROJECT);
220+
Page<Project> projects = RESOURCE_MANAGER.list(LIST_FIELDS, ProjectListOption.pageSize(1));
221+
assertNotNull(projects.nextPageCursor());
222+
Iterator<Project> iterator = projects.values().iterator();
223+
Project returnedProject = iterator.next();
224+
assertEquals(COMPLETE_PROJECT.projectId(), returnedProject.projectId());
225+
assertEquals(COMPLETE_PROJECT.name(), returnedProject.name());
226+
assertEquals(COMPLETE_PROJECT.labels(), returnedProject.labels());
227+
assertNull(returnedProject.parent());
228+
assertNull(returnedProject.projectNumber());
229+
assertNull(returnedProject.state());
230+
assertNull(returnedProject.createTimeMillis());
231+
assertSame(RESOURCE_MANAGER, returnedProject.resourceManager());
232+
assertFalse(iterator.hasNext());
233+
projects = projects.nextPage();
234+
iterator = projects.values().iterator();
235+
returnedProject = iterator.next();
236+
assertEquals(PARTIAL_PROJECT.projectId(), returnedProject.projectId());
237+
assertEquals(PARTIAL_PROJECT.name(), returnedProject.name());
238+
assertEquals(PARTIAL_PROJECT.labels(), returnedProject.labels());
239+
assertNull(returnedProject.parent());
240+
assertNull(returnedProject.projectNumber());
241+
assertNull(returnedProject.state());
242+
assertNull(returnedProject.createTimeMillis());
243+
assertSame(RESOURCE_MANAGER, returnedProject.resourceManager());
244+
assertFalse(iterator.hasNext());
245+
assertNull(projects.nextPageCursor());
246+
}
247+
216248
@Test
217249
public void testListFilterOptions() {
218250
ProjectInfo matchingProject = ProjectInfo.builder("matching-project")

gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ public static BucketListOption prefix(String prefix) {
655655
*/
656656
public static BucketListOption fields(BucketField... fields) {
657657
StringBuilder builder = new StringBuilder();
658-
builder.append("items(").append(BucketField.selector(fields)).append(")");
658+
builder.append("items(").append(BucketField.selector(fields)).append("),nextPageToken");
659659
return new BucketListOption(StorageRpc.Option.FIELDS, builder.toString());
660660
}
661661
}
@@ -708,7 +708,7 @@ public static BlobListOption recursive(boolean recursive) {
708708
*/
709709
public static BlobListOption fields(BlobField... fields) {
710710
StringBuilder builder = new StringBuilder();
711-
builder.append("items(").append(BlobField.selector(fields)).append(")");
711+
builder.append("items(").append(BlobField.selector(fields)).append("),nextPageToken");
712712
return new BlobListOption(StorageRpc.Option.FIELDS, builder.toString());
713713
}
714714
}

gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,8 @@ public void testListBucketsWithSelectedFields() {
586586
assertTrue(selector.contains("name"));
587587
assertTrue(selector.contains("acl"));
588588
assertTrue(selector.contains("location"));
589-
assertEquals(24, selector.length());
589+
assertTrue(selector.contains("nextPageToken"));
590+
assertEquals(38, selector.length());
590591
assertEquals(cursor, page.nextPageCursor());
591592
assertArrayEquals(bucketList.toArray(), Iterables.toArray(page.values(), Bucket.class));
592593
}
@@ -606,7 +607,8 @@ public void testListBucketsWithEmptyFields() {
606607
String selector = (String) capturedOptions.getValue().get(BLOB_LIST_FIELDS.rpcOption());
607608
assertTrue(selector.contains("items"));
608609
assertTrue(selector.contains("name"));
609-
assertEquals(11, selector.length());
610+
assertTrue(selector.contains("nextPageToken"));
611+
assertEquals(25, selector.length());
610612
assertEquals(cursor, page.nextPageCursor());
611613
assertArrayEquals(bucketList.toArray(), Iterables.toArray(page.values(), Bucket.class));
612614
}
@@ -678,7 +680,8 @@ public void testListBlobsWithSelectedFields() {
678680
assertTrue(selector.contains("name"));
679681
assertTrue(selector.contains("contentType"));
680682
assertTrue(selector.contains("md5Hash"));
681-
assertEquals(38, selector.length());
683+
assertTrue(selector.contains("nextPageToken"));
684+
assertEquals(52, selector.length());
682685
assertEquals(cursor, page.nextPageCursor());
683686
assertArrayEquals(blobList.toArray(), Iterables.toArray(page.values(), Blob.class));
684687
}
@@ -706,7 +709,8 @@ public void testListBlobsWithEmptyFields() {
706709
assertTrue(selector.contains("items"));
707710
assertTrue(selector.contains("bucket"));
708711
assertTrue(selector.contains("name"));
709-
assertEquals(18, selector.length());
712+
assertTrue(selector.contains("nextPageToken"));
713+
assertEquals(32, selector.length());
710714
assertEquals(cursor, page.nextPageCursor());
711715
assertArrayEquals(blobList.toArray(), Iterables.toArray(page.values(), Blob.class));
712716
}

0 commit comments

Comments
 (0)