diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookDefinition.java b/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookDefinition.java index 6531f036e4..b2f071aa10 100644 --- a/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookDefinition.java +++ b/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookDefinition.java @@ -38,9 +38,15 @@ public class CookbookDefinition { } public static class Builder { + private String name; private URI url; private ImmutableSet.Builder versions = ImmutableSet.builder(); + public Builder name(String name) { + this.name = checkNotNull(name, "name"); + return this; + } + public Builder url(URI url) { this.url = checkNotNull(url, "url"); return this; @@ -56,20 +62,33 @@ public class CookbookDefinition { return this; } + public Builder from(CookbookDefinition def) { + this.url = checkNotNull(def.getUrl(), "url"); + this.versions.addAll(checkNotNull(def.getVersions(), "versions")); + this.name = def.getName(); + return this; + } + public CookbookDefinition build() { - return new CookbookDefinition(url, versions.build()); + return new CookbookDefinition(name, url, versions.build()); } } + private final String name; private final URI url; private final Set versions; - @ConstructorProperties({ "url", "versions" }) - protected CookbookDefinition(URI url, @Nullable Set versions) { + @ConstructorProperties({"name", "url", "versions" }) + protected CookbookDefinition(String name, URI url, @Nullable Set versions) { + this.name = name; this.url = url; this.versions = copyOfOrEmpty(versions); } + public String getName() { + return name; + } + public URI getUrl() { return url; } @@ -82,6 +101,7 @@ public class CookbookDefinition { public int hashCode() { final int prime = 31; int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((url == null) ? 0 : url.hashCode()); result = prime * result + ((versions == null) ? 0 : versions.hashCode()); return result; @@ -96,6 +116,11 @@ public class CookbookDefinition { if (getClass() != obj.getClass()) return false; CookbookDefinition other = (CookbookDefinition) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; if (url == null) { if (other.url != null) return false; @@ -111,7 +136,7 @@ public class CookbookDefinition { @Override public String toString() { - return "CookbookDefinition [url=" + url + ", versions=" + versions + "]"; + return "CookbookDefinition [name=" + name + ", url=" + url + ", versions=" + versions + "]"; } public static class Version { diff --git a/apis/chef/src/main/java/org/jclouds/chef/functions/ParseCookbookDefinitionFromJsonv10.java b/apis/chef/src/main/java/org/jclouds/chef/functions/ParseCookbookDefinitionFromJsonv10.java index 562a00ad98..80ba9af78a 100644 --- a/apis/chef/src/main/java/org/jclouds/chef/functions/ParseCookbookDefinitionFromJsonv10.java +++ b/apis/chef/src/main/java/org/jclouds/chef/functions/ParseCookbookDefinitionFromJsonv10.java @@ -43,6 +43,12 @@ public class ParseCookbookDefinitionFromJsonv10 implements Function result = parser.apply(response); + String cookbookName = result.keySet().iterator().next(); + CookbookDefinition def = result.values().iterator().next(); + return CookbookDefinition.builder() // + .from(def) // + .name(cookbookName) // + .build(); } } diff --git a/apis/chef/src/main/java/org/jclouds/chef/functions/ParseCookbookDefinitionListFromJsonv10.java b/apis/chef/src/main/java/org/jclouds/chef/functions/ParseCookbookDefinitionListFromJsonv10.java index 311e44b6ef..019ed0d194 100644 --- a/apis/chef/src/main/java/org/jclouds/chef/functions/ParseCookbookDefinitionListFromJsonv10.java +++ b/apis/chef/src/main/java/org/jclouds/chef/functions/ParseCookbookDefinitionListFromJsonv10.java @@ -17,7 +17,6 @@ package org.jclouds.chef.functions; import com.google.common.base.Function; -import com.google.common.collect.Sets; import org.jclouds.chef.domain.CookbookDefinition; import org.jclouds.http.HttpResponse; import org.jclouds.http.functions.ParseJson; @@ -27,6 +26,9 @@ import javax.inject.Singleton; import java.util.Map; import java.util.Set; +import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Sets.newLinkedHashSet; + /** * Parses the cookbook versions in a Chef Server >= 0.10.8. * @@ -47,6 +49,17 @@ public class ParseCookbookDefinitionListFromJsonv10 implements Function apply(HttpResponse response) { - return Sets.newLinkedHashSet(parser.apply(response).values()); + Set> result = parser.apply(response).entrySet(); + return newLinkedHashSet(transform(result, new Function, CookbookDefinition>() { + @Override + public CookbookDefinition apply(Map.Entry input) { + String cookbookName = input.getKey(); + CookbookDefinition def = input.getValue(); + return CookbookDefinition.builder() // + .from(def) // + .name(cookbookName) // + .build(); + } + })); } } diff --git a/apis/chef/src/test/java/org/jclouds/chef/ChefApiExpectTest.java b/apis/chef/src/test/java/org/jclouds/chef/ChefApiExpectTest.java index 7706609995..65344efb4e 100644 --- a/apis/chef/src/test/java/org/jclouds/chef/ChefApiExpectTest.java +++ b/apis/chef/src/test/java/org/jclouds/chef/ChefApiExpectTest.java @@ -24,6 +24,7 @@ import java.util.Set; import javax.ws.rs.core.MediaType; import org.jclouds.chef.config.ChefHttpApiModule; +import org.jclouds.chef.domain.CookbookDefinition; import org.jclouds.date.TimeStamp; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; @@ -156,6 +157,20 @@ public class ChefApiExpectTest extends BaseChefApiExpectTest { assertTrue(nodes.isEmpty(), String.format("Expected nodes to be empty but was: %s", nodes)); } + public void testListCookbooksInEnvironmentReturnsValidSet() { + ChefApi api = requestSendsResponse( + signed(HttpRequest.builder() // + .method("GET") // + .endpoint("http://localhost:4000/environments/dev/cookbooks") // + .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) // + .addHeader("Accept", MediaType.APPLICATION_JSON).build()), // + HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/env_cookbooks.json", MediaType.APPLICATION_JSON)) // + .build()); + Set cookbooks = api.listCookbooksInEnvironment("dev"); + assertEquals(cookbooks.size(), 2); + } + @Override protected Module createModule() { return new TestChefRestClientModule(); diff --git a/apis/chef/src/test/java/org/jclouds/chef/functions/ParseCookbookDefinitionFromJsonv10Test.java b/apis/chef/src/test/java/org/jclouds/chef/functions/ParseCookbookDefinitionFromJsonv10Test.java index 0df9d64599..b5d8a8bf53 100644 --- a/apis/chef/src/test/java/org/jclouds/chef/functions/ParseCookbookDefinitionFromJsonv10Test.java +++ b/apis/chef/src/test/java/org/jclouds/chef/functions/ParseCookbookDefinitionFromJsonv10Test.java @@ -58,7 +58,7 @@ public class ParseCookbookDefinitionFromJsonv10Test { CookbookDefinition.Version v420 = CookbookDefinition.Version.builder() .url(new URI("http://localhost:4000/cookbooks/apache2/4.2.0")).version("4.2.0").build(); CookbookDefinition definition = CookbookDefinition.builder() - .url(new URI("http://localhost:4000/cookbooks/apache2")).version(v510).version(v420).build(); + .name("apache2").url(new URI("http://localhost:4000/cookbooks/apache2")).version(v510).version(v420).build(); assertEquals(handler.apply(HttpResponse .builder() diff --git a/apis/chef/src/test/java/org/jclouds/chef/functions/ParseCookbookDefinitionListFromJsonv10Test.java b/apis/chef/src/test/java/org/jclouds/chef/functions/ParseCookbookDefinitionListFromJsonv10Test.java index b39343da8f..04f8e35ed7 100644 --- a/apis/chef/src/test/java/org/jclouds/chef/functions/ParseCookbookDefinitionListFromJsonv10Test.java +++ b/apis/chef/src/test/java/org/jclouds/chef/functions/ParseCookbookDefinitionListFromJsonv10Test.java @@ -59,14 +59,14 @@ public class ParseCookbookDefinitionListFromJsonv10Test { CookbookDefinition.Version v420 = CookbookDefinition.Version.builder() .url(new URI("http://localhost:4000/cookbooks/apache2/4.2.0")).version("4.2.0").build(); CookbookDefinition apache2 = CookbookDefinition.builder() - .url(new URI("http://localhost:4000/cookbooks/apache2")).version(v510).version(v420).build(); + .name("apache2").url(new URI("http://localhost:4000/cookbooks/apache2")).version(v510).version(v420).build(); CookbookDefinition.Version v100 = CookbookDefinition.Version.builder() .url(new URI("http://localhost:4000/cookbooks/nginx/1.0.0")).version("1.0.0").build(); - CookbookDefinition.Version v130 = CookbookDefinition.Version.builder() + CookbookDefinition.Version v030 = CookbookDefinition.Version.builder() .url(new URI("http://localhost:4000/cookbooks/nginx/0.3.0")).version("0.3.0").build(); CookbookDefinition nginx = CookbookDefinition.builder() - .url(new URI("http://localhost:4000/cookbooks/nginx")).version(v100).version(v130).build(); + .name("nginx").url(new URI("http://localhost:4000/cookbooks/nginx")).version(v100).version(v030).build(); assertEquals(handler.apply(HttpResponse .builder() diff --git a/apis/chef/src/test/java/org/jclouds/chef/internal/BaseChefApiLiveTest.java b/apis/chef/src/test/java/org/jclouds/chef/internal/BaseChefApiLiveTest.java index a742bd11df..6d5f07560a 100644 --- a/apis/chef/src/test/java/org/jclouds/chef/internal/BaseChefApiLiveTest.java +++ b/apis/chef/src/test/java/org/jclouds/chef/internal/BaseChefApiLiveTest.java @@ -39,6 +39,7 @@ import java.util.Set; import org.jclouds.chef.ChefApi; import org.jclouds.chef.domain.ChecksumStatus; import org.jclouds.chef.domain.Client; +import org.jclouds.chef.domain.CookbookDefinition; import org.jclouds.chef.domain.CookbookVersion; import org.jclouds.chef.domain.DatabagItem; import org.jclouds.chef.domain.Environment; @@ -64,6 +65,9 @@ import com.google.common.collect.ImmutableSet; import com.google.common.io.Closeables; import com.google.common.primitives.Bytes; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.all; + /** * Tests behavior of {@code ChefApi} * @@ -483,6 +487,16 @@ public abstract class BaseChefApiLiveTest extends BaseChefLiv assertTrue(!nodeList.isEmpty()); } + @Test(dependsOnMethods = "testCreateNewCookbook") + public void testListCookbooksInEnvironment() throws Exception { + Set cookbooks = api.listCookbooksInEnvironment("_default"); + assertTrue(any(cookbooks, new Predicate() { + @Override + public boolean apply(CookbookDefinition input) { + return PREFIX.equals(input.getName()); + }}), String.format("Cookbook %s not in %s", PREFIX, cookbooks)); + } + @AfterClass(groups = { "live", "integration" }) @Override public void tearDown() { diff --git a/apis/chef/src/test/resources/env_cookbooks.json b/apis/chef/src/test/resources/env_cookbooks.json new file mode 100644 index 0000000000..ee7114f935 --- /dev/null +++ b/apis/chef/src/test/resources/env_cookbooks.json @@ -0,0 +1,20 @@ +{ + "apache2" => { + "url" => "http://localhost:4000/cookbooks/apache2", + "versions" => [ + {"url" => "http://localhost:4000/cookbooks/apache2/5.1.0", + "version" => "5.1.0"}, + {"url" => "http://localhost:4000/cookbooks/apache2/4.2.0", + "version" => "4.2.0"} + ] + }, + "nginx" => { + "url" => "http://localhost:4000/cookbooks/nginx", + "versions" => [ + {"url" => "http://localhost:4000/cookbooks/nginx/1.0.0", + "version" => "1.0.0"}, + {"url" => "http://localhost:4000/cookbooks/nginx/0.3.0", + "version" => "0.3.0"} + ] + } +}