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 d7934fef72c8..00475922c5b3 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 @@ -1,8 +1,8 @@ package com.google.gcloud.resourcemanager.testing; -import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static java.net.HttpURLConnection.HTTP_OK; import com.google.api.client.json.JsonFactory; import com.google.api.services.cloudresourcemanager.model.Project; @@ -23,8 +23,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.HttpURLConnection; import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; @@ -33,6 +34,7 @@ import java.util.Random; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; import java.util.zip.GZIPInputStream; /** @@ -43,10 +45,12 @@ */ @SuppressWarnings("restriction") public class LocalResourceManagerHelper { + private static final Logger log = Logger.getLogger(LocalResourceManagerHelper.class.getName()); private static final JsonFactory jsonFactory = new com.google.api.client.json.jackson.JacksonFactory(); private static final Random PROJECT_NUMBER_GENERATOR = new Random(); private static final String VERSION = "v1beta1"; + private static final String CONTEXT = "/" + VERSION + "/projects"; // see https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects private static final Set PERMISSIBLE_PROJECT_NAME_PUNCTUATION = @@ -105,11 +109,11 @@ Response response(String message) { } private String toJson(String message) throws IOException { - Map args = new HashMap<>(); Map errors = new HashMap<>(); errors.put("domain", domain); errors.put("message", message); errors.put("reason", reason); + Map args = new HashMap<>(); args.put("errors", ImmutableList.of(errors)); args.put("code", code); args.put("message", message); @@ -120,61 +124,93 @@ private String toJson(String message) throws IOException { private class RequestHandler implements HttpHandler { @Override - public void handle(HttpExchange exchange) throws IOException { + public void handle(HttpExchange exchange) { // see https://cloud.google.com/resource-manager/reference/rest/ - String path = exchange.getRequestURI().getPath(); - String requestMethod = exchange.getRequestMethod(); Response response = null; - if (requestMethod.equals("POST") && path.startsWith("/" + VERSION + "/projects")) { - if (path.contains("undelete")) { - try { - response = undelete(projectIdFromURI(path)); - } catch (IOException e) { - response = Error.BAD_REQUEST.response(e.getMessage()); - } - } else { - String requestBody = - decodeContent(exchange.getRequestHeaders(), exchange.getRequestBody()); - response = create(jsonFactory.fromString(requestBody, Project.class)); - } - } else if (requestMethod.equals("DELETE")) { - response = delete(projectIdFromURI(path)); - } else if (requestMethod.equals("GET")) { - if (path.startsWith("/" + VERSION + "/projects/")) { - response = get(projectIdFromURI(path), parseFields(exchange.getRequestURI().getQuery())); - } else { - response = list(parseListOptions(exchange.getRequestURI().getQuery())); + URI baseContext = null; + try { + baseContext = new URI(CONTEXT); + } catch (URISyntaxException e) { + writeResponse( + exchange, + Error.INTERNAL_ERROR.response( + "URI syntax exception when constructing URI from the path '" + CONTEXT + "'")); + return; + } + String path = baseContext.relativize(exchange.getRequestURI()).getPath(); + String requestMethod = exchange.getRequestMethod(); + try { + switch (requestMethod) { + case "POST": + if (path.contains(":undelete")) { + response = undelete(projectIdFromURI(path)); + } else { + String requestBody = + decodeContent(exchange.getRequestHeaders(), exchange.getRequestBody()); + response = create(jsonFactory.fromString(requestBody, Project.class)); + } + break; + case "DELETE": + response = delete(projectIdFromURI(path)); + break; + case "GET": + if (!path.isEmpty()) { + response = + get(projectIdFromURI(path), parseFields(exchange.getRequestURI().getQuery())); + } else { + response = list(parseListOptions(exchange.getRequestURI().getQuery())); + } + break; + case "PUT": + String requestBody = + decodeContent(exchange.getRequestHeaders(), exchange.getRequestBody()); + response = + replace(projectIdFromURI(path), jsonFactory.fromString(requestBody, Project.class)); + break; + default: + response = Error.BAD_REQUEST.response("The server could not understand the request."); } - } else if (requestMethod.equals("PUT")) { - String requestBody = decodeContent(exchange.getRequestHeaders(), exchange.getRequestBody()); - response = replace(jsonFactory.fromString(requestBody, Project.class)); + } catch (IOException e) { + response = Error.BAD_REQUEST.response(e.getMessage()); } - response = firstNonNull( - response, Error.BAD_REQUEST.response("The server could not understand the request.")); - exchange.getResponseHeaders().set("Content-type", "application/json; charset=UTF-8"); + writeResponse(exchange, response); + } + } + + private static void writeResponse(HttpExchange exchange, Response response) { + exchange.getResponseHeaders().set("Content-type", "application/json; charset=UTF-8"); + OutputStream outputStream = exchange.getResponseBody(); + try { exchange.sendResponseHeaders(response.code(), response.body().length()); - OutputStream outputStream = exchange.getResponseBody(); outputStream.write(response.body().getBytes(StandardCharsets.UTF_8)); outputStream.close(); + } catch (IOException e) { + log.info("IOException encountered when sending response."); } } private static String decodeContent(Headers headers, InputStream inputStream) throws IOException { List contentEncoding = headers.get("Content-encoding"); InputStream input = inputStream; - if (contentEncoding != null && contentEncoding.size() > 0 - && contentEncoding.get(0).contains("gzip")) { - input = new GZIPInputStream(inputStream); + try { + if (contentEncoding != null && !contentEncoding.isEmpty()) { + if (contentEncoding.get(0).equals("gzip") || contentEncoding.get(0).equals("x-gzip")) { + input = new GZIPInputStream(inputStream); + } else if (!contentEncoding.equals("identity")) { + throw new IOException("The request has an unsupported HTTP content encoding."); + } + } + return new String(ByteStreams.toByteArray(input), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new IOException("Exception encountered when decoding request content.", e); } - return new String(ByteStreams.toByteArray(input), StandardCharsets.UTF_8); } private static String projectIdFromURI(String path) throws IOException { - String[] pathSplit = path.split("/"); - if (pathSplit.length < 4) { - throw new IOException("The path '" + path + "' doesn't have a project ID"); + if (path.isEmpty()) { + throw new IOException("The URI path '" + path + "' doesn't have a project ID."); } - return pathSplit[3].split(":")[0]; + return path.split(":")[0]; } private static String[] parseFields(String query) { @@ -246,8 +282,7 @@ private static final String checkForProjectErrors(Project project) { private static final boolean isValidIdOrLabel(String value, int minLength, int maxLength) { for (char c : value.toCharArray()) { - if (c != '-' && !Character.isDigit(c) - && (!Character.isLetter(c) || !Character.isLowerCase(c))) { + if (c != '-' && !Character.isDigit(c) && (!Character.isLowerCase(c))) { return false; } } @@ -258,86 +293,93 @@ private static final boolean isValidIdOrLabel(String value, int minLength, int m } Response create(Project project) { - project.setLifecycleState("ACTIVE"); - project.setProjectNumber(Math.abs(PROJECT_NUMBER_GENERATOR.nextLong() % Long.MAX_VALUE)); - project.setCreateTime(ISODateTimeFormat.dateTime().print(System.currentTimeMillis())); - Response response; String customErrorMessage = checkForProjectErrors(project); if (customErrorMessage != null) { - response = Error.INVALID_ARGUMENT.response(customErrorMessage); - } else if (projects.containsKey(project.getProjectId())) { - response = Error.ALREADY_EXISTS.response( - "A project with the same project ID (" + project.getProjectId() + ") already exists."); + return Error.INVALID_ARGUMENT.response(customErrorMessage); } else { - projects.put(project.getProjectId(), project); + project.setLifecycleState("ACTIVE"); + project.setProjectNumber(Math.abs(PROJECT_NUMBER_GENERATOR.nextLong() % Long.MAX_VALUE)); + project.setCreateTime(ISODateTimeFormat.dateTime().print(System.currentTimeMillis())); + if (projects.putIfAbsent(project.getProjectId(), project) != null) { + return Error.ALREADY_EXISTS.response( + "A project with the same project ID (" + project.getProjectId() + ") already exists."); + } try { String createdProjectStr = jsonFactory.toString(project); - response = new Response(HttpURLConnection.HTTP_OK, createdProjectStr); + return new Response(HTTP_OK, createdProjectStr); } catch (IOException e) { - response = - Error.INTERNAL_ERROR.response("Error serializing project " + project.getProjectId()); + return Error.INTERNAL_ERROR.response("Error serializing project " + project.getProjectId()); } } - return response; } Response delete(String projectId) { - Project project = projects.get(checkNotNull(projectId)); - Response response; + Project project = projects.get(projectId); if (project == null) { // when possible, change this to 404 (#440) - response = Error.PERMISSION_DENIED.response( + return Error.PERMISSION_DENIED.response( "Error when deleting " + projectId + " because the project was not found."); - } else if (!project.getLifecycleState().equals("ACTIVE")) { - response = Error.FAILED_PRECONDITION.response( + } + if (!project.getLifecycleState().equals("ACTIVE")) { + return Error.FAILED_PRECONDITION.response( "Error when deleting " + projectId + " because the lifecycle state was not ACTIVE."); } else { project.setLifecycleState("DELETE_REQUESTED"); - response = new Response(HttpURLConnection.HTTP_OK, "{}"); + return new Response(HTTP_OK, "{}"); } - return response; } Response get(String projectId, String[] fields) { - if (!projects.containsKey(checkNotNull(projectId))) { + if (!projects.containsKey(projectId)) { // when possible, change this to 404 (#440) return Error.PERMISSION_DENIED.response("Project " + projectId + " not found."); } Project project = projects.get(projectId); try { - return new Response( - HttpURLConnection.HTTP_OK, jsonFactory.toString(extractFields(project, fields))); + return new Response(HTTP_OK, jsonFactory.toString(extractFields(project, fields))); } catch (IOException e) { return Error.INTERNAL_ERROR.response( "Error when serializing project " + project.getProjectId()); } } - Response list(final Map options) { + 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()) { - Boolean includeProject = includeProject(p, (String[]) options.get("filter")); + Boolean includeProject = includeProject(p, filters); if (includeProject) { try { - projectsSerialized.add( - jsonFactory.toString(extractFields(p, (String[]) options.get("fields")))); + projectsSerialized.add(jsonFactory.toString(extractFields(p, fields))); } catch (IOException e) { return Error.INTERNAL_ERROR.response( "Error when serializing project " + p.getProjectId()); } - } else if (includeProject == null) { - return Error.INVALID_ARGUMENT.response("Could not parse the filter."); } } StringBuilder responseBody = new StringBuilder(); responseBody.append("{\"projects\": ["); - responseBody.append(Joiner.on(",").join(projectsSerialized)); + Joiner.on(",").appendTo(responseBody, projectsSerialized); responseBody.append("]}"); - return new Response(HttpURLConnection.HTTP_OK, responseBody.toString()); + return new Response(HTTP_OK, responseBody.toString()); } - private static Boolean includeProject(Project project, String[] filters) { + private static boolean isValidFilter(String[] filters) { + for (String filter : filters) { + String field = filter.toLowerCase().split(":")[0]; + if (!("id".equals(field) || "name".equals(field) || field.startsWith("labels."))) { + return false; + } + } + return true; + } + + private static boolean includeProject(Project project, String[] filters) { if (filters == null) { return true; } @@ -359,8 +401,6 @@ private static Boolean includeProject(Project project, String[] filters) { return false; } } - } else { - return null; } } return true; @@ -406,35 +446,32 @@ private static Project extractFields(Project fullProject, String[] fields) { return project; } - Response replace(Project project) { - Project oldProject = projects.get(project.getProjectId()); - if (oldProject == null) { + Response replace(String projectId, Project project) { + Project originalProject = projects.get(projectId); + if (originalProject == null) { // when possible, change this to 404 (#440) return Error.PERMISSION_DENIED.response( - "Error when replacing " + project.getProjectId() + " because the project was not found."); - } else if (!oldProject.getLifecycleState().equals("ACTIVE")) { - return Error.FAILED_PRECONDITION.response("Error when replacing " + project.getProjectId() - + " because the lifecycle state was not ACTIVE."); - } else if (!Objects.equal(oldProject.getParent(), project.getParent())) { + "Error when replacing " + projectId + " because the project was not found."); + } else if (!originalProject.getLifecycleState().equals("ACTIVE")) { + return Error.FAILED_PRECONDITION.response( + "Error when replacing " + projectId + " because the lifecycle state was not ACTIVE."); + } else if (!Objects.equal(originalProject.getParent(), project.getParent())) { return Error.INVALID_ARGUMENT.response( "The server currently only supports setting the parent once " + "and does not allow unsetting it."); } - project.setLifecycleState("ACTIVE"); - project.setProjectNumber(oldProject.getProjectNumber()); - project.setCreateTime(oldProject.getCreateTime()); - project.setParent(oldProject.getParent()); - projects.put(project.getProjectId(), project); + originalProject.setName(project.getName()); + originalProject.setLabels(project.getLabels()); + originalProject.setParent(project.getParent()); try { - return new Response(HttpURLConnection.HTTP_OK, jsonFactory.toString(project)); + return new Response(HTTP_OK, jsonFactory.toString(originalProject)); } catch (IOException e) { - return Error.INTERNAL_ERROR.response( - "Error when serializing project " + project.getProjectId()); + return Error.INTERNAL_ERROR.response("Error when serializing project " + projectId); } } Response undelete(String projectId) { - Project project = projects.get(checkNotNull(projectId)); + Project project = projects.get(projectId); Response response; if (project == null) { // when possible, change this to 404 (#440) @@ -445,7 +482,7 @@ Response undelete(String projectId) { + " because the lifecycle state was not DELETE_REQUESTED."); } else { project.setLifecycleState("ACTIVE"); - response = new Response(HttpURLConnection.HTTP_OK, "{}"); + response = new Response(HTTP_OK, "{}"); } return response; } @@ -455,7 +492,7 @@ private LocalResourceManagerHelper() { try { server = HttpServer.create(addr, 0); port = server.getAddress().getPort(); - server.createContext("/", new RequestHandler()); + server.createContext(CONTEXT, new RequestHandler()); } catch (IOException e) { throw new RuntimeException("Could not bind the mock Resource Manager server.", e); } @@ -489,69 +526,6 @@ public void stop() { server.stop(1); } - /** - * Utility method to add a project. - * - *

Will not overwrite an existing project with the same ID. - * - * @return true if the project was successfully added, false if the project already exists or is - * invalid - */ - public boolean addProject(Project project) { - if (checkForProjectErrors(project) == null) { - return projects.putIfAbsent(project.getProjectId(), clone(project)) == null ? true : false; - } - return false; - } - - /** - * Utility method to get a project. - * - * @return Project (if it exists) or null (if it doesn't exist) - */ - public Project getProject(String projectId) { - Project original = projects.get(projectId); - return original != null ? clone(projects.get(projectId)) : null; - } - - private static Project clone(Project original) { - return new Project() - .setProjectId(original.getProjectId()) - .setName(original.getName()) - .setLabels(original.getLabels() != null ? ImmutableMap.copyOf(original.getLabels()) : null) - .setProjectNumber( - original.getProjectNumber() != null ? original.getProjectNumber().longValue() : null) - .setCreateTime(original.getCreateTime()) - .setLifecycleState(original.getLifecycleState()) - .setParent(original.getParent() != null ? original.getParent().clone() : null); - } - - /** - * Utility method to remove the specified project. - * - *

This method can be used to fully remove a project (to mimic when the server completely - * deletes a project). - * - * @return true if the project was successfully deleted, false otherwise. - */ - public boolean removeProject(String projectId) { - return projects.remove(checkNotNull(projectId)) != null ? true : false; - } - - /** - * Utility method to change the project number of a project. - * - * @return true if the project number was successfully changed, false otherwise. - */ - public boolean changeProjectNumber(String projectId, long projectNumber) { - Project project = projects.get(checkNotNull(projectId)); - if (project != null) { - project.setProjectNumber(projectNumber); - return true; - } - return false; - } - /** * Utility method to change the lifecycle state of the specified project. * @@ -571,23 +545,14 @@ public boolean changeLifecycleState(String projectId, String lifecycleState) { } /** - * Utility method to change the create time of a project. + * Utility method to remove the specified project. * - * @return true if the project create time was successfully changed, false otherwise. - */ - public boolean changeCreateTime(String projectId, String createTime) { - Project project = projects.get(checkNotNull(projectId)); - if (project != null) { - project.setCreateTime(checkNotNull(createTime)); - return true; - } - return false; - } - - /** - * Utility method to clear all the projects. + *

This method can be used to fully remove a project (to mimic when the server completely + * deletes a project). + * + * @return true if the project was successfully deleted, false otherwise. */ - public void clearProjects() { - projects.clear(); + public boolean removeProject(String projectId) { + return projects.remove(checkNotNull(projectId)) != null ? true : false; } } 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 ac329e9aa6d0..5bd87d1d4335 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 @@ -24,8 +24,6 @@ public class LocalResourceManagerHelperTest { - private static final long DEFAULT_PROJECT_NUMBER = 123456789L; - private static final String DEFAULT_CREATE_TIME = "2011-11-11T01:23:45.678Z"; private static final String DEFAULT_PARENT_ID = "12345"; private static final String DEFAULT_PARENT_TYPE = "organization"; private static final com.google.api.services.cloudresourcemanager.model.ResourceId PARENT = @@ -46,18 +44,7 @@ public class LocalResourceManagerHelperTest { new com.google.api.services.cloudresourcemanager.model.Project() .setProjectId("complete-project") .setName("full project") - .setLabels(ImmutableMap.of("k1", "v1", "k2", "v2")) - .setProjectNumber(DEFAULT_PROJECT_NUMBER) - .setCreateTime(DEFAULT_CREATE_TIME) - .setLifecycleState("ACTIVE"); - private static final com.google.api.services.cloudresourcemanager.model.Project - DELETE_REQUESTED_PROJECT = copyFrom(COMPLETE_PROJECT) - .setProjectId("delete-requested-project-id") - .setLifecycleState("DELETE_REQUESTED"); - private static final com.google.api.services.cloudresourcemanager.model.Project - DELETE_IN_PROGRESS_PROJECT = copyFrom(COMPLETE_PROJECT) - .setProjectId("delete-in-progress-project-id") - .setLifecycleState("DELETE_IN_PROGRESS"); + .setLabels(ImmutableMap.of("k1", "v1", "k2", "v2")); private static final com.google.api.services.cloudresourcemanager.model.Project PROJECT_WITH_PARENT = copyFrom(COMPLETE_PROJECT).setProjectId("project-with-parent-id").setParent(PARENT); @@ -80,9 +67,17 @@ private static com.google.api.services.cloudresourcemanager.model.Project copyFr .setParent(from.getParent() != null ? from.getParent().clone() : null); } + private void clearProjects() { + Iterator it = + rpc.list(EMPTY_RPC_OPTIONS).y().iterator(); + while (it.hasNext()) { + RESOURCE_MANAGER_HELPER.removeProject(it.next().getProjectId()); + } + } + @Before public void setUp() { - RESOURCE_MANAGER_HELPER.clearProjects(); + clearProjects(); } @AfterClass @@ -94,7 +89,7 @@ public static void afterClass() { public void testCreate() { com.google.api.services.cloudresourcemanager.model.Project returnedProject = rpc.create(PARTIAL_PROJECT); - assertEquals(PARTIAL_PROJECT.getProjectId(), returnedProject.getProjectId()); + compareReadWriteFields(PARTIAL_PROJECT, returnedProject); assertEquals("ACTIVE", returnedProject.getLifecycleState()); assertNull(returnedProject.getLabels()); assertNull(returnedProject.getName()); @@ -110,13 +105,10 @@ public void testCreate() { && e.getMessage().endsWith("already exists.")); } returnedProject = rpc.create(PROJECT_WITH_PARENT); - assertEquals(PROJECT_WITH_PARENT.getProjectId(), returnedProject.getProjectId()); + compareReadWriteFields(PROJECT_WITH_PARENT, returnedProject); assertEquals("ACTIVE", returnedProject.getLifecycleState()); - assertEquals(PARENT, returnedProject.getParent()); - assertEquals(PROJECT_WITH_PARENT.getLabels(), returnedProject.getLabels()); - assertEquals(PROJECT_WITH_PARENT.getName(), returnedProject.getName()); assertNotNull(returnedProject.getProjectNumber()); - assertFalse(PROJECT_WITH_PARENT.getCreateTime().equals(returnedProject.getCreateTime())); + assertNotNull(returnedProject.getCreateTime()); } @Test @@ -137,7 +129,7 @@ public void testIsInvalidProjectId() { expectInvalidArgumentException(project, invalidIDMessageSubstring); project.setProjectId("some-valid-project-id-12345"); rpc.create(project); - assertNotNull(RESOURCE_MANAGER_HELPER.getProject(project.getProjectId())); + assertNotNull(rpc.get(project.getProjectId(), EMPTY_RPC_OPTIONS)); } private void expectInvalidArgumentException( @@ -158,12 +150,11 @@ public void testIsInvalidProjectName() { new com.google.api.services.cloudresourcemanager.model.Project().setProjectId( "some-project-id"); rpc.create(project); - assertNull(RESOURCE_MANAGER_HELPER.getProject(project.getProjectId()).getName()); + assertNull(rpc.get(project.getProjectId(), EMPTY_RPC_OPTIONS).getName()); RESOURCE_MANAGER_HELPER.removeProject(project.getProjectId()); project.setName("This is a valid name-'\"!"); rpc.create(project); - assertEquals( - project.getName(), RESOURCE_MANAGER_HELPER.getProject(project.getProjectId()).getName()); + assertEquals(project.getName(), rpc.get(project.getProjectId(), EMPTY_RPC_OPTIONS).getName()); RESOURCE_MANAGER_HELPER.removeProject(project.getProjectId()); project.setName("invalid-character-,"); try { @@ -180,9 +171,7 @@ public void testIsInvalidProjectLabels() { com.google.api.services.cloudresourcemanager.model.Project project = new com.google.api.services.cloudresourcemanager.model.Project().setProjectId( "some-valid-project-id"); - rpc.create(project); String invalidLabelMessageSubstring = "invalid label entry"; - RESOURCE_MANAGER_HELPER.removeProject(project.getProjectId()); project.setLabels(ImmutableMap.of("", "v1")); expectInvalidArgumentException(project, invalidLabelMessageSubstring); project.setLabels(ImmutableMap.of( @@ -210,8 +199,8 @@ public void testIsInvalidProjectLabels() { expectInvalidArgumentException(project, invalidLabelMessageSubstring); project.setLabels(ImmutableMap.of("k-1", "")); rpc.create(project); - assertNotNull(RESOURCE_MANAGER_HELPER.getProject(project.getProjectId())); - assertTrue(RESOURCE_MANAGER_HELPER.getProject(project.getProjectId()) + assertNotNull(rpc.get(project.getProjectId(), EMPTY_RPC_OPTIONS)); + assertTrue(rpc.get(project.getProjectId(), EMPTY_RPC_OPTIONS) .getLabels() .get("k-1") .isEmpty()); @@ -219,20 +208,23 @@ public void testIsInvalidProjectLabels() { @Test public void testDelete() { - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + rpc.create(COMPLETE_PROJECT); rpc.delete(COMPLETE_PROJECT.getProjectId()); + assertEquals( + "DELETE_REQUESTED", + rpc.get(COMPLETE_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS).getLifecycleState()); try { rpc.delete("some-nonexistant-project-id"); - fail("Should fail because the project was already deleted."); + fail("Should fail because the project doesn't exist."); } catch (ResourceManagerException e) { assertEquals(403, e.code()); - assertTrue(e.getMessage().contains("the project was not found")); + assertTrue(e.getMessage().contains("not found.")); } } @Test public void testDeleteWhenDeleteInProgress() { - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + rpc.create(COMPLETE_PROJECT); RESOURCE_MANAGER_HELPER.changeLifecycleState( COMPLETE_PROJECT.getProjectId(), "DELETE_IN_PROGRESS"); try { @@ -246,7 +238,7 @@ public void testDeleteWhenDeleteInProgress() { @Test public void testDeleteWhenDeleteRequested() { - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + rpc.create(COMPLETE_PROJECT); RESOURCE_MANAGER_HELPER.changeLifecycleState( COMPLETE_PROJECT.getProjectId(), "DELETE_REQUESTED"); try { @@ -260,10 +252,10 @@ public void testDeleteWhenDeleteRequested() { @Test public void testGet() { - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + rpc.create(COMPLETE_PROJECT); com.google.api.services.cloudresourcemanager.model.Project returnedProject = rpc.get(COMPLETE_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS); - assertEquals(COMPLETE_PROJECT, returnedProject); + compareReadWriteFields(COMPLETE_PROJECT, returnedProject); RESOURCE_MANAGER_HELPER.removeProject(COMPLETE_PROJECT.getProjectId()); try { rpc.get(COMPLETE_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS); @@ -276,7 +268,8 @@ public void testGet() { @Test public void testGetWithOptions() { - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + com.google.api.services.cloudresourcemanager.model.Project originalProject = + rpc.create(COMPLETE_PROJECT); Map rpcOptions = new HashMap<>(); rpcOptions.put(ResourceManagerRpc.Option.FIELDS, "projectId,name,createTime"); com.google.api.services.cloudresourcemanager.model.Project returnedProject = @@ -284,7 +277,7 @@ public void testGetWithOptions() { assertFalse(COMPLETE_PROJECT.equals(returnedProject)); assertEquals(COMPLETE_PROJECT.getProjectId(), returnedProject.getProjectId()); assertEquals(COMPLETE_PROJECT.getName(), returnedProject.getName()); - assertEquals(COMPLETE_PROJECT.getCreateTime(), returnedProject.getCreateTime()); + assertEquals(originalProject.getCreateTime(), returnedProject.getCreateTime()); assertNull(returnedProject.getParent()); assertNull(returnedProject.getProjectNumber()); assertNull(returnedProject.getLifecycleState()); @@ -297,13 +290,15 @@ public void testList() { rpc.list(EMPTY_RPC_OPTIONS); assertNull(projects.x()); // change this when #421 is resolved assertFalse(projects.y().iterator().hasNext()); - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); - RESOURCE_MANAGER_HELPER.addProject(PROJECT_WITH_PARENT); + rpc.create(COMPLETE_PROJECT); + RESOURCE_MANAGER_HELPER.changeLifecycleState( + COMPLETE_PROJECT.getProjectId(), "DELETE_REQUESTED"); + rpc.create(PROJECT_WITH_PARENT); projects = rpc.list(EMPTY_RPC_OPTIONS); Iterator it = projects.y().iterator(); - assertEquals(COMPLETE_PROJECT, it.next()); - assertEquals(PROJECT_WITH_PARENT, it.next()); + compareReadWriteFields(COMPLETE_PROJECT, it.next()); + compareReadWriteFields(PROJECT_WITH_PARENT, it.next()); } @Test @@ -312,7 +307,7 @@ public void testListFieldOptions() { rpcOptions.put(ResourceManagerRpc.Option.FIELDS, "projectId,name,labels"); rpcOptions.put(ResourceManagerRpc.Option.PAGE_TOKEN, "somePageToken"); rpcOptions.put(ResourceManagerRpc.Option.PAGE_SIZE, 1); - RESOURCE_MANAGER_HELPER.addProject(PROJECT_WITH_PARENT); + rpc.create(PROJECT_WITH_PARENT); Tuple> projects = rpc.list(rpcOptions); com.google.api.services.cloudresourcemanager.model.Project returnedProject = @@ -336,39 +331,36 @@ public void testListFilterOptions() { new com.google.api.services.cloudresourcemanager.model.Project() .setProjectId("matching-project") .setName("MyProject") - .setProjectNumber(DEFAULT_PROJECT_NUMBER) - .setLabels(ImmutableMap.of("Color", "blue", "size", "Big")); + .setLabels(ImmutableMap.of("color", "blue", "size", "big")); com.google.api.services.cloudresourcemanager.model.Project nonMatchingProject1 = new com.google.api.services.cloudresourcemanager.model.Project() .setProjectId("non-matching-project1") - .setName("myProject") - .setProjectNumber(DEFAULT_PROJECT_NUMBER); + .setName("myProject"); nonMatchingProject1.setLabels(ImmutableMap.of("color", "blue")); com.google.api.services.cloudresourcemanager.model.Project nonMatchingProject2 = new com.google.api.services.cloudresourcemanager.model.Project() .setProjectId("non-matching-project2") .setName("myProj") - .setProjectNumber(DEFAULT_PROJECT_NUMBER) .setLabels(ImmutableMap.of("color", "blue", "size", "big")); com.google.api.services.cloudresourcemanager.model.Project nonMatchingProject3 = - new com.google.api.services.cloudresourcemanager.model.Project() - .setProjectId("non-matching-project3") - .setProjectNumber(DEFAULT_PROJECT_NUMBER); - RESOURCE_MANAGER_HELPER.addProject(matchingProject); - RESOURCE_MANAGER_HELPER.addProject(nonMatchingProject1); - RESOURCE_MANAGER_HELPER.addProject(nonMatchingProject2); - RESOURCE_MANAGER_HELPER.addProject(nonMatchingProject3); + new com.google.api.services.cloudresourcemanager.model.Project().setProjectId( + "non-matching-project3"); + rpc.create(matchingProject); + rpc.create(nonMatchingProject1); + rpc.create(nonMatchingProject2); + rpc.create(nonMatchingProject3); for (com.google.api.services.cloudresourcemanager.model.Project p : rpc.list(rpcFilterOptions).y()) { assertFalse(p.equals(nonMatchingProject1)); assertFalse(p.equals(nonMatchingProject2)); - assertTrue(p.equals(matchingProject)); + compareReadWriteFields(matchingProject, p); } } @Test public void testReplace() { - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + com.google.api.services.cloudresourcemanager.model.Project createdProject = + rpc.create(COMPLETE_PROJECT); String newName = "new name"; Map newLabels = ImmutableMap.of("new k1", "new v1"); com.google.api.services.cloudresourcemanager.model.Project anotherCompleteProject = @@ -379,16 +371,12 @@ public void testReplace() { .setProjectNumber(987654321L) .setCreateTime("2000-01-01T00:00:00.001Z") .setLifecycleState("DELETE_REQUESTED"); - rpc.replace(anotherCompleteProject); com.google.api.services.cloudresourcemanager.model.Project returnedProject = - RESOURCE_MANAGER_HELPER.getProject(COMPLETE_PROJECT.getProjectId()); - assertEquals(COMPLETE_PROJECT.getProjectId(), returnedProject.getProjectId()); - assertEquals(newName, returnedProject.getName()); - assertEquals(newLabels, returnedProject.getLabels()); - assertEquals(COMPLETE_PROJECT.getProjectNumber(), returnedProject.getProjectNumber()); - assertEquals(COMPLETE_PROJECT.getCreateTime(), returnedProject.getCreateTime()); - assertEquals(COMPLETE_PROJECT.getLifecycleState(), returnedProject.getLifecycleState()); - assertNull(returnedProject.getParent()); + rpc.replace(anotherCompleteProject); + compareReadWriteFields(anotherCompleteProject, returnedProject); + assertEquals(createdProject.getProjectNumber(), returnedProject.getProjectNumber()); + assertEquals(createdProject.getCreateTime(), returnedProject.getCreateTime()); + assertEquals(createdProject.getLifecycleState(), returnedProject.getLifecycleState()); com.google.api.services.cloudresourcemanager.model.Project nonexistantProject = new com.google.api.services.cloudresourcemanager.model.Project(); nonexistantProject.setProjectId("some-project-id-that-does-not-exist"); @@ -403,10 +391,11 @@ public void testReplace() { @Test public void testReplaceWhenDeleteRequested() { - RESOURCE_MANAGER_HELPER.addProject(DELETE_REQUESTED_PROJECT); + rpc.create(COMPLETE_PROJECT); + rpc.delete(COMPLETE_PROJECT.getProjectId()); com.google.api.services.cloudresourcemanager.model.Project anotherProject = new com.google.api.services.cloudresourcemanager.model.Project().setProjectId( - DELETE_REQUESTED_PROJECT.getProjectId()); + COMPLETE_PROJECT.getProjectId()); try { rpc.replace(anotherProject); fail("Should fail because the project is not ACTIVE."); @@ -418,10 +407,12 @@ public void testReplaceWhenDeleteRequested() { @Test public void testReplaceWhenDeleteInProgress() { - RESOURCE_MANAGER_HELPER.addProject(DELETE_IN_PROGRESS_PROJECT); + rpc.create(COMPLETE_PROJECT); + RESOURCE_MANAGER_HELPER.changeLifecycleState( + COMPLETE_PROJECT.getProjectId(), "DELETE_IN_PROGRESS"); com.google.api.services.cloudresourcemanager.model.Project anotherProject = new com.google.api.services.cloudresourcemanager.model.Project().setProjectId( - DELETE_IN_PROGRESS_PROJECT.getProjectId()); + COMPLETE_PROJECT.getProjectId()); try { rpc.replace(anotherProject); fail("Should fail because the project is not ACTIVE."); @@ -433,7 +424,7 @@ public void testReplaceWhenDeleteInProgress() { @Test public void testReplaceAddingParent() { - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + rpc.create(COMPLETE_PROJECT); com.google.api.services.cloudresourcemanager.model.Project anotherProject = new com.google.api.services.cloudresourcemanager.model.Project() .setProjectId(COMPLETE_PROJECT.getProjectId()) @@ -452,7 +443,7 @@ public void testReplaceAddingParent() { @Test public void testReplaceRemovingParent() { - RESOURCE_MANAGER_HELPER.addProject(PROJECT_WITH_PARENT); + rpc.create(PROJECT_WITH_PARENT); com.google.api.services.cloudresourcemanager.model.Project anotherProject = new com.google.api.services.cloudresourcemanager.model.Project().setProjectId( PROJECT_WITH_PARENT.getProjectId()); @@ -470,11 +461,16 @@ public void testReplaceRemovingParent() { @Test public void testUndelete() { - RESOURCE_MANAGER_HELPER.addProject(DELETE_REQUESTED_PROJECT); - rpc.undelete(DELETE_REQUESTED_PROJECT.getProjectId()); - com.google.api.services.cloudresourcemanager.model.Project returnedProject = - rpc.get(DELETE_REQUESTED_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS); - assertEquals("ACTIVE", returnedProject.getLifecycleState()); + rpc.create(COMPLETE_PROJECT); + rpc.delete(COMPLETE_PROJECT.getProjectId()); + assertEquals( + "DELETE_REQUESTED", + rpc.get(COMPLETE_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS).getLifecycleState()); + rpc.undelete(COMPLETE_PROJECT.getProjectId()); + com.google.api.services.cloudresourcemanager.model.Project revivedProject = + rpc.get(COMPLETE_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS); + compareReadWriteFields(COMPLETE_PROJECT, revivedProject); + assertEquals("ACTIVE", revivedProject.getLifecycleState()); try { rpc.undelete("invalid-project-id"); fail("Should fail because the project doesn't exist."); @@ -486,7 +482,7 @@ public void testUndelete() { @Test public void testUndeleteWhenActive() { - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + rpc.create(COMPLETE_PROJECT); try { rpc.undelete(COMPLETE_PROJECT.getProjectId()); fail("Should fail because the project is not deleted."); @@ -498,10 +494,12 @@ public void testUndeleteWhenActive() { @Test public void testUndeleteWhenDeleteInProgress() { - RESOURCE_MANAGER_HELPER.addProject(DELETE_IN_PROGRESS_PROJECT); + rpc.create(COMPLETE_PROJECT); + RESOURCE_MANAGER_HELPER.changeLifecycleState( + COMPLETE_PROJECT.getProjectId(), "DELETE_IN_PROGRESS"); try { - rpc.undelete(DELETE_IN_PROGRESS_PROJECT.getProjectId()); - fail("Should fail because the project is not deleted."); + rpc.undelete(COMPLETE_PROJECT.getProjectId()); + fail("Should fail because the project is in the process of being deleted."); } catch (ResourceManagerException e) { assertEquals(400, e.code()); assertTrue(e.getMessage().contains("lifecycle state was not DELETE_REQUESTED")); @@ -512,9 +510,12 @@ public void testUndeleteWhenDeleteInProgress() { public void testChangeLifecycleStatus() { assertFalse(RESOURCE_MANAGER_HELPER.changeLifecycleState( COMPLETE_PROJECT.getProjectId(), "DELETE_IN_PROGRESS")); - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + rpc.create(COMPLETE_PROJECT); assertTrue(RESOURCE_MANAGER_HELPER.changeLifecycleState( COMPLETE_PROJECT.getProjectId(), "DELETE_IN_PROGRESS")); + assertEquals( + "DELETE_IN_PROGRESS", + rpc.get(COMPLETE_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS).getLifecycleState()); try { RESOURCE_MANAGER_HELPER.changeLifecycleState( COMPLETE_PROJECT.getProjectId(), "INVALID_STATE"); @@ -524,53 +525,26 @@ public void testChangeLifecycleStatus() { } } - @Test - public void testAddProject() { - assertTrue(RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT)); - com.google.api.services.cloudresourcemanager.model.Project project = - new com.google.api.services.cloudresourcemanager.model.Project().setProjectId( - COMPLETE_PROJECT.getProjectId()); - assertFalse(RESOURCE_MANAGER_HELPER.addProject(project)); - assertFalse( - project.equals(RESOURCE_MANAGER_HELPER.getProject(COMPLETE_PROJECT.getProjectId()))); - assertFalse(RESOURCE_MANAGER_HELPER.addProject( - new com.google.api.services.cloudresourcemanager.model.Project())); - } - - @Test - public void testGetProject() { - assertNull(RESOURCE_MANAGER_HELPER.getProject("some-invalid-project-id")); - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); - assertEquals( - COMPLETE_PROJECT, RESOURCE_MANAGER_HELPER.getProject(COMPLETE_PROJECT.getProjectId())); - } - @Test public void testRemoveProject() { assertFalse(RESOURCE_MANAGER_HELPER.removeProject(COMPLETE_PROJECT.getProjectId())); - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); + rpc.create(COMPLETE_PROJECT); assertTrue(RESOURCE_MANAGER_HELPER.removeProject(COMPLETE_PROJECT.getProjectId())); + try { + rpc.get(COMPLETE_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS); + fail("Project shouldn't exist."); + } catch (ResourceManagerException e) { + assertEquals(403, e.code()); + assertTrue(e.getMessage().contains("not found.")); + } } - @Test - public void testChangeProjectNumber() { - assertFalse(RESOURCE_MANAGER_HELPER.changeProjectNumber(COMPLETE_PROJECT.getProjectId(), 123L)); - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); - assertTrue(RESOURCE_MANAGER_HELPER.changeProjectNumber(COMPLETE_PROJECT.getProjectId(), 123L)); - } - - @Test - public void testChangeCreateTime() { - assertFalse(RESOURCE_MANAGER_HELPER.changeCreateTime( - COMPLETE_PROJECT.getProjectId(), "2015-01-01T01:01:01.001Z")); - RESOURCE_MANAGER_HELPER.addProject(COMPLETE_PROJECT); - assertTrue(RESOURCE_MANAGER_HELPER.changeCreateTime( - COMPLETE_PROJECT.getProjectId(), "2015-01-01T01:01:01.001Z")); - } - - @Test - public void testClearProjects() { - RESOURCE_MANAGER_HELPER.clearProjects(); - assertFalse(rpc.list(EMPTY_RPC_OPTIONS).y().iterator().hasNext()); + private void compareReadWriteFields( + com.google.api.services.cloudresourcemanager.model.Project expected, + com.google.api.services.cloudresourcemanager.model.Project actual) { + assertEquals(expected.getProjectId(), actual.getProjectId()); + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getLabels(), actual.getLabels()); + assertEquals(expected.getParent(), actual.getParent()); } }