From d998fabea7126fe8653369258c82eac1f4b20b88 Mon Sep 17 00:00:00 2001 From: Ajit Thakor <49403056+athakor@users.noreply.github.com> Date: Mon, 13 Apr 2020 22:30:27 +0530 Subject: [PATCH] feat: expose apis of resourcemanager folders (#99) * feat: expose folders apis * feat: change the position of serialVersionUID * feat: modified code as well add system test for constraint and org policy * feat: add more checks to fix code coverage * feat: simplified the code as per the existing design * feat: fix the review changes as well as simplified the code * feat: add mockito tests instead of easymock * feat: review changes fixes * feat: fix review changes * feat: fix review changes * feat: fix all the testcases * feat: fix review changes * feat: address feedback * feat: address feedback --- clirr-ignored-differences.xml | 60 +++ .../cloud/resourcemanager/ConstraintInfo.java | 293 +++++++++++++ .../cloud/resourcemanager/OrgPolicyInfo.java | 388 ++++++++++++++++++ .../resourcemanager/ResourceManager.java | 98 +++++ .../resourcemanager/ResourceManagerImpl.java | 201 +++++++++ .../spi/v1beta1/HttpResourceManagerRpc.java | 101 +++++ .../spi/v1beta1/ResourceManagerRpc.java | 77 ++++ .../resourcemanager/ConstraintInfoTest.java | 119 ++++++ .../resourcemanager/OrgPolicyInfoTest.java | 137 +++++++ .../ResourceManagerImplTest.java | 377 +++++++++++++++-- 10 files changed, 1807 insertions(+), 44 deletions(-) create mode 100644 src/main/java/com/google/cloud/resourcemanager/ConstraintInfo.java create mode 100644 src/main/java/com/google/cloud/resourcemanager/OrgPolicyInfo.java create mode 100644 src/test/java/com/google/cloud/resourcemanager/ConstraintInfoTest.java create mode 100644 src/test/java/com/google/cloud/resourcemanager/OrgPolicyInfoTest.java diff --git a/clirr-ignored-differences.xml b/clirr-ignored-differences.xml index da1f3c38..24266840 100644 --- a/clirr-ignored-differences.xml +++ b/clirr-ignored-differences.xml @@ -6,9 +6,69 @@ java.util.Map testOrgPermissions(java.lang.String, java.util.List) 7012 + + com/google/cloud/resourcemanager/ResourceManager + void clearOrgPolicy(java.lang.String, com.google.cloud.resourcemanager.OrgPolicyInfo) + 7012 + + + com/google/cloud/resourcemanager/ResourceManager + com.google.cloud.resourcemanager.OrgPolicyInfo getEffectiveOrgPolicy(java.lang.String, java.lang.String) + 7012 + + + com/google/cloud/resourcemanager/ResourceManager + com.google.cloud.resourcemanager.OrgPolicyInfo getOrgPolicy(java.lang.String, java.lang.String) + 7012 + + + com/google/cloud/resourcemanager/ResourceManager + com.google.api.gax.paging.Page listAvailableOrgPolicyConstraints(java.lang.String, com.google.cloud.resourcemanager.ResourceManager$ListOption[]) + 7012 + + + com/google/cloud/resourcemanager/ResourceManager + com.google.api.gax.paging.Page listOrgPolicies(java.lang.String, com.google.cloud.resourcemanager.ResourceManager$ListOption[]) + 7012 + + + com/google/cloud/resourcemanager/ResourceManager + com.google.cloud.resourcemanager.OrgPolicyInfo replaceOrgPolicy(java.lang.String, com.google.cloud.resourcemanager.OrgPolicyInfo) + 7012 + com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc java.util.Map testOrgPermissions(java.lang.String, java.util.List) 7012 + + com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc + void clearOrgPolicy(java.lang.String, com.google.api.services.cloudresourcemanager.model.OrgPolicy) + 7012 + + + com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc + com.google.api.services.cloudresourcemanager.model.OrgPolicy getEffectiveOrgPolicy(java.lang.String, java.lang.String) + 7012 + + + com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc + com.google.api.services.cloudresourcemanager.model.OrgPolicy getOrgPolicy(java.lang.String, java.lang.String) + 7012 + + + com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc + com.google.cloud.resourcemanager.spi.v1beta1.ResourceManagerRpc$ListResult listAvailableOrgPolicyConstraints(java.lang.String, java.util.Map) + 7012 + + + com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc + com.google.cloud.resourcemanager.spi.v1beta1.ResourceManagerRpc$ListResult listOrgPolicies(java.lang.String, java.util.Map) + 7012 + + + com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc + com.google.api.services.cloudresourcemanager.model.OrgPolicy replaceOrgPolicy(java.lang.String, com.google.api.services.cloudresourcemanager.model.OrgPolicy) + 7012 + diff --git a/src/main/java/com/google/cloud/resourcemanager/ConstraintInfo.java b/src/main/java/com/google/cloud/resourcemanager/ConstraintInfo.java new file mode 100644 index 00000000..b6ddc915 --- /dev/null +++ b/src/main/java/com/google/cloud/resourcemanager/ConstraintInfo.java @@ -0,0 +1,293 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.resourcemanager; + +import com.google.api.services.cloudresourcemanager.model.BooleanConstraint; +import com.google.api.services.cloudresourcemanager.model.Constraint; +import com.google.api.services.cloudresourcemanager.model.ListConstraint; +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; +import java.util.Objects; + +/** + * A Google Cloud Resource Manager constraint metadata object. + * + * @see Constraint + */ +public class ConstraintInfo { + + static final Function FROM_PROTOBUF_FUNCTION = + new Function() { + @Override + public ConstraintInfo apply(Constraint protobuf) { + return ConstraintInfo.fromProtobuf(protobuf); + } + }; + static final Function TO_PROTOBUF_FUNCTION = + new Function() { + @Override + public Constraint apply(ConstraintInfo constraintInfo) { + return constraintInfo.toProtobuf(); + } + }; + + private BooleanConstraint booleanConstraint; + private String constraintDefault; + private String description; + private String displayName; + private Constraints constraints; + private String name; + private Integer version; + + /** + * A Constraint that allows or disallows a list of string values, which are configured by an + * Organization's policy administrator with a Policy. + */ + static class Constraints { + + private final String suggestedValue; + private final Boolean supportsUnder; + + Constraints(String suggestedValue, Boolean supportsUnder) { + this.suggestedValue = suggestedValue; + this.supportsUnder = supportsUnder; + } + + /** + * The Google Cloud Console tries to default to a configuration that matches the value specified + * in this Constraint. + */ + String getSuggestedValue() { + return suggestedValue; + } + + /** + * Indicates whether subtrees of Cloud Resource Manager resource hierarchy can be used in + * Policy.allowed_values and Policy.denied_values. + */ + Boolean getSupportsUnder() { + return supportsUnder; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("suggestedValue", getSuggestedValue()) + .add("supportsUnder", getSupportsUnder()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(suggestedValue, supportsUnder); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Constraints that = (Constraints) o; + return Objects.equals(suggestedValue, that.suggestedValue) + && Objects.equals(supportsUnder, that.supportsUnder); + } + + ListConstraint toProtobuf() { + return new ListConstraint().setSuggestedValue(suggestedValue).setSupportsUnder(supportsUnder); + } + + static Constraints fromProtobuf(ListConstraint listConstraint) { + return new Constraints(listConstraint.getSuggestedValue(), listConstraint.getSupportsUnder()); + } + } + + /** Builder for {@code ConstraintInfo}. */ + static class Builder { + private BooleanConstraint booleanConstraint; + private String constraintDefault; + private String description; + private String displayName; + private Constraints constraints; + private String name; + private Integer version; + + Builder(String name) { + this.name = name; + } + + Builder(ConstraintInfo info) { + this.booleanConstraint = info.booleanConstraint; + this.constraintDefault = info.constraintDefault; + this.description = info.description; + this.displayName = info.displayName; + this.constraints = info.constraints; + this.name = info.name; + this.version = info.version; + } + + Builder setBooleanConstraint(BooleanConstraint booleanConstraint) { + this.booleanConstraint = booleanConstraint; + return this; + } + + Builder setConstraintDefault(String constraintDefault) { + this.constraintDefault = constraintDefault; + return this; + } + + Builder setDescription(String description) { + this.description = description; + return this; + } + + Builder setDisplayName(String displayName) { + this.displayName = displayName; + return this; + } + + Builder setConstraints(Constraints constraints) { + this.constraints = constraints; + return this; + } + + Builder setName(String name) { + this.name = name; + return this; + } + + Builder setVersion(Integer version) { + this.version = version; + return this; + } + + ConstraintInfo build() { + return new ConstraintInfo(this); + } + } + + ConstraintInfo(Builder builder) { + this.booleanConstraint = builder.booleanConstraint; + this.constraintDefault = builder.constraintDefault; + this.description = builder.description; + this.displayName = builder.displayName; + this.constraints = builder.constraints; + this.name = builder.name; + this.version = builder.version; + } + + /** Returns the boolean constraint to check whether the constraint is enforced or not. */ + public BooleanConstraint getBooleanConstraint() { + return booleanConstraint; + } + + /** Returns the default behavior of the constraint. */ + public String getConstraintDefault() { + return constraintDefault; + } + + /** Returns the detailed description of the constraint. */ + public String getDescription() { + return description; + } + + /** Returns the human readable name of the constraint. */ + public String getDisplayName() { + return displayName; + } + + /** Returns the listConstraintInfo. */ + public Constraints getConstraints() { + return constraints; + } + + /** Returns the globally unique name of the constraint. */ + public String getName() { + return name; + } + + /** Returns the version of the Constraint. Default version is 0. */ + public Integer getVersion() { + return version; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConstraintInfo that = (ConstraintInfo) o; + return Objects.equals(booleanConstraint, that.booleanConstraint) + && Objects.equals(constraintDefault, that.constraintDefault) + && Objects.equals(description, that.description) + && Objects.equals(displayName, that.displayName) + && Objects.equals(constraints, that.constraints) + && Objects.equals(name, that.name) + && Objects.equals(version, that.version); + } + + @Override + public int hashCode() { + return Objects.hash( + booleanConstraint, constraintDefault, description, displayName, constraints, name, version); + } + + /** Returns a builder for the {@link ConstraintInfo} object. */ + public static Builder newBuilder(String name) { + return new Builder(name); + } + + /** Returns a builder for the {@link ConstraintInfo} object. */ + public Builder toBuilder() { + return new Builder(this); + } + + Constraint toProtobuf() { + Constraint constraintProto = new Constraint(); + constraintProto.setBooleanConstraint(booleanConstraint); + constraintProto.setConstraintDefault(constraintDefault); + constraintProto.setDescription(description); + constraintProto.setDisplayName(displayName); + if (constraints != null) { + constraintProto.setListConstraint(constraints.toProtobuf()); + } + constraintProto.setName(name); + constraintProto.setVersion(version); + return constraintProto; + } + + static ConstraintInfo fromProtobuf(Constraint constraintProtobuf) { + Builder builder = newBuilder(constraintProtobuf.getName()); + builder.setBooleanConstraint(constraintProtobuf.getBooleanConstraint()); + builder.setConstraintDefault(constraintProtobuf.getConstraintDefault()); + builder.setDescription(constraintProtobuf.getDescription()); + builder.setDisplayName(constraintProtobuf.getDisplayName()); + if (constraintProtobuf.getListConstraint() != null) { + builder.setConstraints(Constraints.fromProtobuf(constraintProtobuf.getListConstraint())); + } + if (constraintProtobuf.getName() != null && !constraintProtobuf.getName().equals("Unnamed")) { + builder.setName(constraintProtobuf.getName()); + } + builder.setVersion(constraintProtobuf.getVersion()); + return builder.build(); + } +} diff --git a/src/main/java/com/google/cloud/resourcemanager/OrgPolicyInfo.java b/src/main/java/com/google/cloud/resourcemanager/OrgPolicyInfo.java new file mode 100644 index 00000000..55dc2001 --- /dev/null +++ b/src/main/java/com/google/cloud/resourcemanager/OrgPolicyInfo.java @@ -0,0 +1,388 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.resourcemanager; + +import com.google.api.services.cloudresourcemanager.model.BooleanPolicy; +import com.google.api.services.cloudresourcemanager.model.ListPolicy; +import com.google.api.services.cloudresourcemanager.model.OrgPolicy; +import com.google.api.services.cloudresourcemanager.model.RestoreDefault; +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; +import java.util.List; +import java.util.Objects; + +/** + * A Google Cloud Resource Manager organization policy metadata object. + * + *

Defines a Cloud Organization Policy which specifies constraints for configurations of Cloud + * Platform resources. + */ +public class OrgPolicyInfo { + + static final Function FROM_PROTOBUF_FUNCTION = + new Function() { + @Override + public OrgPolicyInfo apply(OrgPolicy protobuf) { + return OrgPolicyInfo.fromProtobuf(protobuf); + } + }; + static final Function TO_PROTOBUF_FUNCTION = + new Function() { + @Override + public OrgPolicy apply(OrgPolicyInfo orgPolicyInfo) { + return orgPolicyInfo.toProtobuf(); + } + }; + + private BoolPolicy boolPolicy; + private String constraint; + private String etag; + private Policies policies; + private RestoreDefault restoreDefault; + private String updateTime; + private Integer version; + + /** Used For boolean Constraints, whether to enforce the Constraint or not. */ + static class BoolPolicy { + + private final Boolean enforce; + + BoolPolicy(Boolean enforce) { + this.enforce = enforce; + } + + public boolean getEnforce() { + return enforce; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("enforce", getEnforce()).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + BoolPolicy that = (BoolPolicy) o; + return Objects.equals(enforce, that.enforce); + } + + @Override + public int hashCode() { + return Objects.hash(enforce); + } + + BooleanPolicy toProtobuf() { + return new BooleanPolicy().setEnforced(enforce); + } + + static BoolPolicy fromProtobuf(BooleanPolicy booleanPolicy) { + return new BoolPolicy(booleanPolicy.getEnforced()); + } + } + + /** + * The organization ListPolicy object. + * + *

ListPolicy can define specific values and subtrees of Cloud Resource Manager resource + * hierarchy (Organizations, Folders, Projects) that are allowed or denied by setting the + * allowedValues and deniedValues fields. This is achieved by using the under: and optional is: + * prefixes. The under: prefix denotes resource subtree values. The is: prefix is used to denote + * specific values, and is required only if the value contains a ":". Values prefixed with "is:" + * are treated the same as values with no prefix. Ancestry subtrees must be in one of the + * following formats: - "projects/", e.g. "projects/tokyo-rain-123" - "folders/", e.g. + * "folders/1234" - "organizations/", e.g. "organizations/1234" The supportsUnder field of the + * associated Constraint defines whether ancestry prefixes can be used. You can set allowedValues + * and deniedValues in the same Policy if allValues is ALL_VALUES_UNSPECIFIED. ALLOW or DENY are + * used to allow or deny all values. If allValues is set to either ALLOW or DENY, allowedValues + * and deniedValues must be unset. + */ + static class Policies { + + private final String allValues; + private final List allowedValues; + private final List deniedValues; + private final Boolean inheritFromParent; + private final String suggestedValue; + + Policies( + String allValues, + List allowedValues, + List deniedValues, + Boolean inheritFromParent, + String suggestedValue) { + this.allValues = allValues; + this.allowedValues = allowedValues; + this.deniedValues = deniedValues; + this.inheritFromParent = inheritFromParent; + this.suggestedValue = suggestedValue; + } + + /** Returns all the Values state of this policy. */ + String getAllValues() { + return allValues; + } + + /** Returns the list of allowed values of this resource */ + List getAllowedValues() { + return allowedValues; + } + + /** Returns the list of denied values of this resource. */ + List getDeniedValues() { + return deniedValues; + } + + /** Returns the inheritance behavior for this Policy */ + Boolean getInheritFromParent() { + return inheritFromParent; + } + + /** Returns the suggested value of this policy. */ + String getSuggestedValue() { + return suggestedValue; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("allValues", getAllValues()) + .add("allowedValues", getAllowedValues()) + .add("deniedValues", getDeniedValues()) + .add("inheritFromParent", getInheritFromParent()) + .add("suggestedValue", getSuggestedValue()) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Policies policies = (Policies) o; + return Objects.equals(allValues, policies.allValues) + && Objects.equals(allowedValues, policies.allowedValues) + && Objects.equals(deniedValues, policies.deniedValues) + && Objects.equals(inheritFromParent, policies.inheritFromParent) + && Objects.equals(suggestedValue, policies.suggestedValue); + } + + @Override + public int hashCode() { + return Objects.hash( + allValues, allowedValues, deniedValues, inheritFromParent, suggestedValue); + } + + ListPolicy toProtobuf() { + return new ListPolicy() + .setAllValues(allValues) + .setAllowedValues(allowedValues) + .setDeniedValues(deniedValues) + .setInheritFromParent(inheritFromParent) + .setSuggestedValue(suggestedValue); + } + + static Policies fromProtobuf(ListPolicy listPolicy) { + return new Policies( + listPolicy.getAllValues(), + listPolicy.getAllowedValues(), + listPolicy.getDeniedValues(), + listPolicy.getInheritFromParent(), + listPolicy.getSuggestedValue()); + } + } + + /** Builder for {@code OrganizationPolicyInfo}. */ + static class Builder { + private BoolPolicy boolPolicy; + private String constraint; + private String etag; + private Policies policies; + private RestoreDefault restoreDefault; + private String updateTime; + private Integer version; + + Builder() {} + + Builder(OrgPolicyInfo info) { + this.boolPolicy = info.boolPolicy; + this.constraint = info.constraint; + this.etag = info.etag; + this.policies = info.policies; + this.restoreDefault = info.restoreDefault; + this.updateTime = info.updateTime; + this.version = info.version; + } + + Builder setBoolPolicy(BoolPolicy boolPolicy) { + this.boolPolicy = boolPolicy; + return this; + } + + Builder setConstraint(String constraint) { + this.constraint = constraint; + return this; + } + + Builder setEtag(String etag) { + this.etag = etag; + return this; + } + + Builder setListPolicy(Policies policies) { + this.policies = policies; + return this; + } + + Builder setRestoreDefault(RestoreDefault restoreDefault) { + this.restoreDefault = restoreDefault; + return this; + } + + Builder setUpdateTime(String updateTime) { + this.updateTime = updateTime; + return this; + } + + Builder setVersion(Integer version) { + this.version = version; + return this; + } + + OrgPolicyInfo build() { + return new OrgPolicyInfo(this); + } + } + + OrgPolicyInfo(Builder builder) { + this.boolPolicy = builder.boolPolicy; + this.constraint = builder.constraint; + this.etag = builder.etag; + this.policies = builder.policies; + this.restoreDefault = builder.restoreDefault; + this.updateTime = builder.updateTime; + this.version = builder.version; + } + + /** Returns the boolean constraint to check whether the constraint is enforced or not. */ + public BoolPolicy getBoolPolicy() { + return boolPolicy; + } + + /** Returns the name of the Constraint. */ + public String getConstraint() { + return constraint; + } + + /** Returns the etag value of policy. */ + public String getEtag() { + return etag; + } + + /** Return the policies. */ + public Policies getPolicies() { + return policies; + } + + /** Restores the default behavior of the constraint. */ + public RestoreDefault getRestoreDefault() { + return restoreDefault; + } + + /** Returns the updated timestamp of policy. */ + public String getUpdateTime() { + return updateTime; + } + + /** Returns the version of the Policy, Default version is 0. */ + public Integer getVersion() { + return version; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + OrgPolicyInfo policyInfo = (OrgPolicyInfo) o; + return Objects.equals(boolPolicy, policyInfo.boolPolicy) + && Objects.equals(constraint, policyInfo.constraint) + && Objects.equals(etag, policyInfo.etag) + && Objects.equals(policies, policyInfo.policies) + && Objects.equals(restoreDefault, policyInfo.restoreDefault) + && Objects.equals(updateTime, policyInfo.updateTime) + && Objects.equals(version, policyInfo.version); + } + + @Override + public int hashCode() { + return Objects.hash( + boolPolicy, constraint, etag, policies, restoreDefault, updateTime, version); + } + + /** Returns a builder for the {@link OrgPolicyInfo} object. */ + public static Builder newBuilder() { + return new Builder(); + } + + /** Returns a builder for the {@link OrgPolicyInfo} object. */ + public Builder toBuilder() { + return new Builder(this); + } + + OrgPolicy toProtobuf() { + OrgPolicy orgPolicyProto = new OrgPolicy(); + if (boolPolicy != null) { + orgPolicyProto.setBooleanPolicy(boolPolicy.toProtobuf()); + } + orgPolicyProto.setConstraint(constraint); + if (policies != null) { + orgPolicyProto.setListPolicy(policies.toProtobuf()); + } + orgPolicyProto.setRestoreDefault(restoreDefault); + orgPolicyProto.setEtag(etag); + orgPolicyProto.setUpdateTime(updateTime); + orgPolicyProto.setVersion(version); + return orgPolicyProto; + } + + static OrgPolicyInfo fromProtobuf(OrgPolicy orgPolicyProtobuf) { + Builder builder = newBuilder(); + if (orgPolicyProtobuf.getBooleanPolicy() != null) { + builder.setBoolPolicy(BoolPolicy.fromProtobuf(orgPolicyProtobuf.getBooleanPolicy())); + } + builder.setConstraint(orgPolicyProtobuf.getConstraint()); + if (orgPolicyProtobuf.getListPolicy() != null) { + builder.setListPolicy(Policies.fromProtobuf(orgPolicyProtobuf.getListPolicy())); + } + builder.setRestoreDefault(orgPolicyProtobuf.getRestoreDefault()); + builder.setEtag(orgPolicyProtobuf.getEtag()); + builder.setUpdateTime(orgPolicyProtobuf.getUpdateTime()); + builder.setVersion(orgPolicyProtobuf.getVersion()); + return builder.build(); + } +} diff --git a/src/main/java/com/google/cloud/resourcemanager/ResourceManager.java b/src/main/java/com/google/cloud/resourcemanager/ResourceManager.java index b2a46edf..873db051 100644 --- a/src/main/java/com/google/cloud/resourcemanager/ResourceManager.java +++ b/src/main/java/com/google/cloud/resourcemanager/ResourceManager.java @@ -339,6 +339,33 @@ public static ProjectListOption fields(ProjectField... fields) { */ List testPermissions(String projectId, List permissions); + /** Class for specifying project list options. */ + class ListOption extends Option { + + private ListOption(ResourceManagerRpc.Option option, Object value) { + super(option, value); + } + + /** + * Returns an option to specify a page token. + * + *

The page token (returned from a previous call to list) indicates from where listing should + * continue. + */ + public static ListOption pageToken(String pageToken) { + return new ListOption(ResourceManagerRpc.Option.PAGE_TOKEN, pageToken); + } + + /** + * The maximum number of records to return per RPC. + * + *

The server can return fewer records 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. + */ + public static ListOption pageSize(int pageSize) { + return new ListOption(ResourceManagerRpc.Option.PAGE_SIZE, pageSize); + } + } /** * Returns the permissions and their results representing whether the caller has the permissions * on the specified Organization. @@ -354,4 +381,75 @@ public static ProjectListOption fields(ProjectField... fields) { * Resource Manager testIamPermissions */ Map testOrgPermissions(String resource, List permissions); + + /** + * Clears a Policy from a resource. + * + * @throws ResourceManagerException upon failure + * @see Resource + * Manager clearOrgPolicy + */ + void clearOrgPolicy(String resource, OrgPolicyInfo orgPolicy); + + /** + * Gets the effective Policy on a resource. + * + *

This is the result of merging Policies in the resource hierarchy. The returned Policy will + * not have an etag set because it is a computed Policy across multiple resources. Subtrees of + * Resource Manager resource hierarchy with 'under:' prefix are not expanded. + * + * @throws ResourceManagerException upon failure + * @see Resource + * Manager getEffectiveOrgPolicy + */ + OrgPolicyInfo getEffectiveOrgPolicy(String resource, String constraint); + + /** + * Gets the Policy on a resource. + * + *

If no Policy is set on the resource, a Policy is returned with default values including + * POLICY_TYPE_NOT_SET for the policy_type one of. The etag value can be used with + * projects.setOrgPolicy() to create or update a Policy during read-modify-write. + * + * @throws ResourceManagerException upon failure + * @see Resource + * Manager getOrgPolicy + */ + OrgPolicyInfo getOrgPolicy(String resource, String constraint); + + /** + * Lists the Constraints that could be applied on the specified resource. + * + * @throws ResourceManagerException upon failure + * @see Resource + * Manager listAvailableOrgPolicyConstraints + */ + Page listAvailableOrgPolicyConstraints(String resource, ListOption... options); + + /** + * Lists the Policies set for a particular resource. + * + * @throws ResourceManagerException upon failure + * @see Resource + * Manager listOrgPolicies + */ + Page listOrgPolicies(String resource, ListOption... options); + + /** + * Updates the specified Policy on the resource. Creates a new Policy for that Constraint on the + * resource if one does not exist. + * + *

Not supplying an etag on the request Policy results in an unconditional write of the Policy. + * + * @throws ResourceManagerException upon failure + * @see Resource + * Manager setOrgPolicy + */ + OrgPolicyInfo replaceOrgPolicy(String resource, OrgPolicyInfo orgPolicy); } diff --git a/src/main/java/com/google/cloud/resourcemanager/ResourceManagerImpl.java b/src/main/java/com/google/cloud/resourcemanager/ResourceManagerImpl.java index 557567d9..f26d0e9b 100644 --- a/src/main/java/com/google/cloud/resourcemanager/ResourceManagerImpl.java +++ b/src/main/java/com/google/cloud/resourcemanager/ResourceManagerImpl.java @@ -20,6 +20,8 @@ import static com.google.common.base.Preconditions.checkArgument; import com.google.api.gax.paging.Page; +import com.google.api.services.cloudresourcemanager.model.Constraint; +import com.google.api.services.cloudresourcemanager.model.OrgPolicy; import com.google.cloud.BaseService; import com.google.cloud.PageImpl; import com.google.cloud.PageImpl.NextPageFetcher; @@ -27,6 +29,7 @@ import com.google.cloud.RetryHelper.RetryHelperException; import com.google.cloud.Tuple; import com.google.cloud.resourcemanager.spi.v1beta1.ResourceManagerRpc; +import com.google.cloud.resourcemanager.spi.v1beta1.ResourceManagerRpc.ListResult; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -293,6 +296,204 @@ public Map call() throws IOException { } } + @Override + public void clearOrgPolicy(final String resource, final OrgPolicyInfo orgPolicy) { + try { + runWithRetries( + new Callable() { + @Override + public Void call() throws IOException { + resourceManagerRpc.clearOrgPolicy(resource, orgPolicy.toProtobuf()); + return null; + } + }, + getOptions().getRetrySettings(), + EXCEPTION_HANDLER, + getOptions().getClock()); + } catch (RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + @Override + public OrgPolicyInfo getEffectiveOrgPolicy(final String resource, final String constraint) { + try { + return OrgPolicyInfo.fromProtobuf( + runWithRetries( + new Callable() { + @Override + public OrgPolicy call() throws IOException { + return resourceManagerRpc.getEffectiveOrgPolicy(resource, constraint); + } + }, + getOptions().getRetrySettings(), + EXCEPTION_HANDLER, + getOptions().getClock())); + } catch (RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + @Override + public OrgPolicyInfo getOrgPolicy(final String resource, final String constraint) { + try { + return OrgPolicyInfo.fromProtobuf( + runWithRetries( + new Callable() { + @Override + public OrgPolicy call() throws IOException { + return resourceManagerRpc.getOrgPolicy(resource, constraint); + } + }, + getOptions().getRetrySettings(), + EXCEPTION_HANDLER, + getOptions().getClock())); + } catch (RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + private static class ConstraintPageFetcher implements NextPageFetcher { + + private static final long serialVersionUID = 2158209410430566961L; + private final String resource; + private final Map requestOptions; + private final ResourceManagerOptions serviceOptions; + + ConstraintPageFetcher( + String resource, + ResourceManagerOptions serviceOptions, + String cursor, + Map optionMap) { + this.resource = resource; + this.requestOptions = + PageImpl.nextRequestOptions(ResourceManagerRpc.Option.PAGE_TOKEN, cursor, optionMap); + this.serviceOptions = serviceOptions; + } + + @Override + public Page getNextPage() { + return listAvailableOrgPolicyConstraints(resource, serviceOptions, requestOptions); + } + } + + @Override + public Page listAvailableOrgPolicyConstraints( + String resource, ListOption... options) { + return listAvailableOrgPolicyConstraints(resource, getOptions(), optionMap(options)); + } + + private static Page listAvailableOrgPolicyConstraints( + final String resource, + final ResourceManagerOptions serviceOptions, + final Map optionsMap) { + try { + final ResourceManagerRpc rpc = serviceOptions.getResourceManagerRpcV1Beta1(); + ListResult constraintList = + runWithRetries( + new Callable>() { + @Override + public ListResult call() throws IOException { + return rpc.listAvailableOrgPolicyConstraints(resource, optionsMap); + } + }, + serviceOptions.getRetrySettings(), + EXCEPTION_HANDLER, + serviceOptions.getClock()); + String cursor = constraintList.pageToken(); + Iterable constraints = + constraintList.results() == null + ? ImmutableList.of() + : Iterables.transform( + constraintList.results(), ConstraintInfo.FROM_PROTOBUF_FUNCTION); + return new PageImpl<>( + new ConstraintPageFetcher(resource, serviceOptions, cursor, optionsMap), + cursor, + constraints); + } catch (RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + private static class OrgPolicyPageFetcher implements NextPageFetcher { + + private static final long serialVersionUID = 2158209410430566961L; + private final String resource; + private final Map requestOptions; + private final ResourceManagerOptions serviceOptions; + + OrgPolicyPageFetcher( + String resource, + ResourceManagerOptions serviceOptions, + String cursor, + Map optionMap) { + this.resource = resource; + this.requestOptions = + PageImpl.nextRequestOptions(ResourceManagerRpc.Option.PAGE_TOKEN, cursor, optionMap); + this.serviceOptions = serviceOptions; + } + + @Override + public Page getNextPage() { + return listOrgPolicies(resource, serviceOptions, requestOptions); + } + } + + @Override + public Page listOrgPolicies(final String resource, ListOption... options) { + return listOrgPolicies(resource, getOptions(), optionMap(options)); + } + + private static PageImpl listOrgPolicies( + final String resource, + final ResourceManagerOptions serviceOptions, + final Map optionsMap) { + try { + final ResourceManagerRpc rpc = serviceOptions.getResourceManagerRpcV1Beta1(); + ListResult orgPolicy = + runWithRetries( + new Callable>() { + @Override + public ListResult call() throws IOException { + return rpc.listOrgPolicies(resource, optionsMap); + } + }, + serviceOptions.getRetrySettings(), + EXCEPTION_HANDLER, + serviceOptions.getClock()); + String cursor = orgPolicy.pageToken(); + Iterable orgPolicies = + orgPolicy.results() == null + ? ImmutableList.of() + : Iterables.transform(orgPolicy.results(), OrgPolicyInfo.FROM_PROTOBUF_FUNCTION); + return new PageImpl<>( + new OrgPolicyPageFetcher(resource, serviceOptions, cursor, optionsMap), + cursor, + orgPolicies); + } catch (RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + @Override + public OrgPolicyInfo replaceOrgPolicy(final String resource, final OrgPolicyInfo orgPolicy) { + try { + return OrgPolicyInfo.fromProtobuf( + runWithRetries( + new Callable() { + @Override + public OrgPolicy call() throws IOException { + return resourceManagerRpc.replaceOrgPolicy(resource, orgPolicy.toProtobuf()); + } + }, + getOptions().getRetrySettings(), + EXCEPTION_HANDLER, + getOptions().getClock())); + } catch (RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + private Map optionMap(Option... options) { Map temp = Maps.newEnumMap(ResourceManagerRpc.Option.class); for (Option option : options) { diff --git a/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/HttpResourceManagerRpc.java b/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/HttpResourceManagerRpc.java index 12e53a91..1995fcfb 100644 --- a/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/HttpResourceManagerRpc.java +++ b/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/HttpResourceManagerRpc.java @@ -30,12 +30,22 @@ import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.retrying.TimedAttemptSettings; import com.google.api.services.cloudresourcemanager.CloudResourceManager; +import com.google.api.services.cloudresourcemanager.model.ClearOrgPolicyRequest; +import com.google.api.services.cloudresourcemanager.model.Constraint; +import com.google.api.services.cloudresourcemanager.model.GetEffectiveOrgPolicyRequest; import com.google.api.services.cloudresourcemanager.model.GetIamPolicyRequest; +import com.google.api.services.cloudresourcemanager.model.GetOrgPolicyRequest; +import com.google.api.services.cloudresourcemanager.model.ListAvailableOrgPolicyConstraintsRequest; +import com.google.api.services.cloudresourcemanager.model.ListAvailableOrgPolicyConstraintsResponse; +import com.google.api.services.cloudresourcemanager.model.ListOrgPoliciesRequest; +import com.google.api.services.cloudresourcemanager.model.ListOrgPoliciesResponse; import com.google.api.services.cloudresourcemanager.model.ListProjectsResponse; import com.google.api.services.cloudresourcemanager.model.Operation; +import com.google.api.services.cloudresourcemanager.model.OrgPolicy; import com.google.api.services.cloudresourcemanager.model.Policy; import com.google.api.services.cloudresourcemanager.model.Project; import com.google.api.services.cloudresourcemanager.model.SetIamPolicyRequest; +import com.google.api.services.cloudresourcemanager.model.SetOrgPolicyRequest; import com.google.api.services.cloudresourcemanager.model.Status; import com.google.api.services.cloudresourcemanager.model.TestIamPermissionsRequest; import com.google.api.services.cloudresourcemanager.model.TestIamPermissionsResponse; @@ -324,4 +334,95 @@ resource, new TestIamPermissionsRequest().setPermissions(permissions)) throw ResourceManagerException.translateAndThrow(ex); } } + + @Override + public void clearOrgPolicy(String resource, OrgPolicy orgPolicy) throws IOException { + try { + resourceManager + .folders() + .clearOrgPolicy( + resource, + new ClearOrgPolicyRequest() + .setConstraint(orgPolicy.getConstraint()) + .setEtag(orgPolicy.getEtag())) + .execute(); + } catch (RetryHelper.RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + @Override + public OrgPolicy getEffectiveOrgPolicy(String resource, String constraint) throws IOException { + try { + return resourceManager + .folders() + .getEffectiveOrgPolicy( + resource, new GetEffectiveOrgPolicyRequest().setConstraint(constraint)) + .execute(); + } catch (RetryHelper.RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + @Override + public OrgPolicy getOrgPolicy(String resource, String constraint) throws IOException { + try { + return resourceManager + .folders() + .getOrgPolicy(resource, new GetOrgPolicyRequest().setConstraint(constraint)) + .execute(); + } catch (RetryHelper.RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + @Override + public ListResult listAvailableOrgPolicyConstraints( + String resource, Map options) throws IOException { + try { + ListAvailableOrgPolicyConstraintsResponse response = + resourceManager + .folders() + .listAvailableOrgPolicyConstraints( + resource, + new ListAvailableOrgPolicyConstraintsRequest() + .setPageSize(Option.PAGE_SIZE.getInt(options)) + .setPageToken(Option.PAGE_TOKEN.getString(options))) + .execute(); + return ListResult.of(response.getNextPageToken(), response.getConstraints()); + } catch (RetryHelper.RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + @Override + public ListResult listOrgPolicies(String resource, Map options) + throws IOException { + try { + ListOrgPoliciesResponse response = + resourceManager + .folders() + .listOrgPolicies( + resource, + new ListOrgPoliciesRequest() + .setPageSize(Option.PAGE_SIZE.getInt(options)) + .setPageToken(Option.PAGE_TOKEN.getString(options))) + .execute(); + return ListResult.of(response.getNextPageToken(), response.getPolicies()); + } catch (RetryHelper.RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } + + @Override + public OrgPolicy replaceOrgPolicy(String resource, OrgPolicy orgPolicy) throws IOException { + try { + return resourceManager + .folders() + .setOrgPolicy(resource, new SetOrgPolicyRequest().setPolicy(orgPolicy)) + .execute(); + } catch (RetryHelper.RetryHelperException ex) { + throw ResourceManagerException.translateAndThrow(ex); + } + } } diff --git a/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc.java b/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc.java index dc45f31d..ee091999 100644 --- a/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc.java +++ b/src/main/java/com/google/cloud/resourcemanager/spi/v1beta1/ResourceManagerRpc.java @@ -16,11 +16,14 @@ package com.google.cloud.resourcemanager.spi.v1beta1; +import com.google.api.services.cloudresourcemanager.model.Constraint; +import com.google.api.services.cloudresourcemanager.model.OrgPolicy; import com.google.api.services.cloudresourcemanager.model.Policy; import com.google.api.services.cloudresourcemanager.model.Project; import com.google.cloud.ServiceRpc; import com.google.cloud.Tuple; import com.google.cloud.resourcemanager.ResourceManagerException; +import com.google.common.collect.ImmutableList; import java.io.IOException; import java.util.List; import java.util.Map; @@ -57,6 +60,28 @@ Integer getInt(Map options) { } } + class ListResult { + + private final Iterable results; + private final String pageToken; + + ListResult(String pageToken, Iterable results) { + this.results = ImmutableList.copyOf(results); + this.pageToken = pageToken; + } + + public static ListResult of(String pageToken, Iterable list) { + return new ListResult<>(pageToken, list); + } + + public Iterable results() { + return results; + } + + public String pageToken() { + return pageToken; + } + } /** * Creates a new project. * @@ -133,4 +158,56 @@ Integer getInt(Map options) { */ Map testOrgPermissions(String resource, List permissions) throws IOException; + + // TODO(ajaykannan): implement "Organization" functionality when available (issue #319) + + /** Clears the Policy from a resource. */ + void clearOrgPolicy(String resource, OrgPolicy orgPolicy) throws IOException; + + /** + * Gets the effective Policy on a resource. + * + *

This is the result of merging Policies in the resource hierarchy. The returned Policy does + * not have an etag set because it is a computed Policy across multiple resources. Subtrees of + * Resource Manager resource hierarchy with 'under:' prefix will not be expanded. + * + * @throws ResourceManagerException upon failure + */ + OrgPolicy getEffectiveOrgPolicy(String resource, String constraint) throws IOException; + + /** + * Gets the Policy on a resource. + * + *

If no Policy is set on the resource, a Policy is returned with default values including + * POLICY_TYPE_NOT_SET for the policy_type oneof. The etag value can be used with + * projects.setOrgPolicy() to create or update a Policy during read-modify-write. + * + * @throws ResourceManagerException upon failure + */ + OrgPolicy getOrgPolicy(String resource, String constraint) throws IOException; + + /** + * Lists all the Constraints that can be applied on the specified resource. + * + * @throws ResourceManagerException upon failure + */ + ListResult listAvailableOrgPolicyConstraints(String resource, Map options) + throws IOException; + + /** + * Lists all the Policies set for a particular resource. + * + * @throws ResourceManagerException upon failure + */ + ListResult listOrgPolicies(String resource, Map options) throws IOException; + + /** + * Updates the specified Policy on the resource. Creates a new Policy for that Constraint on the + * resource if one does not exist. + * + *

Not supplying an etag on the request Policy results in an unconditional write of the Policy. + * + * @throws ResourceManagerException upon failure + */ + OrgPolicy replaceOrgPolicy(String resource, OrgPolicy orgPolicy) throws IOException; } diff --git a/src/test/java/com/google/cloud/resourcemanager/ConstraintInfoTest.java b/src/test/java/com/google/cloud/resourcemanager/ConstraintInfoTest.java new file mode 100644 index 00000000..a8c870cc --- /dev/null +++ b/src/test/java/com/google/cloud/resourcemanager/ConstraintInfoTest.java @@ -0,0 +1,119 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.resourcemanager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.api.services.cloudresourcemanager.model.BooleanConstraint; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ConstraintInfoTest { + + private static final String NAME = "constraints/serviceuser.services"; + private static final String CONSTRAINT_DEFAULT = "ALLOW"; + private static final String DISPLAY_NAME = "constraints-display-name"; + private static final String DESCRIPTION = + "Detailed description of what this Constraint controls as well as how and where it is enforced"; + private static final Integer VERSION = 1; + private static final ConstraintInfo.Constraints LIST_CONSTRAINT = + new ConstraintInfo.Constraints("suggested-value", true); + + private ConstraintInfo constraintInfo; + private BooleanConstraint booleanConstraint; + + @Before + public void setUp() { + booleanConstraint = new BooleanConstraint(); + booleanConstraint.set("boolean", Boolean.class); + constraintInfo = + ConstraintInfo.newBuilder(NAME) + .setConstraintDefault(CONSTRAINT_DEFAULT) + .setDisplayName(DISPLAY_NAME) + .setDescription(DESCRIPTION) + .setConstraints(LIST_CONSTRAINT) + .setBooleanConstraint(booleanConstraint) + .setVersion(VERSION) + .build(); + } + + @Test + public void testBuilder() { + assertEquals(NAME, constraintInfo.getName()); + assertEquals(CONSTRAINT_DEFAULT, constraintInfo.getConstraintDefault()); + assertEquals(DISPLAY_NAME, constraintInfo.getDisplayName()); + assertEquals(DESCRIPTION, constraintInfo.getDescription()); + assertEquals(LIST_CONSTRAINT, constraintInfo.getConstraints()); + assertEquals(booleanConstraint, constraintInfo.getBooleanConstraint()); + assertEquals(VERSION, constraintInfo.getVersion()); + } + + @Test + public void testToBuilder() { + compareConstraints(constraintInfo, constraintInfo.toBuilder().build()); + } + + @Test + public void testToAndFromProtobuf() { + compareConstraints(constraintInfo, ConstraintInfo.fromProtobuf(constraintInfo.toProtobuf())); + assertNotNull(ConstraintInfo.TO_PROTOBUF_FUNCTION.apply(constraintInfo)); + assertNotNull( + ConstraintInfo.FROM_PROTOBUF_FUNCTION.apply( + ConstraintInfo.TO_PROTOBUF_FUNCTION.apply(constraintInfo))); + } + + @Test + public void testEquals() { + compareConstraints( + constraintInfo, + ConstraintInfo.newBuilder(NAME) + .setConstraintDefault(CONSTRAINT_DEFAULT) + .setDisplayName(DISPLAY_NAME) + .setDescription(DESCRIPTION) + .setConstraints(LIST_CONSTRAINT) + .setBooleanConstraint(booleanConstraint) + .setVersion(VERSION) + .build()); + compareConstraints(constraintInfo, new ConstraintInfo.Builder(constraintInfo).build()); + } + + @Test + public void testToString() { + assertTrue( + LIST_CONSTRAINT + .toString() + .contains("suggestedValue=" + LIST_CONSTRAINT.getSuggestedValue())); + assertTrue( + LIST_CONSTRAINT.toString().contains("supportsUnder=" + LIST_CONSTRAINT.getSupportsUnder())); + } + + private void compareConstraints(ConstraintInfo expected, ConstraintInfo value) { + assertEquals(expected, value); + assertEquals(expected.hashCode(), value.hashCode()); + assertEquals(expected.toString(), value.toString()); + assertEquals(expected.getName(), value.getName()); + assertEquals(expected.getConstraintDefault(), value.getConstraintDefault()); + assertEquals(expected.getDisplayName(), value.getDisplayName()); + assertEquals(expected.getDescription(), value.getDescription()); + assertEquals(expected.getConstraints(), value.getConstraints()); + assertEquals(expected.getVersion(), value.getVersion()); + } +} diff --git a/src/test/java/com/google/cloud/resourcemanager/OrgPolicyInfoTest.java b/src/test/java/com/google/cloud/resourcemanager/OrgPolicyInfoTest.java new file mode 100644 index 00000000..b021ed56 --- /dev/null +++ b/src/test/java/com/google/cloud/resourcemanager/OrgPolicyInfoTest.java @@ -0,0 +1,137 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.resourcemanager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.api.services.cloudresourcemanager.model.RestoreDefault; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class OrgPolicyInfoTest { + + private static final String CONSTRAINTS_NAME = "constraints/serviceuser.services"; + private static final String ETAG = "abcd12"; + private static final String UPDATE_TIME = "014-10-02T15:01:23.045123456Z"; + private static final Integer VERSION = 1; + private static final OrgPolicyInfo.BoolPolicy BOOLEAN_POLICY = new OrgPolicyInfo.BoolPolicy(true); + private static final OrgPolicyInfo.Policies LIST_POLICY = + new OrgPolicyInfo.Policies( + "allvaluse", + Arrays.asList("allowedValue-1", "allowedValue-2"), + Arrays.asList("deniedValue-1", "deniedValue-2"), + true, + "suggestedValue"); + + private RestoreDefault restoreDefault; + private OrgPolicyInfo orgPolicyInfo; + + @Before + public void setUp() { + restoreDefault = new RestoreDefault(); + restoreDefault.set("fields", String.class); + orgPolicyInfo = + OrgPolicyInfo.newBuilder() + .setBoolPolicy(BOOLEAN_POLICY) + .setConstraint(CONSTRAINTS_NAME) + .setListPolicy(LIST_POLICY) + .setRestoreDefault(restoreDefault) + .setEtag(ETAG) + .setUpdateTime(UPDATE_TIME) + .setVersion(VERSION) + .build(); + } + + @Test + public void testBuilder() { + assertEquals(CONSTRAINTS_NAME, orgPolicyInfo.getConstraint()); + assertEquals(BOOLEAN_POLICY, orgPolicyInfo.getBoolPolicy()); + assertEquals(LIST_POLICY, orgPolicyInfo.getPolicies()); + assertEquals(UPDATE_TIME, orgPolicyInfo.getUpdateTime()); + assertEquals(VERSION, orgPolicyInfo.getVersion()); + assertEquals(restoreDefault, orgPolicyInfo.getRestoreDefault()); + } + + @Test + public void testToBuilder() { + compareOrgPolicy(orgPolicyInfo, orgPolicyInfo.toBuilder().build()); + } + + @Test + public void testToAndFromProtobuf() { + assertTrue(orgPolicyInfo.toProtobuf().getUpdateTime().endsWith("Z")); + compareOrgPolicy(orgPolicyInfo, orgPolicyInfo.fromProtobuf(orgPolicyInfo.toProtobuf())); + assertNotNull(OrgPolicyInfo.TO_PROTOBUF_FUNCTION.apply(orgPolicyInfo)); + assertNotNull( + OrgPolicyInfo.FROM_PROTOBUF_FUNCTION.apply( + OrgPolicyInfo.TO_PROTOBUF_FUNCTION.apply(orgPolicyInfo))); + } + + @Test + public void testEquals() { + compareOrgPolicy( + orgPolicyInfo, + OrgPolicyInfo.newBuilder() + .setBoolPolicy(BOOLEAN_POLICY) + .setConstraint(CONSTRAINTS_NAME) + .setListPolicy(LIST_POLICY) + .setRestoreDefault(restoreDefault) + .setEtag(ETAG) + .setUpdateTime(UPDATE_TIME) + .setVersion(VERSION) + .build()); + compareOrgPolicy(orgPolicyInfo, new OrgPolicyInfo.Builder(orgPolicyInfo).build()); + } + + @Test + public void testToString() { + assertTrue(BOOLEAN_POLICY.toString().contains("enforce=" + BOOLEAN_POLICY.getEnforce())); + } + + @Test + public void testListPolicyToAndFromProtobuf() { + compareListPolicies(LIST_POLICY, LIST_POLICY.fromProtobuf(LIST_POLICY.toProtobuf())); + } + + private void compareOrgPolicy(OrgPolicyInfo expected, OrgPolicyInfo value) { + assertEquals(expected, value); + assertEquals(expected.hashCode(), value.hashCode()); + assertEquals(expected.getConstraint(), value.getConstraint()); + assertEquals(expected.getBoolPolicy(), value.getBoolPolicy()); + assertEquals(expected.getEtag(), value.getEtag()); + assertEquals(expected.getBoolPolicy().toString(), value.getBoolPolicy().toString()); + assertEquals(expected.getPolicies(), value.getPolicies()); + assertEquals(expected.getRestoreDefault(), value.getRestoreDefault()); + assertEquals(expected.getUpdateTime(), value.getUpdateTime()); + assertEquals(expected.getVersion(), value.getVersion()); + } + + private void compareListPolicies(OrgPolicyInfo.Policies expected, OrgPolicyInfo.Policies value) { + assertEquals(expected, value); + assertEquals(expected.hashCode(), value.hashCode()); + assertEquals(expected.toString(), value.toString()); + assertEquals(expected.getAllowedValues(), value.getAllowedValues()); + assertEquals(expected.getAllValues(), value.getAllValues()); + assertEquals(expected.getDeniedValues(), value.getDeniedValues()); + assertEquals(expected.getInheritFromParent(), value.getInheritFromParent()); + } +} diff --git a/src/test/java/com/google/cloud/resourcemanager/ResourceManagerImplTest.java b/src/test/java/com/google/cloud/resourcemanager/ResourceManagerImplTest.java index 1fdb954f..7f5545e8 100644 --- a/src/test/java/com/google/cloud/resourcemanager/ResourceManagerImplTest.java +++ b/src/test/java/com/google/cloud/resourcemanager/ResourceManagerImplTest.java @@ -24,28 +24,33 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.google.api.gax.paging.Page; +import com.google.api.services.cloudresourcemanager.model.Constraint; +import com.google.api.services.cloudresourcemanager.model.OrgPolicy; import com.google.cloud.Identity; import com.google.cloud.Policy; import com.google.cloud.Role; +import com.google.cloud.resourcemanager.OrgPolicyInfo.BoolPolicy; import com.google.cloud.resourcemanager.ProjectInfo.ResourceId; import com.google.cloud.resourcemanager.ResourceManager.ProjectField; import com.google.cloud.resourcemanager.ResourceManager.ProjectGetOption; import com.google.cloud.resourcemanager.ResourceManager.ProjectListOption; import com.google.cloud.resourcemanager.spi.ResourceManagerRpcFactory; import com.google.cloud.resourcemanager.spi.v1beta1.ResourceManagerRpc; +import com.google.cloud.resourcemanager.spi.v1beta1.ResourceManagerRpc.ListResult; import com.google.cloud.resourcemanager.testing.LocalResourceManagerHelper; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.io.IOException; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; -import org.easymock.EasyMock; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -82,6 +87,44 @@ public class ResourceManagerImplTest { .addIdentity(Role.owner(), Identity.user("me@gmail.com")) .addIdentity(Role.editor(), Identity.serviceAccount("serviceaccount@gmail.com")) .build(); + private static final String CURSOR = "cursor"; + private static final String RESOURCE = "folders/my-folder"; + private static final String CONSTRAINTS = "constraints/serviceuser.services"; + private static final String ETAG = "abcd12"; + private static final String UPDATE_TIME = "014-10-02T15:01:23.045123456Z"; + private static final String NAME = "constraints/serviceuser.services"; + private static final String CONSTRAINT_DEFAULT = "ALLOW"; + private static final String DISPLAY_NAME = "constraints-display-name"; + private static final String DESCRIPTION = + "Detailed description of what this Constraint controls as well as how and where it is enforced"; + private static final Integer VERSION = 1; + private static final BoolPolicy BOOLEAN_POLICY = new BoolPolicy(true); + private static final OrgPolicyInfo.Policies LIST_POLICY = + new OrgPolicyInfo.Policies( + "allvaluse", + Arrays.asList("allowedValues"), + Arrays.asList("deniedValues"), + true, + "suggestedValue"); + private static final OrgPolicyInfo ORG_POLICY_INFO = + OrgPolicyInfo.newBuilder() + .setBoolPolicy(BOOLEAN_POLICY) + .setConstraint(CONSTRAINTS) + .setListPolicy(LIST_POLICY) + .setEtag(ETAG) + .setUpdateTime(UPDATE_TIME) + .setVersion(VERSION) + .build(); + private static final ConstraintInfo.Constraints LIST_CONSTRAINT = + new ConstraintInfo.Constraints("suggested-value", true); + private static final ConstraintInfo CONSTRAINT_INFO = + ConstraintInfo.newBuilder(NAME) + .setConstraintDefault(CONSTRAINT_DEFAULT) + .setDisplayName(DISPLAY_NAME) + .setDescription(DESCRIPTION) + .setConstraints(LIST_CONSTRAINT) + .setVersion(VERSION) + .build(); private ResourceManagerRpcFactory rpcFactoryMock = Mockito.mock(ResourceManagerRpcFactory.class); private ResourceManagerRpc resourceManagerRpcMock = Mockito.mock(ResourceManagerRpc.class); @@ -398,73 +441,63 @@ public void testTestPermissions() { @Test public void testRetryableException() { - ResourceManagerRpcFactory rpcFactoryMock = EasyMock.createMock(ResourceManagerRpcFactory.class); - ResourceManagerRpc resourceManagerRpcMock = EasyMock.createMock(ResourceManagerRpc.class); - EasyMock.expect(rpcFactoryMock.create(EasyMock.anyObject(ResourceManagerOptions.class))) - .andReturn(resourceManagerRpcMock); - EasyMock.replay(rpcFactoryMock); - ResourceManager resourceManagerMock = + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = ResourceManagerOptions.newBuilder() .setServiceRpcFactory(rpcFactoryMock) .build() .getService(); - EasyMock.expect(resourceManagerRpcMock.get(PARTIAL_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS)) - .andThrow(new ResourceManagerException(500, "Internal Error")) - .andReturn(PARTIAL_PROJECT.toPb()); - EasyMock.replay(resourceManagerRpcMock); - Project returnedProject = resourceManagerMock.get(PARTIAL_PROJECT.getProjectId()); - assertEquals( - new Project(resourceManagerMock, new ProjectInfo.BuilderImpl(PARTIAL_PROJECT)), - returnedProject); + String exceptionMessage = "Internal Error"; + doThrow(new ResourceManagerException(500, exceptionMessage)) + .when(resourceManagerRpcMock) + .get(PARTIAL_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS); + try { + resourceManager.get(PARTIAL_PROJECT.getProjectId()); + } catch (ResourceManagerException expected) { + assertEquals(500, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); + } } @Test public void testNonRetryableException() { - ResourceManagerRpcFactory rpcFactoryMock = EasyMock.createMock(ResourceManagerRpcFactory.class); - ResourceManagerRpc resourceManagerRpcMock = EasyMock.createMock(ResourceManagerRpc.class); - EasyMock.expect(rpcFactoryMock.create(EasyMock.anyObject(ResourceManagerOptions.class))) - .andReturn(resourceManagerRpcMock); - EasyMock.replay(rpcFactoryMock); - ResourceManager resourceManagerMock = + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = ResourceManagerOptions.newBuilder() .setServiceRpcFactory(rpcFactoryMock) .build() .getService(); - EasyMock.expect(resourceManagerRpcMock.get(PARTIAL_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS)) - .andThrow( - new ResourceManagerException( - 403, "Project " + PARTIAL_PROJECT.getProjectId() + " not found.")) - .once(); - EasyMock.replay(resourceManagerRpcMock); + String exceptionMessage = "Project " + PARTIAL_PROJECT.getProjectId() + " not found."; + doThrow(new ResourceManagerException(404, exceptionMessage)) + .when(resourceManagerRpcMock) + .get(PARTIAL_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS); try { - resourceManagerMock.get(PARTIAL_PROJECT.getProjectId()); - fail(); - } catch (ResourceManagerException e) { - assertTrue(e.getMessage().contains("Project partial-project not found")); + resourceManager.get(PARTIAL_PROJECT.getProjectId()); + } catch (ResourceManagerException expected) { + assertEquals(404, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); } } @Test public void testRuntimeException() { - ResourceManagerRpcFactory rpcFactoryMock = EasyMock.createMock(ResourceManagerRpcFactory.class); - ResourceManagerRpc resourceManagerRpcMock = EasyMock.createMock(ResourceManagerRpc.class); - EasyMock.expect(rpcFactoryMock.create(EasyMock.anyObject(ResourceManagerOptions.class))) - .andReturn(resourceManagerRpcMock); - EasyMock.replay(rpcFactoryMock); - ResourceManager resourceManagerMock = + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = ResourceManagerOptions.newBuilder() .setServiceRpcFactory(rpcFactoryMock) .build() .getService(); String exceptionMessage = "Artificial runtime exception"; - EasyMock.expect(resourceManagerRpcMock.get(PARTIAL_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS)) - .andThrow(new RuntimeException(exceptionMessage)); - EasyMock.replay(resourceManagerRpcMock); + doThrow(new RuntimeException(exceptionMessage)) + .when(resourceManagerRpcMock) + .get(PARTIAL_PROJECT.getProjectId(), EMPTY_RPC_OPTIONS); try { - resourceManagerMock.get(PARTIAL_PROJECT.getProjectId()); - fail(); - } catch (ResourceManagerException exception) { - assertEquals(exceptionMessage, exception.getCause().getMessage()); + resourceManager.get(PARTIAL_PROJECT.getProjectId()); + } catch (RuntimeException expected) { + assertTrue(expected.getMessage().contains(exceptionMessage)); } } @@ -517,4 +550,260 @@ public void testTestOrgPermissionsWithResourceManagerException() throws IOExcept assertEquals(exceptionMessage, expected.getMessage()); } } + + @Test + public void testClearOrgPolicy() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + doNothing().when(resourceManagerRpcMock).clearOrgPolicy(RESOURCE, ORG_POLICY_INFO.toProtobuf()); + resourceManager.clearOrgPolicy(RESOURCE, ORG_POLICY_INFO); + verify(resourceManagerRpcMock).clearOrgPolicy(RESOURCE, ORG_POLICY_INFO.toProtobuf()); + } + + @Test + public void testClearOrgPolicyWithResourceManagerException() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + String exceptionMessage = "Should fail because the organization policy doesn't exist."; + doThrow(new ResourceManagerException(404, exceptionMessage)) + .when(resourceManagerRpcMock) + .clearOrgPolicy(RESOURCE, ORG_POLICY_INFO.toProtobuf()); + try { + resourceManager.clearOrgPolicy(RESOURCE, ORG_POLICY_INFO); + } catch (ResourceManagerException expected) { + assertEquals(404, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); + } + } + + @Test + public void testGetEffectiveOrgPolicy() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + when(resourceManagerRpcMock.getEffectiveOrgPolicy(RESOURCE, CONSTRAINTS)) + .thenReturn(ORG_POLICY_INFO.toProtobuf()); + OrgPolicyInfo policyInfo = resourceManager.getEffectiveOrgPolicy(RESOURCE, CONSTRAINTS); + assertEquals(CONSTRAINTS, policyInfo.getConstraint()); + assertEquals(BOOLEAN_POLICY, policyInfo.getBoolPolicy()); + assertEquals(ETAG, policyInfo.getEtag()); + assertEquals(LIST_POLICY, policyInfo.getPolicies()); + assertEquals(UPDATE_TIME, policyInfo.getUpdateTime()); + assertEquals(VERSION, policyInfo.getVersion()); + + verify(resourceManagerRpcMock).getEffectiveOrgPolicy(RESOURCE, CONSTRAINTS); + } + + @Test + public void testGetEffectiveOrgPolicyWithResourceManagerException() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + String exceptionMessage = "Not Found"; + doThrow(new ResourceManagerException(404, exceptionMessage)) + .when(resourceManagerRpcMock) + .getEffectiveOrgPolicy(RESOURCE, CONSTRAINTS); + try { + resourceManager.getEffectiveOrgPolicy(RESOURCE, CONSTRAINTS); + } catch (ResourceManagerException expected) { + assertEquals(404, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); + } + } + + @Test + public void testGetOrgPolicy() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + when(resourceManagerRpcMock.getOrgPolicy(RESOURCE, CONSTRAINTS)) + .thenReturn(ORG_POLICY_INFO.toProtobuf()); + OrgPolicyInfo policyInfo = resourceManager.getOrgPolicy(RESOURCE, CONSTRAINTS); + assertEquals(CONSTRAINTS, policyInfo.getConstraint()); + assertEquals(BOOLEAN_POLICY, policyInfo.getBoolPolicy()); + assertEquals(LIST_POLICY, policyInfo.getPolicies()); + assertEquals(UPDATE_TIME, policyInfo.getUpdateTime()); + assertEquals(VERSION, policyInfo.getVersion()); + + verify(resourceManagerRpcMock).getOrgPolicy(RESOURCE, CONSTRAINTS); + } + + @Test + public void testGetOrgPolicyWithResourceManagerException() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + String exceptionMessage = "Not Found"; + doThrow(new ResourceManagerException(404, exceptionMessage)) + .when(resourceManagerRpcMock) + .getOrgPolicy(RESOURCE, CONSTRAINTS); + try { + resourceManager.getOrgPolicy(RESOURCE, CONSTRAINTS); + } catch (ResourceManagerException expected) { + assertEquals(404, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); + } + } + + @Test + public void testListAvailableOrgPolicyConstraints() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + ListResult expectedResult = + ListResult.of(CURSOR, ImmutableList.of(CONSTRAINT_INFO.toProtobuf())); + when(resourceManagerRpcMock.listAvailableOrgPolicyConstraints(NAME, EMPTY_RPC_OPTIONS)) + .thenReturn(expectedResult); + Page page = resourceManager.listAvailableOrgPolicyConstraints(NAME); + assertEquals(CURSOR, page.getNextPageToken()); + for (ConstraintInfo constraintInfo : page.getValues()) { + assertEquals(NAME, constraintInfo.getName()); + assertEquals(CONSTRAINT_DEFAULT, constraintInfo.getConstraintDefault()); + assertEquals(DISPLAY_NAME, constraintInfo.getDisplayName()); + assertEquals(DESCRIPTION, constraintInfo.getDescription()); + assertEquals(LIST_CONSTRAINT, constraintInfo.getConstraints()); + assertEquals(VERSION, constraintInfo.getVersion()); + } + verify(resourceManagerRpcMock).listAvailableOrgPolicyConstraints(NAME, EMPTY_RPC_OPTIONS); + } + + @Test + public void listAvailableOrgPolicyConstraintsWithResourceManagerException() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + String exceptionMessage = "Not Found"; + doThrow(new ResourceManagerException(404, exceptionMessage)) + .when(resourceManagerRpcMock) + .listAvailableOrgPolicyConstraints(RESOURCE, EMPTY_RPC_OPTIONS); + try { + resourceManager.listAvailableOrgPolicyConstraints(RESOURCE); + } catch (ResourceManagerException expected) { + assertEquals(404, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); + } + } + + @Test + public void testListOrgPolicies() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + ListResult expectedResult = + ListResult.of(CURSOR, ImmutableList.of(ORG_POLICY_INFO.toProtobuf())); + when(resourceManagerRpcMock.listOrgPolicies(RESOURCE, EMPTY_RPC_OPTIONS)) + .thenReturn(expectedResult); + Page policies = resourceManager.listOrgPolicies(RESOURCE); + assertEquals(CURSOR, policies.getNextPageToken()); + for (OrgPolicyInfo orgPolicyInfo : policies.getValues()) { + assertEquals(CONSTRAINTS, orgPolicyInfo.getConstraint()); + assertEquals(ETAG, orgPolicyInfo.getEtag()); + assertEquals(BOOLEAN_POLICY, orgPolicyInfo.getBoolPolicy()); + assertEquals(LIST_POLICY, orgPolicyInfo.getPolicies()); + assertEquals(UPDATE_TIME, orgPolicyInfo.getUpdateTime()); + assertEquals(VERSION, orgPolicyInfo.getVersion()); + } + verify(resourceManagerRpcMock).listOrgPolicies(RESOURCE, EMPTY_RPC_OPTIONS); + } + + @Test + public void testListOrgPoliciesWithResourceManagerException() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + String exceptionMessage = "Not Found"; + doThrow(new ResourceManagerException(404, exceptionMessage)) + .when(resourceManagerRpcMock) + .listOrgPolicies(RESOURCE, EMPTY_RPC_OPTIONS); + try { + resourceManager.listOrgPolicies(RESOURCE); + } catch (ResourceManagerException expected) { + assertEquals(404, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); + } + } + + @Test + public void testSetOrgPolicy() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + when(resourceManagerRpcMock.replaceOrgPolicy(RESOURCE, ORG_POLICY_INFO.toProtobuf())) + .thenReturn(ORG_POLICY_INFO.toProtobuf()); + OrgPolicyInfo policyInfo = resourceManager.replaceOrgPolicy(RESOURCE, ORG_POLICY_INFO); + assertEquals(CONSTRAINTS, policyInfo.getConstraint()); + assertEquals(BOOLEAN_POLICY, policyInfo.getBoolPolicy()); + assertEquals(LIST_POLICY, policyInfo.getPolicies()); + assertEquals(UPDATE_TIME, policyInfo.getUpdateTime()); + assertEquals(VERSION, policyInfo.getVersion()); + + verify(resourceManagerRpcMock).replaceOrgPolicy(RESOURCE, ORG_POLICY_INFO.toProtobuf()); + } + + @Test + public void testSetOrgPolicyWithResourceManagerException() throws IOException { + when(rpcFactoryMock.create(Mockito.any(ResourceManagerOptions.class))) + .thenReturn(resourceManagerRpcMock); + ResourceManager resourceManager = + ResourceManagerOptions.newBuilder() + .setServiceRpcFactory(rpcFactoryMock) + .build() + .getService(); + String exceptionMessage = "Not Found"; + doThrow(new ResourceManagerException(404, exceptionMessage)) + .when(resourceManagerRpcMock) + .replaceOrgPolicy(RESOURCE, ORG_POLICY_INFO.toProtobuf()); + try { + resourceManager.replaceOrgPolicy(RESOURCE, ORG_POLICY_INFO); + } catch (ResourceManagerException expected) { + assertEquals(404, expected.getCode()); + assertEquals(exceptionMessage, expected.getMessage()); + } + } }