Repository: jclouds
Updated Branches:
  refs/heads/master eba727fef -> 867c7a407


http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/pom.xml
----------------------------------------------------------------------
diff --git a/providers/enterprise-chef/pom.xml 
b/providers/enterprise-chef/pom.xml
new file mode 100644
index 0000000..944701b
--- /dev/null
+++ b/providers/enterprise-chef/pom.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.jclouds</groupId>
+    <artifactId>jclouds-project</artifactId>
+    <version>1.8.0-SNAPSHOT</version>
+    <relativePath>../../project/pom.xml</relativePath>
+  </parent>
+  <groupId>org.apache.jclouds.provider</groupId>
+  <artifactId>enterprisechef</artifactId>
+  <name>jclouds Enterprise Chef provider</name>
+  <description>jclouds components to access Enterprise Chef</description>
+
+  <properties>
+    <test.enterprisechef.org>YOUR_ORG</test.enterprisechef.org>
+    
<test.enterprisechef.endpoint>https://api.opscode.com/organizations/${test.enterprisechef.org}</test.enterprisechef.endpoint>
+    <test.enterprisechef.api-version />
+    <test.enterprisechef.build-version />
+    <test.enterprisechef.identity>YOUR_USER</test.enterprisechef.identity>
+    
<test.enterprisechef.credential>${user.home}/.chef/${test.enterprisechef.org}/${test.enterprisechef.identity}.pem</test.enterprisechef.credential>
+    
<jclouds.osgi.export>org.jclouds.enterprisechef*;version="${project.version}"</jclouds.osgi.export>
+    
<jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>chef</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.api</groupId>
+      <artifactId>chef</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-slf4j</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <version>1.0.9</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>live</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>integration</id>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>test</goal>
+                </goals>
+                <configuration>
+                  <systemPropertyVariables>
+                    
<test.enterprisechef.org>${test.enterprisechef.org}</test.enterprisechef.org>
+                    
<test.enterprisechef.endpoint>${test.enterprisechef.endpoint}</test.enterprisechef.endpoint>
+                    
<test.enterprisechef.api-version>${test.enterprisechef.api-version}</test.enterprisechef.api-version>
+                    
<test.enterprisechef.build-version>${test.enterprisechef.build-version}</test.enterprisechef.build-version>
+                    
<test.enterprisechef.identity>${test.enterprisechef.identity}</test.enterprisechef.identity>
+                    
<test.enterprisechef.credential>${test.enterprisechef.credential}</test.enterprisechef.credential>
+                  </systemPropertyVariables>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefApi.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefApi.java
 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefApi.java
new file mode 100644
index 0000000..8f1a0ed
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefApi.java
@@ -0,0 +1,124 @@
+/*
+ * 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.enterprisechef;
+
+import java.util.Set;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Constants;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.filters.SignedHeaderAuth;
+import org.jclouds.chef.functions.ParseKeySetFromJson;
+import org.jclouds.enterprisechef.binders.BindGroupToUpdateRequestJsonPayload;
+import org.jclouds.enterprisechef.binders.GroupName;
+import org.jclouds.enterprisechef.domain.Group;
+import org.jclouds.enterprisechef.domain.User;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.ParamParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.WrapWith;
+
+/**
+ * Provides synchronous access to the Enterprise Chef Api.
+ */
+@RequestFilters(SignedHeaderAuth.class)
+@Consumes(MediaType.APPLICATION_JSON)
+@Headers(keys = "X-Chef-Version", values = "{" + 
Constants.PROPERTY_API_VERSION + "}")
+public interface EnterpriseChefApi extends ChefApi
+{
+    /**
+     * Retrieves an existing user.
+     * 
+     * @param name The name of the user to get.
+     * @return The details of the user or <code>null</code> if not found.
+     */
+    @Named("user:get")
+    @GET
+    @Path("/users/{name}")
+    @Fallback(NullOnNotFoundOr404.class)
+    User getUser(@PathParam("name") String name);
+
+    /**
+     * List all existing groups.
+     * 
+     * @return The list of groups.
+     */
+    @Named("group:list")
+    @GET
+    @Path("/groups")
+    @ResponseParser(ParseKeySetFromJson.class)
+    Set<String> listGroups();
+
+    /**
+     * Retrieves an existing group.
+     * 
+     * @param name The name of the group to get.
+     * @return The details of the group or <code>null</code> if not found.
+     */
+    @Named("group:get")
+    @GET
+    @Path("/groups/{name}")
+    @Fallback(NullOnNotFoundOr404.class)
+    Group getGroup(@PathParam("name") String name);
+
+    /**
+     * Creates a new group.
+     * 
+     * @param name The name of the group to create.
+     */
+    @Named("group:create")
+    @POST
+    @Path("/groups")
+    void createGroup(@WrapWith("groupname") String name);
+
+    /**
+     * Updates a group.
+     * <p>
+     * This method can be used to add actors (clients, groups) to the group.
+     * 
+     * @param group The group with the updated information.
+     */
+    @Named("group:update")
+    @PUT
+    @Path("/groups/{name}")
+    void updateGroup(
+        @PathParam("name") @ParamParser(GroupName.class) 
@BinderParam(BindGroupToUpdateRequestJsonPayload.class) Group group);
+
+    /**
+     * Deletes a group.
+     * 
+     * @param name The name of the group to delete.
+     */
+    @Named("group:delete")
+    @DELETE
+    @Path("/groups/{name}")
+    void deleteGroup(@PathParam("name") String name);
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefApiMetadata.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefApiMetadata.java
 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefApiMetadata.java
new file mode 100644
index 0000000..fdccf46
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefApiMetadata.java
@@ -0,0 +1,82 @@
+/*
+ * 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.enterprisechef;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.chef.ChefApiMetadata;
+import org.jclouds.chef.ChefContext;
+import org.jclouds.chef.config.ChefBootstrapModule;
+import org.jclouds.chef.config.ChefParserModule;
+import org.jclouds.enterprisechef.config.EnterpriseChefHttpApiModule;
+import org.jclouds.ohai.config.JMXOhaiModule;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for the Enterprise Chef api.
+ */
+public class EnterpriseChefApiMetadata extends 
BaseHttpApiMetadata<EnterpriseChefApi> {
+
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public EnterpriseChefApiMetadata() {
+      this(new Builder());
+   }
+
+   protected EnterpriseChefApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      return ChefApiMetadata.defaultProperties();
+   }
+
+   public static class Builder extends 
BaseHttpApiMetadata.Builder<EnterpriseChefApi, Builder> {
+
+      protected Builder() {
+         id("enterprisechef")
+               .name("Enterprise Chef Api")
+               .identityName("User")
+               .credentialName("Certificate")
+               .version(ChefApiMetadata.DEFAULT_API_VERSION)
+               .documentation(URI.create("http://www.opscode.com/support";))
+               .defaultEndpoint("https://api.opscode.com";)
+               .view(ChefContext.class)
+               
.defaultProperties(EnterpriseChefApiMetadata.defaultProperties())
+               .defaultModules(
+                     ImmutableSet.<Class<? extends Module>> 
of(EnterpriseChefHttpApiModule.class,
+                           ChefParserModule.class, ChefBootstrapModule.class, 
JMXOhaiModule.class));
+      }
+
+      @Override
+      public EnterpriseChefApiMetadata build() {
+         return new EnterpriseChefApiMetadata(this);
+      }
+
+      @Override
+      protected Builder self() {
+         return this;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefProviderMetadata.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefProviderMetadata.java
 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefProviderMetadata.java
new file mode 100644
index 0000000..336ea7a
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/EnterpriseChefProviderMetadata.java
@@ -0,0 +1,86 @@
+/*
+ * 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.enterprisechef;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+
+/**
+ * Implementation of @ link org.jclouds.types.ProviderMetadata} for Enterprise 
Chef
+ */
+public class EnterpriseChefProviderMetadata extends BaseProviderMetadata
+{
+
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    public Builder toBuilder()
+    {
+        return builder().fromProviderMetadata(this);
+    }
+
+    public EnterpriseChefProviderMetadata()
+    {
+        super(builder());
+    }
+
+    public EnterpriseChefProviderMetadata(Builder builder)
+    {
+        super(builder);
+    }
+
+    public static Properties defaultProperties()
+    {
+        Properties properties = new Properties();
+        return properties;
+    }
+
+    public static class Builder extends BaseProviderMetadata.Builder
+    {
+
+        protected Builder()
+        {
+            id("enterprisechef") //
+                .name("OpsCode Enterprise Chef") //
+                .endpoint("https://api.opscode.com";) //
+                .homepage(URI.create("https://manage.opscode.com";)) //
+                .console(URI.create("https://manage.opscode.com";)) //
+                .apiMetadata(new EnterpriseChefApiMetadata()) //
+                
.defaultProperties(EnterpriseChefProviderMetadata.defaultProperties());
+        }
+
+        @Override
+        public EnterpriseChefProviderMetadata build()
+        {
+            return new EnterpriseChefProviderMetadata(this);
+        }
+
+        @Override
+        public Builder fromProviderMetadata(ProviderMetadata in)
+        {
+            super.fromProviderMetadata(in);
+            return this;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/binders/BindGroupToUpdateRequestJsonPayload.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/binders/BindGroupToUpdateRequestJsonPayload.java
 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/binders/BindGroupToUpdateRequestJsonPayload.java
new file mode 100644
index 0000000..2573b9d
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/binders/BindGroupToUpdateRequestJsonPayload.java
@@ -0,0 +1,79 @@
+/*
+ * 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.enterprisechef.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.enterprisechef.domain.Group;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+/**
+ * Binds a group to the payload expected for the Put method in the Enterprise 
Chef
+ * Api.
+ */
+@Singleton
+public class BindGroupToUpdateRequestJsonPayload extends BindToJsonPayload {
+
+   @Inject
+   public BindGroupToUpdateRequestJsonPayload(Json jsonBinder) {
+      super(jsonBinder);
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
+      checkArgument(checkNotNull(payload, "payload") instanceof Group, "this 
binder is only valid for Group objects");
+      GroupUpdateRequest updateGroup = new GroupUpdateRequest((Group) payload);
+      return super.bindToRequest(request, updateGroup);
+   }
+
+   @SuppressWarnings("unused")
+   private static class GroupUpdateRequest {
+      private String name;
+      private String groupname;
+      private String orgname;
+      private ActorConfiguration actors;
+
+      public GroupUpdateRequest(Group group) {
+         this.name = group.getName();
+         this.groupname = group.getGroupname();
+         this.orgname = group.getOrgname();
+         this.actors = new ActorConfiguration(group);
+      }
+   }
+
+   @SuppressWarnings("unused")
+   private static class ActorConfiguration {
+      private Set<String> clients;
+      private Set<String> groups;
+      private Set<String> users;
+
+      public ActorConfiguration(Group group) {
+         this.clients = group.getClients();
+         this.groups = group.getGroups();
+         this.users = group.getUsers();
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/binders/GroupName.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/binders/GroupName.java
 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/binders/GroupName.java
new file mode 100644
index 0000000..12286a6
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/binders/GroupName.java
@@ -0,0 +1,38 @@
+/*
+ * 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.enterprisechef.binders;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import org.jclouds.enterprisechef.domain.Group;
+
+import com.google.common.base.Function;
+
+/**
+ * Gets the name of a group.
+ */
+@Singleton
+public class GroupName implements Function<Object, String> {
+
+   @Override
+   public String apply(Object from) {
+      return ((Group) checkNotNull(from, "from")).getGroupname();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/config/EnterpriseChefHttpApiModule.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/config/EnterpriseChefHttpApiModule.java
 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/config/EnterpriseChefHttpApiModule.java
new file mode 100644
index 0000000..ed0a49f
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/config/EnterpriseChefHttpApiModule.java
@@ -0,0 +1,36 @@
+/*
+ * 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.enterprisechef.config;
+
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.config.BaseChefHttpApiModule;
+import org.jclouds.enterprisechef.EnterpriseChefApi;
+import org.jclouds.rest.ConfiguresHttpApi;
+
+/**
+ * Configures the Enterprise Chef connection.
+ */
+@ConfiguresHttpApi
+public class EnterpriseChefHttpApiModule extends 
BaseChefHttpApiModule<EnterpriseChefApi> {
+
+   @Override
+   protected void configure() {
+      super.configure();
+      bind(ChefApi.class).to(EnterpriseChefApi.class);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/domain/Group.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/domain/Group.java
 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/domain/Group.java
new file mode 100644
index 0000000..8535ca2
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/domain/Group.java
@@ -0,0 +1,211 @@
+/*
+ * 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.enterprisechef.domain;
+
+import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.util.Set;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Group object.
+ */
+public class Group {
+   public static Builder builder(String groupname) {
+      return new Builder(groupname);
+   }
+
+   public static class Builder {
+      private String name;
+      private String groupname;
+      private String orgname;
+      private ImmutableSet.Builder<String> actors = ImmutableSet.builder();
+      private ImmutableSet.Builder<String> clients = ImmutableSet.builder();
+      private ImmutableSet.Builder<String> groups = ImmutableSet.builder();
+      private ImmutableSet.Builder<String> users = ImmutableSet.builder();
+
+      public Builder(String groupname) {
+         this.groupname = groupname;
+      }
+
+      public Builder name(String name) {
+         this.name = checkNotNull(name, "name");
+         return this;
+      }
+
+      public Builder groupname(String groupname) {
+         this.groupname = checkNotNull(groupname, "groupname");
+         return this;
+      }
+
+      public Builder orgname(String orgname) {
+         this.orgname = checkNotNull(orgname, "orgname");
+         return this;
+      }
+
+      public Builder actor(String actor) {
+         this.actors.add(checkNotNull(actor, "actor"));
+         return this;
+      }
+
+      public Builder actors(Iterable<String> actors) {
+         this.actors.addAll(checkNotNull(actors, "actors"));
+         return this;
+      }
+
+      public Builder client(String client) {
+         this.clients.add(checkNotNull(client, "client"));
+         return this;
+      }
+
+      public Builder clients(Iterable<String> clients) {
+         this.clients.addAll(checkNotNull(clients, "clients"));
+         return this;
+      }
+
+      public Builder group(String group) {
+         this.groups.add(checkNotNull(group, "group"));
+         return this;
+      }
+
+      public Builder groups(Iterable<String> groups) {
+         this.groups.addAll(checkNotNull(groups, "groups"));
+         return this;
+      }
+
+      public Builder user(String user) {
+         this.users.add(checkNotNull(user, "user"));
+         return this;
+      }
+
+      public Builder users(Iterable<String> users) {
+         this.users.addAll(checkNotNull(users, "users"));
+         return this;
+      }
+
+      public Group build() {
+         return new Group(name, checkNotNull(groupname, "groupname"), orgname, 
actors.build(), clients.build(),
+               groups.build(), users.build());
+      }
+   }
+
+   private final String name;
+   private final String groupname;
+   private final String orgname;
+   private final Set<String> actors;
+   private final Set<String> clients;
+   private final Set<String> groups;
+   private final Set<String> users;
+
+   @ConstructorProperties({ "name", "groupname", "orgname", "actors", 
"clients", "groups", "users" })
+   public Group(String name, String groupname, String orgname, @Nullable 
Set<String> actors,
+         @Nullable Set<String> clients, @Nullable Set<String> groups, 
@Nullable Set<String> users) {
+      this.name = name;
+      this.groupname = groupname;
+      this.orgname = orgname;
+      this.actors = copyOfOrEmpty(actors);
+      this.clients = copyOfOrEmpty(clients);
+      this.groups = copyOfOrEmpty(groups);
+      this.users = copyOfOrEmpty(users);
+   }
+
+   public String getName() {
+      return name;
+   }
+
+   public String getGroupname() {
+      return groupname;
+   }
+
+   public String getOrgname() {
+      return orgname;
+   }
+
+   public Set<String> getActors() {
+      return actors;
+   }
+
+   public Set<String> getClients() {
+      return clients;
+   }
+
+   public Set<String> getGroups() {
+      return groups;
+   }
+
+   public Set<String> getUsers() {
+      return users;
+   }
+
+   @Override
+   public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + (groupname == null ? 0 : groupname.hashCode());
+      result = prime * result + (name == null ? 0 : name.hashCode());
+      result = prime * result + (orgname == null ? 0 : orgname.hashCode());
+      return result;
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) {
+         return true;
+      }
+      if (obj == null) {
+         return false;
+      }
+      if (getClass() != obj.getClass()) {
+         return false;
+      }
+      Group other = (Group) obj;
+      if (groupname == null) {
+         if (other.groupname != null) {
+            return false;
+         }
+      } else if (!groupname.equals(other.groupname)) {
+         return false;
+      }
+      if (name == null) {
+         if (other.name != null) {
+            return false;
+         }
+      } else if (!name.equals(other.name)) {
+         return false;
+      }
+      if (orgname == null) {
+         if (other.orgname != null) {
+            return false;
+         }
+      } else if (!orgname.equals(other.orgname)) {
+         return false;
+      }
+      return true;
+   }
+
+   @Override
+   public String toString() {
+      return "Group [name=" + name + ", groupname=" + groupname + ", orgname=" 
+ orgname + ", actors=" + actors
+            + ", clients=" + clients + ", groups=" + groups + ", users=" + 
users + "]";
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/domain/User.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/domain/User.java
 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/domain/User.java
new file mode 100644
index 0000000..da4e9e5
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/java/org/jclouds/enterprisechef/domain/User.java
@@ -0,0 +1,220 @@
+/*
+ * 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.enterprisechef.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.security.PublicKey;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * User object.
+ */
+public class User {
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static class Builder {
+      private String username;
+      private String firstName;
+      private String middleName;
+      private String lastName;
+      private String displayName;
+      private String email;
+      private PublicKey publicKey;
+
+      public Builder username(String username) {
+         this.username = checkNotNull(username, "username");
+         return this;
+      }
+
+      public Builder firstName(String firstName) {
+         this.firstName = checkNotNull(firstName, "firstName");
+         return this;
+      }
+
+      public Builder middleName(String middleName) {
+         this.middleName = checkNotNull(middleName, "middleName");
+         return this;
+      }
+
+      public Builder lastName(String lastName) {
+         this.lastName = checkNotNull(lastName, "lastName");
+         return this;
+      }
+
+      public Builder displayName(String displayName) {
+         this.displayName = checkNotNull(displayName, "displayName");
+         return this;
+      }
+
+      public Builder email(String email) {
+         this.email = checkNotNull(email, "email");
+         return this;
+      }
+
+      public Builder publicKey(PublicKey publicKey) {
+         this.publicKey = checkNotNull(publicKey, "publicKey");
+         return this;
+      }
+
+      public User build() {
+         return new User(username, firstName, middleName, lastName, 
displayName, email, publicKey);
+      }
+   }
+
+   private final String username;
+   @SerializedName("first_name")
+   private final String firstName;
+   @SerializedName("middle_name")
+   private final String middleName;
+   @SerializedName("last_name")
+   private final String lastName;
+   @SerializedName("display_name")
+   private final String displayName;
+   private final String email;
+   @SerializedName("public_key")
+   private final PublicKey publicKey;
+
+   @ConstructorProperties({ "username", "first_name", "middle_name", 
"last_name", "display_name", "email", "public_key" })
+   protected User(String username, String firstName, String middleName, String 
lastName, String displayName,
+         String email, PublicKey publicKey) {
+      this.username = username;
+      this.firstName = firstName;
+      this.middleName = middleName;
+      this.lastName = lastName;
+      this.displayName = displayName;
+      this.email = email;
+      this.publicKey = publicKey;
+   }
+
+   public String getUsername() {
+      return username;
+   }
+
+   public String getFirstName() {
+      return firstName;
+   }
+
+   public String getMiddleName() {
+      return middleName;
+   }
+
+   public String getLastName() {
+      return lastName;
+   }
+
+   public String getDisplayName() {
+      return displayName;
+   }
+
+   public String getEmail() {
+      return email;
+   }
+
+   public PublicKey getPublicKey() {
+      return publicKey;
+   }
+
+   @Override
+   public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + (displayName == null ? 0 : 
displayName.hashCode());
+      result = prime * result + (email == null ? 0 : email.hashCode());
+      result = prime * result + (firstName == null ? 0 : firstName.hashCode());
+      result = prime * result + (lastName == null ? 0 : lastName.hashCode());
+      result = prime * result + (middleName == null ? 0 : 
middleName.hashCode());
+      result = prime * result + (publicKey == null ? 0 : publicKey.hashCode());
+      result = prime * result + (username == null ? 0 : username.hashCode());
+      return result;
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) {
+         return true;
+      }
+      if (obj == null) {
+         return false;
+      }
+      if (getClass() != obj.getClass()) {
+         return false;
+      }
+      User other = (User) obj;
+      if (displayName == null) {
+         if (other.displayName != null) {
+            return false;
+         }
+      } else if (!displayName.equals(other.displayName)) {
+         return false;
+      }
+      if (email == null) {
+         if (other.email != null) {
+            return false;
+         }
+      } else if (!email.equals(other.email)) {
+         return false;
+      }
+      if (firstName == null) {
+         if (other.firstName != null) {
+            return false;
+         }
+      } else if (!firstName.equals(other.firstName)) {
+         return false;
+      }
+      if (lastName == null) {
+         if (other.lastName != null) {
+            return false;
+         }
+      } else if (!lastName.equals(other.lastName)) {
+         return false;
+      }
+      if (middleName == null) {
+         if (other.middleName != null) {
+            return false;
+         }
+      } else if (!middleName.equals(other.middleName)) {
+         return false;
+      }
+      if (publicKey == null) {
+         if (other.publicKey != null) {
+            return false;
+         }
+      } else if (!publicKey.equals(other.publicKey)) {
+         return false;
+      }
+      if (username == null) {
+         if (other.username != null) {
+            return false;
+         }
+      } else if (!username.equals(other.username)) {
+         return false;
+      }
+      return true;
+   }
+
+   @Override
+   public String toString() {
+      return "User [username=" + username + ", firstName=" + firstName + ", 
middleName=" + middleName + ", lastName="
+            + lastName + ", displayName=" + displayName + ", email=" + email + 
", publicKey=" + publicKey + "]";
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
 
b/providers/enterprise-chef/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..7861cbb
--- /dev/null
+++ 
b/providers/enterprise-chef/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.enterprisechef.EnterpriseChefProviderMetadata

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefApiExpectTest.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefApiExpectTest.java
 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefApiExpectTest.java
new file mode 100644
index 0000000..3785cf6
--- /dev/null
+++ 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefApiExpectTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.enterprisechef;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.chef.BaseChefApiExpectTest;
+import org.jclouds.chef.ChefApiMetadata;
+import org.jclouds.date.TimeStamp;
+import org.jclouds.enterprisechef.config.EnterpriseChefHttpApiModule;
+import org.jclouds.enterprisechef.domain.Group;
+import org.jclouds.enterprisechef.domain.User;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Supplier;
+import com.google.inject.Module;
+
+/**
+ * Expect tests for the {@link EnterpriseChefApi} class.
+ */
+@Test(groups = "unit", testName = "EnterpriseChefApiExpectTest")
+public class EnterpriseChefApiExpectTest extends 
BaseChefApiExpectTest<EnterpriseChefApi> {
+   public EnterpriseChefApiExpectTest() {
+      provider = "enterprisechef";
+   }
+
+   public void testGetUserReturns2xx() {
+      EnterpriseChefApi api = requestSendsResponse(
+            signed(HttpRequest.builder() //
+                  .method("GET") //
+                  .endpoint("https://api.opscode.com/users/nacx";) //
+                  .addHeader("X-Chef-Version", 
ChefApiMetadata.DEFAULT_API_VERSION) //
+                  .addHeader("Accept", MediaType.APPLICATION_JSON).build()), //
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/user.json", 
MediaType.APPLICATION_JSON)) //
+                  .build());
+
+      User user = api.getUser("nacx");
+      assertEquals(user.getUsername(), "nacx");
+      assertEquals(user.getDisplayName(), "Ignasi Barrera");
+   }
+
+   public void testGetUserReturns404() {
+      EnterpriseChefApi api = 
requestSendsResponse(signed(HttpRequest.builder() //
+            .method("GET") //
+            .endpoint("https://api.opscode.com/users/foo";) //
+            .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) 
//
+            .addHeader("Accept", MediaType.APPLICATION_JSON) //
+            .build()), //
+            HttpResponse.builder().statusCode(404).build());
+
+      assertNull(api.getUser("foo"));
+   }
+
+   public void testListGroups() {
+      EnterpriseChefApi api = requestSendsResponse(
+            signed(HttpRequest.builder() //
+                  .method("GET") //
+                  .endpoint("https://api.opscode.com/groups";) //
+                  .addHeader("X-Chef-Version", 
ChefApiMetadata.DEFAULT_API_VERSION) //
+                  .addHeader("Accept", MediaType.APPLICATION_JSON).build()), //
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/groups.json", 
MediaType.APPLICATION_JSON)) //
+                  .build());
+
+      Set<String> groups = api.listGroups();
+      assertEquals(groups.size(), 5);
+      assertTrue(groups.contains("admins"));
+   }
+
+   public void testGetGroupReturns2xx() {
+      EnterpriseChefApi api = requestSendsResponse(
+            signed(HttpRequest.builder() //
+                  .method("GET") //
+                  .endpoint("https://api.opscode.com/groups/admins";) //
+                  .addHeader("X-Chef-Version", 
ChefApiMetadata.DEFAULT_API_VERSION) //
+                  .addHeader("Accept", MediaType.APPLICATION_JSON).build()), //
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/group.json", 
MediaType.APPLICATION_JSON)) //
+                  .build());
+
+      Group group = api.getGroup("admins");
+      assertEquals(group.getName(), "admins");
+      assertEquals(group.getGroupname(), "admins");
+   }
+
+   public void testGetGroupReturns404() {
+      EnterpriseChefApi api = 
requestSendsResponse(signed(HttpRequest.builder() //
+            .method("GET") //
+            .endpoint("https://api.opscode.com/groups/foo";) //
+            .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) 
//
+            .addHeader("Accept", MediaType.APPLICATION_JSON) //
+            .build()), //
+            HttpResponse.builder().statusCode(404).build());
+
+      assertNull(api.getGroup("foo"));
+   }
+
+   public void testCreateGroupReturns2xx() {
+      EnterpriseChefApi api = 
requestSendsResponse(signed(HttpRequest.builder() //
+            .method("POST") //
+            .endpoint("https://api.opscode.com/groups";) //
+            .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) 
//
+            .addHeader("Accept", MediaType.APPLICATION_JSON) //
+            
.payload(payloadFromStringWithContentType("{\"groupname\":\"foo\"}", 
MediaType.APPLICATION_JSON)) //
+            .build()), //
+            HttpResponse.builder().statusCode(201).build());
+
+      api.createGroup("foo");
+   }
+
+   public void testDeleteGroupReturns2xx() {
+      EnterpriseChefApi api = 
requestSendsResponse(signed(HttpRequest.builder() //
+            .method("DELETE") //
+            .endpoint("https://api.opscode.com/groups/foo";) //
+            .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) 
//
+            .addHeader("Accept", MediaType.APPLICATION_JSON) //
+            .build()), //
+            HttpResponse.builder().statusCode(200).build());
+
+      api.deleteGroup("foo");
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testDeleteGroupFailsOn404() {
+      EnterpriseChefApi api = 
requestSendsResponse(signed(HttpRequest.builder() //
+            .method("DELETE") //
+            .endpoint("https://api.opscode.com/groups/foo";) //
+            .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) 
//
+            .addHeader("Accept", MediaType.APPLICATION_JSON) //
+            .build()), //
+            HttpResponse.builder().statusCode(404).build());
+
+      api.deleteGroup("foo");
+   }
+
+   public void testUpdateGroupReturns2xx() {
+      EnterpriseChefApi api = 
requestSendsResponse(signed(HttpRequest.builder() //
+            .method("PUT") //
+            .endpoint("https://api.opscode.com/groups/admins";) //
+            .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) 
//
+            .addHeader("Accept", MediaType.APPLICATION_JSON) //
+            .payload(payloadFromResourceWithContentType("/group-update.json", 
MediaType.APPLICATION_JSON)) //
+            .build()), //
+            HttpResponse.builder().statusCode(200).build());
+
+      Group group = 
Group.builder("admins").client("abiquo").group("admins").user("nacx").build();
+      api.updateGroup(group);
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testUpdateGroupFailsOn404() {
+      EnterpriseChefApi api = 
requestSendsResponse(signed(HttpRequest.builder() //
+            .method("PUT") //
+            .endpoint("https://api.opscode.com/groups/admins";) //
+            .addHeader("X-Chef-Version", ChefApiMetadata.DEFAULT_API_VERSION) 
//
+            .addHeader("Accept", MediaType.APPLICATION_JSON) //
+            .payload(payloadFromResourceWithContentType("/group-update.json", 
MediaType.APPLICATION_JSON)) //
+            .build()), //
+            HttpResponse.builder().statusCode(404).build());
+
+      Group group = 
Group.builder("admins").client("abiquo").group("admins").user("nacx").build();
+      api.updateGroup(group);
+   }
+
+   @Override
+   protected Module createModule() {
+      return new TestEnterpriseChefRestClientModule();
+   }
+
+   @ConfiguresRestClient
+   static class TestEnterpriseChefRestClientModule extends 
EnterpriseChefHttpApiModule {
+      @Override
+      protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
+         return "timestamp";
+      }
+   }
+
+   @Override
+   protected ProviderMetadata createProviderMetadata() {
+      return new EnterpriseChefProviderMetadata();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefApiLiveTest.java
 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefApiLiveTest.java
new file mode 100644
index 0000000..6ac99c1
--- /dev/null
+++ 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefApiLiveTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.enterprisechef;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+import java.util.UUID;
+
+import org.jclouds.chef.internal.BaseChefApiLiveTest;
+import org.jclouds.enterprisechef.domain.Group;
+import org.jclouds.enterprisechef.domain.User;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of the EnterpriseChefApi.
+ */
+@Test(groups = "live", singleThreaded = true, testName = 
"EnterpriseChefApiLiveTest")
+public class EnterpriseChefApiLiveTest extends 
BaseChefApiLiveTest<EnterpriseChefApi> {
+
+   private static final String GROUP_NAME = System.getProperty("user.name") + 
"-jcloudstest";
+   private static final String ORG_NAME = 
System.getProperty("test.enterprisechef.org");
+
+   public EnterpriseChefApiLiveTest() {
+      provider = "enterprisechef";
+   }
+
+   @Override
+   @Test
+   public void testSearchClientsWithOptions() throws Exception {
+      // This test will fail because Enterprise Chef does not index client 
name.
+      // Once it is fixes, the test should succeed.
+      // See: http://tickets.opscode.com/browse/CHEF-2477
+      super.testSearchClientsWithOptions();
+   }
+
+   public void testGetUser() {
+      User user = api.getUser(identity);
+      assertEquals(user.getUsername(), identity);
+      assertNotNull(user.getPublicKey());
+   }
+
+   public void testGetUnexistingUser() {
+      User user = api.getUser(UUID.randomUUID().toString());
+      assertNull(user);
+   }
+
+   public void testListGroups() {
+      Set<String> groups = api.listGroups();
+      assertNotNull(groups);
+      assertFalse(groups.isEmpty());
+   }
+
+   public void testGetUnexistingGroup() {
+      Group group = api.getGroup(UUID.randomUUID().toString());
+      assertNull(group);
+   }
+
+   public void testCreateGroup() {
+      api.createGroup(GROUP_NAME);
+      Group group = api.getGroup(GROUP_NAME);
+      assertNotNull(group);
+      assertEquals(group.getGroupname(), GROUP_NAME);
+   }
+
+   @Test(dependsOnMethods = "testCreateGroup")
+   public void testUpdateGroup() {
+      Group group = api.getGroup(GROUP_NAME);
+      Group updated = Group.builder(group.getGroupname()) //
+            .actors(group.getActors()) //
+            .orgname(group.getOrgname()) //
+            .name(group.getName()) //
+            .groups(group.getGroups()) //
+            .client(ORG_NAME + "-validator") //
+            .user(identity) //
+            .build();
+
+      api.updateGroup(updated);
+      group = api.getGroup(GROUP_NAME);
+
+      assertNotNull(group);
+      assertTrue(group.getUsers().contains(identity));
+      assertTrue(group.getClients().contains(ORG_NAME + "-validator"));
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testUpdateUnexistingGroup() {
+      api.updateGroup(Group.builder(UUID.randomUUID().toString()).build());
+   }
+
+   @Test(dependsOnMethods = "testUpdateGroup")
+   public void testDeleteGroup() {
+      api.deleteGroup(GROUP_NAME);
+      Group group = api.getGroup(GROUP_NAME);
+      assertNull(group);
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testDeleteUnexistingGroup() {
+      api.deleteGroup(UUID.randomUUID().toString());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefProviderMetadataTest.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefProviderMetadataTest.java
 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefProviderMetadataTest.java
new file mode 100644
index 0000000..9675af8
--- /dev/null
+++ 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/EnterpriseChefProviderMetadataTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.enterprisechef;
+
+import org.jclouds.providers.internal.BaseProviderMetadataTest;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link EnterpriseChefProviderMetadata} class.
+ */
+@Test(groups = "unit", testName = "EnterpriseChefProviderTest")
+public class EnterpriseChefProviderMetadataTest extends 
BaseProviderMetadataTest {
+
+   public EnterpriseChefProviderMetadataTest() {
+      super(new EnterpriseChefProviderMetadata(), new 
EnterpriseChefApiMetadata());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/binders/BindGroupToUpdateRequestJsonPayloadTest.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/binders/BindGroupToUpdateRequestJsonPayloadTest.java
 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/binders/BindGroupToUpdateRequestJsonPayloadTest.java
new file mode 100644
index 0000000..4e9a3c2
--- /dev/null
+++ 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/binders/BindGroupToUpdateRequestJsonPayloadTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.enterprisechef.binders;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jclouds.chef.ChefApiMetadata;
+import org.jclouds.chef.config.ChefParserModule;
+import org.jclouds.enterprisechef.domain.Group;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.rest.annotations.ApiVersion;
+import org.jclouds.util.Strings2;
+import org.testng.annotations.Test;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * Unit tests for the {@link BindGroupToUpdateRequestJsonPayload} class.
+ */
+@Test(groups = "unit", testName = "BindGroupToUpdateRequestJsonPayloadTest")
+public class BindGroupToUpdateRequestJsonPayloadTest {
+
+   private Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+         
bind(String.class).annotatedWith(ApiVersion.class).toInstance(ChefApiMetadata.DEFAULT_API_VERSION);
+      }
+   }, new ChefParserModule(), new GsonModule());
+
+   private BindGroupToUpdateRequestJsonPayload binder = 
injector.getInstance(BindGroupToUpdateRequestJsonPayload.class);
+
+   @Test(expectedExceptions = NullPointerException.class)
+   public void testInvalidNullInput() {
+      HttpRequest request = 
HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost";)).build();
+      binder.bindToRequest(request, null);
+   }
+
+   @Test(expectedExceptions = IllegalArgumentException.class)
+   public void testInvalidTypeInput() {
+      HttpRequest request = 
HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost";)).build();
+      binder.bindToRequest(request, new Object());
+   }
+
+   public void testBindOnlyName() throws IOException {
+      HttpRequest request = 
HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost";)).build();
+      HttpRequest newRequest = binder.bindToRequest(request, 
Group.builder("foo").build());
+
+      String payload = 
Strings2.toStringAndClose(newRequest.getPayload().getInput());
+      assertEquals(payload, 
"{\"groupname\":\"foo\",\"actors\":{\"clients\":[],\"groups\":[],\"users\":[]}}");
+   }
+
+   public void testBindNameAndLists() throws IOException {
+      Group group = 
Group.builder("foo").client("nacx-validator").group("admins").user("nacx").build();
+
+      HttpRequest request = 
HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost";)).build();
+      HttpRequest newRequest = binder.bindToRequest(request, group);
+
+      String payload = 
Strings2.toStringAndClose(newRequest.getPayload().getInput());
+      assertEquals(payload,
+            
"{\"groupname\":\"foo\",\"actors\":{\"clients\":[\"nacx-validator\"],\"groups\":[\"admins\"],\"users\":[\"nacx\"]}}");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/binders/GroupNameTest.java
----------------------------------------------------------------------
diff --git 
a/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/binders/GroupNameTest.java
 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/binders/GroupNameTest.java
new file mode 100644
index 0000000..98ea715
--- /dev/null
+++ 
b/providers/enterprise-chef/src/test/java/org/jclouds/enterprisechef/binders/GroupNameTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.enterprisechef.binders;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.jclouds.enterprisechef.domain.Group;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link GroupName} class.
+ */
+@Test(groups = "unit", testName = "GroupNameTest")
+public class GroupNameTest {
+
+   @Test(expectedExceptions = NullPointerException.class)
+   public void testInvalidNullInput() {
+      new GroupName().apply(null);
+   }
+
+   public void testApplyGroupName() throws IOException {
+      assertEquals(new GroupName().apply(Group.builder("foo").build()), "foo");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/resources/group-update.json
----------------------------------------------------------------------
diff --git a/providers/enterprise-chef/src/test/resources/group-update.json 
b/providers/enterprise-chef/src/test/resources/group-update.json
new file mode 100644
index 0000000..cc7bf6a
--- /dev/null
+++ b/providers/enterprise-chef/src/test/resources/group-update.json
@@ -0,0 +1 @@
+{"groupname":"admins","actors":{"clients":["abiquo"],"groups":["admins"],"users":["nacx"]}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/resources/group.json
----------------------------------------------------------------------
diff --git a/providers/enterprise-chef/src/test/resources/group.json 
b/providers/enterprise-chef/src/test/resources/group.json
new file mode 100644
index 0000000..df3eb28
--- /dev/null
+++ b/providers/enterprise-chef/src/test/resources/group.json
@@ -0,0 +1,14 @@
+{
+  "actors" : [ "abiquo",
+      "nacx",
+      "pivotal"
+    ],
+  "clients" : [ "abiquo" ],
+  "groupname" : "admins",
+  "groups" : [ "billing-admins" ],
+  "name" : "admins",
+  "orgname" : "nacx",
+  "users" : [ "nacx",
+      "pivotal"
+  ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/resources/groups.json
----------------------------------------------------------------------
diff --git a/providers/enterprise-chef/src/test/resources/groups.json 
b/providers/enterprise-chef/src/test/resources/groups.json
new file mode 100644
index 0000000..30c8aa6
--- /dev/null
+++ b/providers/enterprise-chef/src/test/resources/groups.json
@@ -0,0 +1,7 @@
+{
+  "965f2db33d302ed4625d172e0bc36920" : 
"https://api.opscode.com/organizations/nacx/groups/965f2db33d302ed4625d172e0bc36920";,
+  "admins" : "https://api.opscode.com/organizations/nacx/groups/admins";,
+  "billing-admins" : 
"https://api.opscode.com/organizations/nacx/groups/billing-admins";,
+  "clients" : "https://api.opscode.com/organizations/nacx/groups/clients";,
+  "users" : "https://api.opscode.com/organizations/nacx/groups/users";
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/enterprise-chef/src/test/resources/user.json
----------------------------------------------------------------------
diff --git a/providers/enterprise-chef/src/test/resources/user.json 
b/providers/enterprise-chef/src/test/resources/user.json
new file mode 100644
index 0000000..ee35a95
--- /dev/null
+++ b/providers/enterprise-chef/src/test/resources/user.json
@@ -0,0 +1,9 @@
+{
+  "display_name" : "Ignasi Barrera",
+  "email" : "[email protected]",
+  "first_name" : "Ignasi",
+  "last_name" : "Barrera",
+  "middle_name" : "",
+  "public_key" : "-----BEGIN RSA PUBLIC 
KEY-----\nMIIBCgKCAQEAp0ytgXbPzqJwOOixn7bTa6VAiNvVIOn+yDPoWbyEfc0li93BHIwv\n01KW/mn55IXnSbMw86rdxisvwPHFfb7URuKuTzME6yrphBiancmNjushZZeBWb8j\nqJhnFIKbaaOqew0LZSyG9ycYODB/HDK/pWTV4Bd1OtLHBNFrnIf+r3HOjJsa4rmK\nWXgSQIQO7be/iRHysApV9tfVH8lo1ETnA08JTrQwDgo9St9YNbydb5V0CiLiQsOa\nIbY09buUK9lXthh/rrRVbGbSwQM6OYdXIEZTN2BFvQ0p5pH8AiTwFqb0ICO46a0S\njfGcXNjC/QfHljAPY3T5xyIOODM8afHCnwIDAQAB\n-----END
 RSA PUBLIC KEY-----\n",
+  "username" : "nacx"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/providers/pom.xml
----------------------------------------------------------------------
diff --git a/providers/pom.xml b/providers/pom.xml
index 2f64ce5..2fec399 100644
--- a/providers/pom.xml
+++ b/providers/pom.xml
@@ -79,5 +79,6 @@
     <module>aws-route53</module>
     <module>ultradns-ws</module>
     <module>dynect</module>
+    <module>enterprise-chef</module>
   </modules>
 </project>

Reply via email to