Repository: jclouds
Updated Branches:
  refs/heads/master 2bd055011 -> 27b3a844f


JCLOUDS-1072: Add support for environment-specific run lists to Role


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/27b3a844
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/27b3a844
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/27b3a844

Branch: refs/heads/master
Commit: 27b3a844f89e311b2e25fc27e83659b3637dec2b
Parents: 2bd0550
Author: rongallagher <[email protected]>
Authored: Tue Feb 2 14:03:50 2016 -0500
Committer: Ignasi Barrera <[email protected]>
Committed: Wed Feb 10 12:09:19 2016 +0100

----------------------------------------------------------------------
 .../main/java/org/jclouds/chef/domain/Role.java |  64 +++++++++-
 .../java/org/jclouds/chef/ChefApiLiveTest.java  |  18 ++-
 .../test/java/org/jclouds/chef/ChefApiTest.java |  18 ++-
 .../java/org/jclouds/chef/domain/RoleTest.java  | 117 +++++++++++++++++++
 4 files changed, 208 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/27b3a844/apis/chef/src/main/java/org/jclouds/chef/domain/Role.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/Role.java 
b/apis/chef/src/main/java/org/jclouds/chef/domain/Role.java
index d51dc1e..ac37bec 100644
--- a/apis/chef/src/main/java/org/jclouds/chef/domain/Role.java
+++ b/apis/chef/src/main/java/org/jclouds/chef/domain/Role.java
@@ -20,14 +20,18 @@ import static 
com.google.common.base.Preconditions.checkNotNull;
 import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
 
 import java.beans.ConstructorProperties;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.jclouds.domain.JsonBall;
 import org.jclouds.javax.annotation.Nullable;
 
+import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -44,6 +48,10 @@ public class Role {
       private ImmutableMap.Builder<String, JsonBall> overrideAttributes = 
ImmutableMap.builder();
       private ImmutableMap.Builder<String, JsonBall> defaultAttributes = 
ImmutableMap.builder();
       private ImmutableList.Builder<String> runList = ImmutableList.builder();
+      // envRunList is a nested set of collections. The Immutable* classes in 
google collections don't appear to
+      // support this nested immutability, so the builder will utilize native 
collections as the envRunList is
+      // assembled. An immutable, nested map of collections will be assembled 
in the build() method.
+      private Map<String, List<String>> envRunList = new HashMap<String, 
List<String>>();
 
       public Builder name(String name) {
          this.name = checkNotNull(name, "name");
@@ -85,8 +93,40 @@ public class Role {
          return this;
       }
 
+      public Builder envRunList(Map<String, List<String>> envRunList) {
+         this.envRunList.putAll(checkNotNull(envRunList, "envRunList"));
+         return this;
+      }
+
+      public Builder envRunList(String name, List<String> runList) {
+         this.envRunList.put(checkNotNull(name, "name"), checkNotNull(runList, 
"runList"));
+         return this;
+      }
+
+      public Builder envRunListElement(String name, String value) {
+         checkNotNull(name, "name");
+         checkNotNull(value, "value");
+         List<String> runList = this.envRunList.get(name);
+         if (runList == null) {
+            runList = new ArrayList<String>();
+            this.envRunList.put(name, runList);
+         }
+         runList.add(value);
+         return this;
+      }
+
       public Role build() {
-         return new Role(name, description, defaultAttributes.build(), 
runList.build(), overrideAttributes.build());
+         // Assemble an immutable envRunList where each entry is an immutable 
list of entries.
+         Map<String, List<String>> immutableEnvRunList = 
Maps.transformValues(envRunList,
+               new Function<List<String>, List<String>>() {
+                  @Override
+                  public List<String> apply(List<String> input) {
+                     return ImmutableList.copyOf(input);
+                  }
+               });
+         
+         return new Role(name, description, defaultAttributes.build(), 
runList.build(), overrideAttributes.build(), 
+               immutableEnvRunList);
       }
    }
 
@@ -98,6 +138,8 @@ public class Role {
    private final Map<String, JsonBall> defaultAttributes;
    @SerializedName("run_list")
    private final List<String> runList;
+   @SerializedName("env_run_lists")
+   private Map<String, List<String>> envRunList;
 
    // internal
    @SerializedName("json_class")
@@ -105,14 +147,17 @@ public class Role {
    @SerializedName("chef_type")
    private final String _chefType = "role";
 
-   @ConstructorProperties({ "name", "description", "default_attributes", 
"run_list", "override_attributes" })
+   @ConstructorProperties({ "name", "description", "default_attributes", 
"run_list", "override_attributes", 
+      "env_run_lists"  })
    protected Role(String name, String description, @Nullable Map<String, 
JsonBall> defaultAttributes,
-         @Nullable List<String> runList, @Nullable Map<String, JsonBall> 
overrideAttributes) {
+         @Nullable List<String> runList, @Nullable Map<String, JsonBall> 
overrideAttributes,
+         @Nullable Map<String, List<String>> envRunList) {
       this.name = name;
       this.description = description;
       this.defaultAttributes = copyOfOrEmpty(defaultAttributes);
       this.runList = copyOfOrEmpty(runList);
       this.overrideAttributes = copyOfOrEmpty(overrideAttributes);
+      this.envRunList = envRunList;
    }
 
    public String getName() {
@@ -135,6 +180,10 @@ public class Role {
       return runList;
    }
 
+   public Map<String, List<String>> getEnvRunList() {
+      return envRunList;
+   }
+
    @Override
    public int hashCode() {
       final int prime = 31;
@@ -146,6 +195,7 @@ public class Role {
       result = prime * result + ((name == null) ? 0 : name.hashCode());
       result = prime * result + ((overrideAttributes == null) ? 0 : 
overrideAttributes.hashCode());
       result = prime * result + ((runList == null) ? 0 : runList.hashCode());
+      result = prime * result + ((envRunList == null) ? 0 : 
envRunList.hashCode());
       return result;
    }
 
@@ -193,13 +243,19 @@ public class Role {
             return false;
       } else if (!runList.equals(other.runList))
          return false;
+      if (envRunList == null) {
+         if (other.envRunList != null)
+            return false;
+      } else if (!envRunList.equals(other.envRunList))
+         return false;
       return true;
    }
 
    @Override
    public String toString() {
       return "Role [name=" + name + ", description=" + description + ", 
defaultAttributes=" + defaultAttributes
-            + ", overrideAttributes=" + overrideAttributes + ", runList=" + 
runList + "]";
+            + ", overrideAttributes=" + overrideAttributes + ", runList=" + 
runList
+            + ", envRunList=" + this.envRunList + "]";
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/27b3a844/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java 
b/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java
index c00e0d9..9f46f78 100644
--- a/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java
+++ b/apis/chef/src/test/java/org/jclouds/chef/ChefApiLiveTest.java
@@ -20,6 +20,7 @@ import static com.google.common.collect.Iterables.any;
 import static com.google.common.collect.Iterables.isEmpty;
 import static com.google.common.hash.Hashing.md5;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.jclouds.chef.domain.RoleTest.verifyRunListForEnvironment;
 import static org.jclouds.util.Closeables2.closeQuietly;
 import static org.jclouds.util.Predicates2.retry;
 import static org.testng.Assert.assertEquals;
@@ -243,12 +244,27 @@ public class ChefApiLiveTest extends BaseChefLiveTest {
 
    @Test
    public void testCreateRole() throws Exception {
+      String env1 = "env1";
+      String env2 = "env2";
+      String env1Alpha = "env1.alpha";
+      String env2Alpha = "env2.alpha";
+      String env2Bravo = "env2.bravo";
+
       api.deleteRole(PREFIX);
-      
api.createRole(Role.builder().name(PREFIX).runListElement("recipe[java]").build());
+      api.createRole(Role.builder().name(PREFIX).runListElement("recipe[java]")
+            .envRunListElement(env1, env1Alpha)
+            .envRunListElement(env2, env2Alpha)
+            .envRunListElement(env2, env2Bravo)
+            .build());
       Role role = api.getRole(PREFIX);
       assertNotNull(role, "Created role should not be null");
       assertEquals(role.getName(), PREFIX);
       assertEquals(role.getRunList(), Collections.singleton("recipe[java]"));
+
+      assertNotNull(role.getEnvRunList(), "envRunList should not be null");
+      assertEquals(role.getEnvRunList().size(), 2, "envRunList.size should be 
2");
+      verifyRunListForEnvironment(role.getEnvRunList(), env1, env1Alpha);
+      verifyRunListForEnvironment(role.getEnvRunList(), env2, env2Alpha, 
env2Bravo);
    }
 
    @Test(dependsOnMethods = "testCreateRole")

http://git-wip-us.apache.org/repos/asf/jclouds/blob/27b3a844/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java 
b/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java
index 99a2da0..b24a130 100644
--- a/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java
+++ b/apis/chef/src/test/java/org/jclouds/chef/ChefApiTest.java
@@ -357,13 +357,18 @@ public class ChefApiTest extends 
BaseRestAnnotationProcessingTest<ChefApi> {
    public void testCreateRole() throws SecurityException, 
NoSuchMethodException, IOException {
       Invokable<?, ?> method = method(ChefApi.class, "createRole", Role.class);
       GeneratedHttpRequest httpRequest = 
processor.apply(Invocation.create(method,
-            ImmutableList.<Object> 
of(Role.builder().name("testrole").runListElement("recipe[java]").build())));
+            ImmutableList.<Object> 
of(Role.builder().name("testrole").runListElement("recipe[java]")
+            .envRunListElement("erl.one", "erl.one.alpha")
+            .envRunListElement("erl.one", "erl.one.bravo")
+            .envRunListElement("erl.two", "erl.two.alpha")
+            .envRunListElement("erl.two", "erl.two.bravo")
+            .build())));
 
       assertRequestLineEquals(httpRequest, "POST http://localhost:4000/roles 
HTTP/1.1");
       assertNonPayloadHeadersEqual(httpRequest, "Accept: 
application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION
             + "-test\n");
       assertPayloadEquals(httpRequest, 
"{\"name\":\"testrole\",\"override_attributes\":{},\"default_attributes\":{},"
-            + 
"\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::Role\",\"chef_type\":\"role\"}",
+            + 
"\"run_list\":[\"recipe[java]\"],\"env_run_lists\":{\"erl.one\":[\"erl.one.alpha\",\"erl.one.bravo\"],\"erl.two\":[\"erl.two.alpha\",\"erl.two.bravo\"]},\"json_class\":\"Chef::Role\",\"chef_type\":\"role\"}",
             "application/json", false);
 
       assertResponseParserClassEquals(method, httpRequest, 
ReleasePayloadAndReturn.class);
@@ -377,13 +382,18 @@ public class ChefApiTest extends 
BaseRestAnnotationProcessingTest<ChefApi> {
    public void testUpdateRole() throws SecurityException, 
NoSuchMethodException, IOException {
       Invokable<?, ?> method = method(ChefApi.class, "updateRole", Role.class);
       GeneratedHttpRequest httpRequest = 
processor.apply(Invocation.create(method,
-            ImmutableList.<Object> 
of(Role.builder().name("testrole").runListElement("recipe[java]").build())));
+            ImmutableList.<Object> 
of(Role.builder().name("testrole").runListElement("recipe[java]")
+            .envRunListElement("erl.one", "erl.one.alpha")
+            .envRunListElement("erl.one", "erl.one.bravo")
+            .envRunListElement("erl.two", "erl.two.alpha")
+            .envRunListElement("erl.two", "erl.two.bravo")
+            .build())));
 
       assertRequestLineEquals(httpRequest, "PUT 
http://localhost:4000/roles/testrole HTTP/1.1");
       assertNonPayloadHeadersEqual(httpRequest, "Accept: 
application/json\nX-Chef-Version: " + ChefApiMetadata.DEFAULT_API_VERSION
             + "-test\n");
       assertPayloadEquals(httpRequest, 
"{\"name\":\"testrole\",\"override_attributes\":{},\"default_attributes\":{},"
-            + 
"\"run_list\":[\"recipe[java]\"],\"json_class\":\"Chef::Role\",\"chef_type\":\"role\"}",
+            + 
"\"run_list\":[\"recipe[java]\"],\"env_run_lists\":{\"erl.one\":[\"erl.one.alpha\",\"erl.one.bravo\"],\"erl.two\":[\"erl.two.alpha\",\"erl.two.bravo\"]},\"json_class\":\"Chef::Role\",\"chef_type\":\"role\"}",
             "application/json", false);
 
       assertResponseParserClassEquals(method, httpRequest, ParseJson.class);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/27b3a844/apis/chef/src/test/java/org/jclouds/chef/domain/RoleTest.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/test/java/org/jclouds/chef/domain/RoleTest.java 
b/apis/chef/src/test/java/org/jclouds/chef/domain/RoleTest.java
new file mode 100644
index 0000000..59f92bf
--- /dev/null
+++ b/apis/chef/src/test/java/org/jclouds/chef/domain/RoleTest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.jclouds.chef.domain;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+/**
+ * Tests behaviors of {@code Role}.
+ */
+@Test(groups = { "unit" })
+public class RoleTest {
+   @Test(expectedExceptions = NullPointerException.class)
+   public void canNotAddEnvRunListMapThatIsNull() {
+      Role.builder().envRunList((Map<String, List<String>>) null);
+   }
+
+   @Test(expectedExceptions = NullPointerException.class)
+   public void canNotAddRunListForEnvironmentThatIsNull() {
+      Role.builder().envRunList("does.not.matter", (List<String>) null);
+   }
+
+   @Test(expectedExceptions = NullPointerException.class)
+   public void canNotUseNullEnvNameWhenAddingEnvRunListEntry() {
+      Role.builder().envRunListElement((String) null, "does.not.matter");
+   }
+
+   @Test(expectedExceptions = NullPointerException.class)
+   public void canNotUseNullEntryWhenAddingEnvRunListEntry() {
+      Role.builder().envRunListElement("does.not.matter", (String) null);
+   }
+
+   public void multipleEnvRunListsCanBePopulated() {
+      String env1 = "env1";
+      String env2 = "env2";
+      String env1Alpha = "env1.alpha";
+      String env2Alpha = "env2.alpha";
+      String env2Bravo = "env2.bravo";
+      Role role = Role.builder().envRunListElement(env1, 
env1Alpha).envRunListElement(env2, env2Alpha)
+            .envRunListElement(env2, env2Bravo).build();
+      Map<String, List<String>> envRunList = role.getEnvRunList();
+      assertNotNull(envRunList, "envRunList");
+      assertEquals(envRunList.size(), 2, "envRunList.size");
+
+      verifyRunListForEnvironment(envRunList, env1, env1Alpha);
+      verifyRunListForEnvironment(envRunList, env2, env2Alpha, env2Bravo);
+   }
+
+   @Test(expectedExceptions = UnsupportedOperationException.class)
+   public void envRunListOnNewlyBuiltRoleIsImmutable() {
+      String env = "env";
+      Role role = Role.builder().envRunListElement(env, env + "1").build();
+      role.getEnvRunList().put("does.not.matter", new ArrayList<String>());
+   }
+
+   @Test(expectedExceptions = UnsupportedOperationException.class)
+   public void envRunListEntriesOnNewlyBuiltRoleIsImmutable() {
+      String env = "env";
+      Role role = Role.builder().envRunListElement(env, env + "1").build();
+      role.getEnvRunList().get(env).add("does.not.matter");
+   }
+
+   public void rolesWithSameEnvRunListAreEqual() {
+      String env = "env";
+      String entry = "entry";
+
+      Role role1 = Role.builder().envRunListElement(env, entry).build();
+      Role role2 = Role.builder().envRunListElement(env, entry).build();
+
+      assertEquals(role1.hashCode(), role2.hashCode(), "hashCodes should be 
equal");
+      assertEquals(role1, role2, "role1 should equal role2");
+      assertEquals(role2, role1, "role2 should equal role1");
+   }
+
+   public void rolesWithDifferentEnvRunListAreNotEqual() {
+      String env = "env";
+      String entry = "entry";
+
+      Role role1 = Role.builder().envRunListElement(env, 
entry.toUpperCase()).build();
+      Role role2 = Role.builder().envRunListElement(env, 
entry.toLowerCase()).build();
+
+      assertNotEquals(role1.hashCode(), role2.hashCode(), "hashCodes should 
not be equal");
+      assertNotEquals(role1, role2, "role1 should not equal role2");
+      assertNotEquals(role2, role1, "role2 should not equal role1");
+   }
+
+   public static void verifyRunListForEnvironment(Map<String, List<String>> 
envRunList, String envName,
+         String... expectedEntries) {
+      assertTrue(envRunList.containsKey(envName), "envRunList contains " + 
envName);
+      assertEquals(envRunList.get(envName).size(), expectedEntries.length, 
"envRunList size for '" + envName);
+      
assertTrue(envRunList.get(envName).containsAll(Arrays.asList(expectedEntries)), 
"envRunList for e1 contains "
+            + Arrays.asList(expectedEntries));
+   }
+}

Reply via email to