You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2018/01/16 08:12:42 UTC

[4/9] jclouds git commit: Add support for OpenStack Keystone V3

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneApiLiveTest.java
index ee85a5e..004d813 100644
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneApiLiveTest.java
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneApiLiveTest.java
@@ -19,8 +19,8 @@ package org.jclouds.openstack.keystone.v2_0.internal;
 import java.util.Properties;
 
 import org.jclouds.apis.BaseApiLiveTest;
+import org.jclouds.openstack.keystone.config.KeystoneProperties;
 import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
-import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
 import org.testng.annotations.Test;
 
 /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneRestApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneRestApiExpectTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneRestApiExpectTest.java
index 01fc644..1f19d96 100644
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneRestApiExpectTest.java
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/internal/BaseKeystoneRestApiExpectTest.java
@@ -16,7 +16,7 @@
  */
 package org.jclouds.openstack.keystone.v2_0.internal;
 
-import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.SERVICE_TYPE;
 
 import java.util.Properties;
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/LocationIdToURIFromAccessForTypeAndVersionTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/LocationIdToURIFromAccessForTypeAndVersionTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/LocationIdToURIFromAccessForTypeAndVersionTest.java
deleted file mode 100644
index f530329..0000000
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/LocationIdToURIFromAccessForTypeAndVersionTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.openstack.keystone.v2_0.suppliers;
-
-import static org.testng.Assert.assertEquals;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import javax.inject.Singleton;
-
-import org.jclouds.location.Provider;
-import org.jclouds.openstack.keystone.v2_0.domain.Access;
-import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
-import org.jclouds.openstack.keystone.v2_0.functions.EndpointToRegion;
-import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
-import org.jclouds.openstack.keystone.v2_0.parse.ParseRackspaceAccessTest;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Function;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Provides;
-import com.google.inject.TypeLiteral;
-import com.google.inject.assistedinject.FactoryModuleBuilder;
-
-@Test(groups = "unit", testName = "LocationIdToURIFromAccessForTypeAndVersionTest")
-public class LocationIdToURIFromAccessForTypeAndVersionTest {
-   private final LocationIdToURIFromAccessForTypeAndVersion.Factory factory = Guice.createInjector(new AbstractModule() {
-
-      @Override
-      protected void configure() {
-         bindConstant().annotatedWith(Provider.class).to("openstack-keystone");
-         bind(new TypeLiteral<Supplier<URI>>() {
-         }).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
-         bind(new TypeLiteral<Function<Endpoint, String>>(){}).to(EndpointToRegion.class);
-         install(new FactoryModuleBuilder().implement(LocationIdToURIFromAccessForTypeAndVersion.class,
-                  LocationIdToURIFromAccessForTypeAndVersion.class).build(
-                  LocationIdToURIFromAccessForTypeAndVersion.Factory.class));
-      }
-
-      @Provides
-      @Singleton
-      public Supplier<Access> provide() {
-         return Suppliers.ofInstance(new ParseAccessTest().expected());
-      }
-
-   }).getInstance(LocationIdToURIFromAccessForTypeAndVersion.Factory.class);
-
-   public void testRegionUnmatchesOkWhenNoVersionIdSet() {
-      assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "2").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("az-1.region-a.geo-1", URI
-               .create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-2.region-a.geo-1", URI
-               .create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-3.region-a.geo-1", URI
-               .create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v2/3456")));
-   }
-
-   public void testRegionMatches() {
-      assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "2").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("az-1.region-a.geo-1", URI
-               .create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-2.region-a.geo-1", URI
-               .create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-3.region-a.geo-1", URI
-               .create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v2/3456")));
-   }
-
-   private final LocationIdToURIFromAccessForTypeAndVersion.Factory raxFactory = Guice.createInjector(new AbstractModule() {
-
-      @Override
-      protected void configure() {
-         bindConstant().annotatedWith(Provider.class).to("rackspace");
-         bind(new TypeLiteral<Supplier<URI>>() {
-         }).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
-         bind(new TypeLiteral<Function<Endpoint, String>>(){}).to(EndpointToRegion.class);
-         install(new FactoryModuleBuilder().implement(LocationIdToURIFromAccessForTypeAndVersion.class,
-                  LocationIdToURIFromAccessForTypeAndVersion.class).build(
-                  LocationIdToURIFromAccessForTypeAndVersion.Factory.class));
-      }
-
-      @Provides
-      @Singleton
-      public Supplier<Access> provide() {
-         return Suppliers.ofInstance(new ParseRackspaceAccessTest().expected());
-      }
-   }).getInstance(LocationIdToURIFromAccessForTypeAndVersion.Factory.class);
-
-   @Test(expectedExceptions = NoSuchElementException.class)
-   public void testWhenNotInList() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("goo", "1.0").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("rackspace", URI
-               .create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-
-   public void testProviderWhenNoRegions() {
-      Map<String, URI> withNoRegions = Maps.transformValues(raxFactory.createForApiTypeAndVersion("compute", "1.0")
-            .get(), Suppliers.<URI> supplierFunction());
-      assertEquals(withNoRegions, ImmutableMap.of("rackspace", URI
-               .create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-
-   public void testOkWithNoVersions() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("rax:database", null).get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("DFW", URI
-               .create("https://dfw.databases.api.rackspacecloud.com/v1.0/40806637803162"), "ORD", URI
-               .create("https://ord.databases.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToAdminURIFromAccessForTypeAndVersionTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToAdminURIFromAccessForTypeAndVersionTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToAdminURIFromAccessForTypeAndVersionTest.java
deleted file mode 100644
index 91ebb61..0000000
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToAdminURIFromAccessForTypeAndVersionTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.openstack.keystone.v2_0.suppliers;
-
-import static org.testng.Assert.assertEquals;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import javax.inject.Singleton;
-
-import org.jclouds.location.Provider;
-import org.jclouds.openstack.keystone.v2_0.domain.Access;
-import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
-import org.jclouds.openstack.keystone.v2_0.parse.ParseRackspaceAccessTest;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Provides;
-import com.google.inject.TypeLiteral;
-import com.google.inject.assistedinject.FactoryModuleBuilder;
-
-@Test(groups = "unit", testName = "RegionIdToAdminURIFromAccessForTypeAndVersionTest")
-public class RegionIdToAdminURIFromAccessForTypeAndVersionTest {
-   private final RegionIdToAdminURISupplier.Factory factory = Guice.createInjector(new AbstractModule() {
-
-      @Override
-      protected void configure() {
-         bindConstant().annotatedWith(Provider.class).to("openstack-keystone");
-         bind(new TypeLiteral<Supplier<URI>>() {
-         }).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
-         install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
-                  RegionIdToAdminURIFromAccessForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
-      }
-
-      @Provides
-      @Singleton
-      public Supplier<Access> provide() {
-         return Suppliers.ofInstance(new ParseAccessTest().expected());
-      }
-   }).getInstance(RegionIdToAdminURISupplier.Factory.class);
-
-   public void testRegionMatches() {
-      assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("identity", "2.0").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("region-a.geo-1", URI.create("https://csnode.jclouds.org:35357/v2.0/")));
-      Map<String, URI> map = Maps.newLinkedHashMap();
-      map.put("region-a.geo-1", null);
-      map.put("region-b.geo-1", null);
-      map.put("region-c.geo-1", null);
-      assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "2").get(), Suppliers
-               .<URI> supplierFunction()), map);
-   }
-   
-   private final RegionIdToAdminURISupplier.Factory raxFactory = Guice.createInjector(new AbstractModule() {
-
-      @Override
-      protected void configure() {
-         bindConstant().annotatedWith(Provider.class).to("rackspace");
-         bind(new TypeLiteral<Supplier<URI>>() {
-         }).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
-         install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
-                  RegionIdToAdminURIFromAccessForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
-      }
-
-      @Provides
-      @Singleton
-      public Supplier<Access> provide() {
-         return Suppliers.ofInstance(new ParseRackspaceAccessTest().expected());
-      }
-   }).getInstance(RegionIdToAdminURISupplier.Factory.class);
-
-   @Test(expectedExceptions = NoSuchElementException.class)
-   public void testWhenNotInList() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("goo", "1.0").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("rackspace", URI
-               .create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-   
-   public void testProviderWhenNoRegions() {
-      Map<String, URI> map = Maps.newLinkedHashMap();
-      map.put("rackspace", null);
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("compute", "1.0").get(), Suppliers
-               .<URI> supplierFunction()), map);
-   }
-   
-   public void testOkWithNoVersions() {
-      Map<String, URI> map = Maps.newLinkedHashMap();
-      map.put("DFW", null);
-      map.put("ORD", null);
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("rax:database", null).get(), Suppliers
-               .<URI> supplierFunction()), map);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToURIFromAccessForTypeAndVersionTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToURIFromAccessForTypeAndVersionTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToURIFromAccessForTypeAndVersionTest.java
deleted file mode 100644
index 0b48360..0000000
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToURIFromAccessForTypeAndVersionTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.openstack.keystone.v2_0.suppliers;
-
-import static org.testng.Assert.assertEquals;
-
-import java.net.URI;
-import java.util.NoSuchElementException;
-
-import javax.inject.Singleton;
-
-import org.jclouds.location.Provider;
-import org.jclouds.location.suppliers.RegionIdToURISupplier;
-import org.jclouds.openstack.keystone.v2_0.domain.Access;
-import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
-import org.jclouds.openstack.keystone.v2_0.parse.ParseRackspaceAccessTest;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Provides;
-import com.google.inject.TypeLiteral;
-import com.google.inject.assistedinject.FactoryModuleBuilder;
-
-@Test(groups = "unit", testName = "RegionIdToURIFromAccessForTypeAndVersionTest")
-public class RegionIdToURIFromAccessForTypeAndVersionTest {
-   private final RegionIdToURISupplier.Factory factory = Guice.createInjector(new AbstractModule() {
-
-      @Override
-      protected void configure() {
-         bindConstant().annotatedWith(Provider.class).to("openstack-keystone");
-         bind(new TypeLiteral<Supplier<URI>>() {
-         }).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
-         install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
-                  RegionIdToURIFromAccessForTypeAndVersion.class).build(
-                  RegionIdToURISupplier.Factory.class));
-      }
-
-      @Provides
-      @Singleton
-      public Supplier<Access> provide() {
-         return Suppliers.ofInstance(new ParseAccessTest().expected());
-      }
-   }).getInstance(RegionIdToURISupplier.Factory.class);
-
-   @SuppressWarnings("CheckReturnValue")
-   @Test(expectedExceptions = NoSuchElementException.class)
-   public void testRegionUnmatches() {
-      Maps.transformValues(factory.createForApiTypeAndVersion("compute", "1.0").get(),
-               Suppliers.<URI> supplierFunction());
-   }
-   
-   public void testRegionMatches() {
-      assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "2").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("az-1.region-a.geo-1", URI
-               .create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-2.region-a.geo-1", URI
-               .create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-3.region-a.geo-1", URI
-               .create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v2/3456")));
-   }
-
-   private final RegionIdToURISupplier.Factory raxFactory = Guice.createInjector(new AbstractModule() {
-
-      @Override
-      protected void configure() {
-         bindConstant().annotatedWith(Provider.class).to("rackspace");
-         bind(new TypeLiteral<Supplier<URI>>() {
-         }).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
-         install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
-                  RegionIdToURIFromAccessForTypeAndVersion.class).build(
-                  RegionIdToURISupplier.Factory.class));
-      }
-
-      @Provides
-      @Singleton
-      public Supplier<Access> provide() {
-         return Suppliers.ofInstance(new ParseRackspaceAccessTest().expected());
-      }
-   }).getInstance(RegionIdToURISupplier.Factory.class);
-
-   @Test(expectedExceptions = NoSuchElementException.class)
-   public void testWhenNotInList() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("goo", "1.0").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("rackspace", URI
-               .create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-
-   public void testProviderWhenNoRegions() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("compute", "1.0").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("rackspace", URI
-               .create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-
-   public void testOkWithNoVersions() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("rax:database", null).get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("DFW", URI
-               .create("https://dfw.databases.api.rackspacecloud.com/v1.0/40806637803162"), "ORD", URI
-               .create("https://ord.databases.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/ZoneIdToURIFromAccessForTypeAndVersionTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/ZoneIdToURIFromAccessForTypeAndVersionTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/ZoneIdToURIFromAccessForTypeAndVersionTest.java
deleted file mode 100644
index b716bbc..0000000
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/suppliers/ZoneIdToURIFromAccessForTypeAndVersionTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.openstack.keystone.v2_0.suppliers;
-
-import static org.testng.Assert.assertEquals;
-
-import java.net.URI;
-import java.util.NoSuchElementException;
-
-import javax.inject.Singleton;
-
-import org.jclouds.location.Provider;
-import org.jclouds.location.suppliers.ZoneIdToURISupplier;
-import org.jclouds.openstack.keystone.v2_0.domain.Access;
-import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
-import org.jclouds.openstack.keystone.v2_0.parse.ParseRackspaceAccessTest;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Provides;
-import com.google.inject.TypeLiteral;
-import com.google.inject.assistedinject.FactoryModuleBuilder;
-
-@Test(groups = "unit", testName = "ZoneIdToURIFromAccessForTypeAndVersionSupplierTest")
-public class ZoneIdToURIFromAccessForTypeAndVersionTest {
-   private final ZoneIdToURISupplier.Factory factory = Guice.createInjector(new AbstractModule() {
-
-      @Override
-      protected void configure() {
-         bindConstant().annotatedWith(Provider.class).to("rackspace");
-         bind(new TypeLiteral<Supplier<URI>>() {
-         }).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));         
-         install(new FactoryModuleBuilder().implement(ZoneIdToURISupplier.class,
-                  ZoneIdToURIFromAccessForTypeAndVersion.class).build(ZoneIdToURISupplier.Factory.class));
-      }
-
-      @Provides
-      @Singleton
-      public Supplier<Access> provide() {
-         return Suppliers.ofInstance(new ParseAccessTest().expected());
-      }
-   }).getInstance(ZoneIdToURISupplier.Factory.class);
-
-
-   @SuppressWarnings("CheckReturnValue")
-   @Test(expectedExceptions = NoSuchElementException.class)
-   public void testZoneUnmatches() {
-      Maps.transformValues(factory.createForApiTypeAndVersion("compute", "1.0").get(),
-               Suppliers.<URI> supplierFunction());
-   }
-  
-   public void testZoneMatches() {
-      assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("compute", "2").get(), Suppliers
-            .<URI> supplierFunction()), ImmutableMap.of("az-1.region-a.geo-1", URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"),
-                                                        "az-2.region-a.geo-1", URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"),
-                                                        "az-3.region-a.geo-1", URI.create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v2/3456")));
-   }
-   
-   private final ZoneIdToURISupplier.Factory raxFactory = Guice.createInjector(new AbstractModule() {
-
-      @Override
-      protected void configure() {
-         bindConstant().annotatedWith(Provider.class).to("rackspace");
-         bind(new TypeLiteral<Supplier<URI>>() {
-         }).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));        
-         install(new FactoryModuleBuilder().implement(ZoneIdToURISupplier.class,
-                  ZoneIdToURIFromAccessForTypeAndVersion.class).build(ZoneIdToURISupplier.Factory.class));
-      }
-
-      @Provides
-      @Singleton
-      public Supplier<Access> provide() {
-         return Suppliers.ofInstance(new ParseRackspaceAccessTest().expected());
-      }
-   }).getInstance(ZoneIdToURISupplier.Factory.class);
-
-   @Test(expectedExceptions = NoSuchElementException.class)
-   public void testWhenNotInList() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("goo", "1.0").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("rackspace", URI
-               .create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-
-   public void testProviderWhenNoZones() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("compute", "1.0").get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("rackspace", URI.create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-   
-   public void testOkWithNoVersions() {
-      assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("rax:database", null).get(), Suppliers
-               .<URI> supplierFunction()), ImmutableMap.of("DFW", URI.create("https://dfw.databases.api.rackspacecloud.com/v1.0/40806637803162"),
-                                                           "ORD", URI.create("https://ord.databases.api.rackspacecloud.com/v1.0/40806637803162")));
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/auth/V3AuthenticationApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/auth/V3AuthenticationApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/auth/V3AuthenticationApiLiveTest.java
new file mode 100644
index 0000000..3b8a3b4
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/auth/V3AuthenticationApiLiveTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.openstack.keystone.v3.auth;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
+import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
+import org.jclouds.openstack.keystone.auth.domain.TokenCredentials;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiLiveTest;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+
+@Test(groups = "live", testName = "V3AuthenticationApiLiveTest")
+public class V3AuthenticationApiLiveTest extends BaseV3KeystoneApiLiveTest {
+
+   private String tenant;
+   private String user;
+
+   @Override
+   protected Properties setupProperties() {
+      Properties properties = super.setupProperties();
+      tenant = Iterables.get(Splitter.on(":").split(identity), 0);
+      user = Iterables.get(Splitter.on(":").split(identity), 1);
+      return properties;
+   }
+
+   public void testAuthenticatePassword() {
+      assertNotNull(authenticationApi.authenticatePassword(TenantOrDomainAndCredentials.<PasswordCredentials> builder()
+            .tenantOrDomainName(tenant).scope("unscoped")
+            .credentials(PasswordCredentials.builder().username(user).password(credential).build()).build()));
+   }
+
+   public void testAuthenticateToken() {
+      assertNotNull(authenticationApi.authenticateToken(TenantOrDomainAndCredentials.<TokenCredentials> builder()
+            .tenantOrDomainName(tenant).scope("unscoped")
+            .credentials(TokenCredentials.builder().id(token.get()).build()).build()));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/auth/V3AuthenticationApiMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/auth/V3AuthenticationApiMockTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/auth/V3AuthenticationApiMockTest.java
new file mode 100644
index 0000000..d601913
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/auth/V3AuthenticationApiMockTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.openstack.keystone.v3.auth;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
+import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
+import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
+import org.jclouds.openstack.keystone.auth.domain.TokenCredentials;
+import org.jclouds.openstack.keystone.v3.domain.Token;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiMockTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "V3AuthenticationApiMockTest", singleThreaded = true)
+public class V3AuthenticationApiMockTest extends BaseV3KeystoneApiMockTest {
+
+   public void testAuthenticatePassword() throws InterruptedException {
+      server.enqueue(jsonResponse("/v3/token.json"));
+
+      TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials.<PasswordCredentials> builder()
+            .tenantOrDomainName("domain")
+            .scope("unscoped")
+            .credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
+      
+      AuthInfo authInfo = authenticationApi.authenticatePassword(credentials);
+
+      assertTrue(authInfo instanceof Token);
+      assertEquals(authInfo, tokenFromResource("/v3/token.json"));
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "/auth/tokens", stringFromResource("/v3/auth-password.json"));
+   }
+   
+   public void testAuthenticatePasswordScoped() throws InterruptedException {
+      server.enqueue(jsonResponse("/v3/token.json"));
+
+      TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials.<PasswordCredentials> builder()
+            .tenantOrDomainName("domain")
+            .scope("projectId:1234567890")
+            .credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
+      
+      AuthInfo authInfo = authenticationApi.authenticatePassword(credentials);
+
+      assertTrue(authInfo instanceof Token);
+      assertEquals(authInfo, tokenFromResource("/v3/token.json"));
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "/auth/tokens", stringFromResource("/v3/auth-password-scoped.json"));
+   }
+
+   public void testAuthenticateToken() throws InterruptedException {
+      server.enqueue(jsonResponse("/v3/token.json"));
+
+      TenantOrDomainAndCredentials<TokenCredentials> credentials = TenantOrDomainAndCredentials.<TokenCredentials> builder()
+            .tenantOrDomainName("domain")
+            .scope("unscoped")
+            .credentials(TokenCredentials.builder().id("token").build()).build();
+      
+      AuthInfo authInfo = authenticationApi.authenticateToken(credentials);
+
+      assertTrue(authInfo instanceof Token);
+      assertEquals(authInfo, tokenFromResource("/v3/token.json"));
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "/auth/tokens", stringFromResource("/v3/auth-token.json"));
+   }
+   
+   public void testAuthenticateTokenScoped() throws InterruptedException {
+      server.enqueue(jsonResponse("/v3/token.json"));
+
+      TenantOrDomainAndCredentials<TokenCredentials> credentials = TenantOrDomainAndCredentials.<TokenCredentials> builder()
+            .tenantOrDomainName("domain")
+            .scope("domain:mydomain")
+            .credentials(TokenCredentials.builder().id("token").build()).build();
+      
+      AuthInfo authInfo = authenticationApi.authenticateToken(credentials);
+
+      assertTrue(authInfo instanceof Token);
+      assertEquals(authInfo, tokenFromResource("/v3/token.json"));
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "/auth/tokens", stringFromResource("/v3/auth-token-scoped.json"));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/AuthApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/AuthApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/AuthApiLiveTest.java
new file mode 100644
index 0000000..2cfef51
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/AuthApiLiveTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "AuthApiLiveTest")
+public class AuthApiLiveTest extends BaseV3KeystoneApiLiveTest {
+
+   public void testIsTokenValid() {
+      assertTrue(api().isValid(token.get()));
+   }
+
+   public void testGetToken() {
+      assertNotNull(api().get(token.get()));
+   }
+
+   private AuthApi api() {
+      return api.getAuthApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/AuthApiMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/AuthApiMockTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/AuthApiMockTest.java
new file mode 100644
index 0000000..a156fad
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/AuthApiMockTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.openstack.keystone.v3.domain.Token;
+import org.jclouds.openstack.keystone.v3.domain.User;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiMockTest;
+import org.testng.annotations.Test;
+
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
+
+@Test(groups = "unit", testName = "AuthApiMockTest", singleThreaded = true)
+public class AuthApiMockTest extends BaseV3KeystoneApiMockTest {
+
+   public void testGetToken() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/token.json"));
+
+      Token token = api.getAuthApi().get(authToken);
+
+      assertEquals(token, tokenFromResource("/v3/token.json"));
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      RecordedRequest request = assertSent(server, "GET", "/auth/tokens");
+      assertEquals(request.getHeader("X-Subject-Token"), authToken);
+   }
+
+   public void testGetTokenReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      Token token = api.getAuthApi().get("foo");
+      assertNull(token);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      RecordedRequest request = assertSent(server, "GET", "/auth/tokens");
+      assertEquals(request.getHeader("X-Subject-Token"), "foo");
+   }
+   
+   public void testIsValidToken() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response204());
+
+      boolean valid = api.getAuthApi().isValid(authToken);
+      assertTrue(valid);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      RecordedRequest request = assertSent(server, "HEAD", "/auth/tokens");
+      assertEquals(request.getHeader("X-Subject-Token"), authToken);
+   }
+
+   public void testIsValidTokenReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      boolean valid = api.getAuthApi().isValid("foo");
+      assertFalse(valid);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      RecordedRequest request = assertSent(server, "HEAD", "/auth/tokens");
+      assertEquals(request.getHeader("X-Subject-Token"), "foo");
+   }
+   
+   public void testGetUserOfToken() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/token.json"));
+
+      User user = api.getAuthApi().getUserOfToken(authToken);
+
+      assertEquals(user, tokenFromResource("/v3/token.json").user());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      RecordedRequest request = assertSent(server, "GET", "/auth/tokens");
+      assertEquals(request.getHeader("X-Subject-Token"), authToken);
+   }
+
+   public void testGetUserOfTokenReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      User user = api.getAuthApi().getUserOfToken("foo");
+      assertNull(user);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      RecordedRequest request = assertSent(server, "GET", "/auth/tokens");
+      assertEquals(request.getHeader("X-Subject-Token"), "foo");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/CatalogApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/CatalogApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/CatalogApiLiveTest.java
new file mode 100644
index 0000000..3044c13
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/CatalogApiLiveTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.List;
+
+import org.jclouds.openstack.keystone.v3.domain.Endpoint;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CatalogApiLiveTest")
+public class CatalogApiLiveTest extends BaseV3KeystoneApiLiveTest {
+
+   @Test
+   public void testTenants() {
+      List<Endpoint> result = api.getCatalogApi().endpoints();
+      assertNotNull(result);
+      assertFalse(result.isEmpty());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/CatalogApiMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/CatalogApiMockTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/CatalogApiMockTest.java
new file mode 100644
index 0000000..d7f7639
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/CatalogApiMockTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.jclouds.openstack.keystone.v3.domain.Endpoint;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiMockTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "CatalogApiMockTest", singleThreaded = true)
+public class CatalogApiMockTest extends BaseV3KeystoneApiMockTest {
+
+   public void testListEndpoints() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/endpoints.json"));
+
+      List<Endpoint> endpoints = api.getCatalogApi().endpoints();
+      assertFalse(endpoints.isEmpty());
+      
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/endpoints");
+   }
+
+   public void testListEndpointsReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      List<Endpoint> endpoints = api.getCatalogApi().endpoints();
+      assertTrue(endpoints.isEmpty());
+      
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/endpoints");
+   }
+   
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/ProjectApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/ProjectApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/ProjectApiLiveTest.java
new file mode 100644
index 0000000..df0c0dd
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/ProjectApiLiveTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+import static com.google.common.collect.Iterables.any;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.jclouds.openstack.keystone.v3.domain.Project;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiLiveTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+
+@Test(groups = "live", testName = "ProjectApiLiveTest", singleThreaded = true)
+public class ProjectApiLiveTest extends BaseV3KeystoneApiLiveTest {
+
+   private Project project;
+   
+   @BeforeClass
+   public void createTestProject() {
+      project = api().create(getClass().getSimpleName(), null, true, false, null, null);
+      assertNotNull(project.id());
+   }
+   
+   @Test
+   public void testListProjects() {
+      assertTrue(any(api().list(), new Predicate<Project>() {
+         @Override
+         public boolean apply(Project input) {
+            return input.id().equals(project.id());
+         }
+      }));
+   }
+   
+   @Test
+   public void testGetProject() {
+      assertNotNull(api().get(project.id()));
+   }
+   
+   @Test
+   public void testUpdateProject() {
+      Project updated = api().get(project.id());
+      api().update(project.id(), updated.toBuilder().description("Updated").build());
+      project = api().get(project.id());
+      assertEquals(project.description(), "Updated");
+   }
+   
+   @Test
+   public void testSetAndListTags() {
+      api().setTags(project.id(), ImmutableSet.of("foo", "bar"));
+      Set<String> projectTags = api().listTags(project.id());
+      assertEquals(projectTags, ImmutableSet.of("foo", "bar"));
+   }
+   
+   @Test(dependsOnMethods = "testSetAndListTags")
+   public void testHasTag() {
+      assertTrue(api().hasTag(project.id(), "foo"));
+   }
+   
+   @Test(dependsOnMethods = "testSetAndListTags")
+   public void testAddTag() {
+      api().addTag(project.id(), "three");
+      assertTrue(api().hasTag(project.id(), "three"));
+   }
+   
+   @Test(dependsOnMethods = "testSetAndListTags")
+   public void testRemoveTag() {
+      api().removeTag(project.id(), "bar");
+      assertFalse(api().hasTag(project.id(), "bar"));
+   }
+   
+   @Test(dependsOnMethods = "testRemoveTag")
+   public void testRemoveAllTags() {
+      api().removeAllTags(project.id());
+      assertTrue(api().listTags(project.id()).isEmpty());
+   }
+   
+   @AfterClass(alwaysRun = true)
+   public void deleteProject() {
+      assertTrue(api().delete(project.id()));
+   }
+   
+   private ProjectApi api() {
+      return api.getProjectApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/ProjectApiMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/ProjectApiMockTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/ProjectApiMockTest.java
new file mode 100644
index 0000000..b8a4542
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/ProjectApiMockTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+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.List;
+import java.util.Set;
+
+import org.jclouds.openstack.keystone.v3.domain.Project;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiMockTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+
+@Test(groups = "unit", testName = "ProjectApiMockTest", singleThreaded = true)
+public class ProjectApiMockTest extends BaseV3KeystoneApiMockTest {
+
+   public void testListProjects() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/projects.json").setResponseCode(201));
+
+      List<Project> projects = api.getProjectApi().list();
+      assertFalse(projects.isEmpty());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/projects");
+   }
+
+   public void testListProjectsReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      List<Project> projects = api.getProjectApi().list();
+      assertTrue(projects.isEmpty());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/projects");
+   }
+
+   public void testGetProject() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/project.json"));
+
+      Project project = api.getProjectApi().get("2f9b30f706bc45d7923e055567be2e98");
+      assertNotNull(project);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/projects/2f9b30f706bc45d7923e055567be2e98");
+   }
+
+   public void testGetProjectReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      Project project = api.getProjectApi().get("2f9b30f706bc45d7923e055567be2e98");
+      assertNull(project);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/projects/2f9b30f706bc45d7923e055567be2e98");
+   }
+
+   public void testCreateProject() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/project.json"));
+
+      Project project = api.getProjectApi().create("foo", null, true, false, null, null);
+      assertNotNull(project);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "POST", "/projects", "{\"project\":{\"is_domain\":false,\"enabled\":true,\"name\":\"foo\"}}");
+   }
+
+   public void testUpdateProject() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/project.json"));
+
+      Project project = api.getProjectApi().update("2f9b30f706bc45d7923e055567be2e98",
+            Project.builder().name("foo").build());
+      assertNotNull(project);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "PATCH", "/projects/2f9b30f706bc45d7923e055567be2e98",
+            "{\"project\":{\"is_domain\":false,\"enabled\":true,\"name\":\"foo\"}}");
+   }
+
+   public void testDeleteProject() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response204());
+
+      boolean deleted = api.getProjectApi().delete("2f9b30f706bc45d7923e055567be2e98");
+      assertTrue(deleted);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "DELETE", "/projects/2f9b30f706bc45d7923e055567be2e98");
+   }
+
+   public void testDeleteProjectReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      boolean deleted = api.getProjectApi().delete("2f9b30f706bc45d7923e055567be2e98");
+      assertFalse(deleted);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "DELETE", "/projects/2f9b30f706bc45d7923e055567be2e98");
+   }
+
+   public void testListTags() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(new MockResponse().setBody("{\"tags\":[\"foo\",\"bar\"]}"));
+
+      Set<String> tags = api.getProjectApi().listTags("2f9b30f706bc45d7923e055567be2e98");
+      assertEquals(tags, ImmutableSet.of("foo", "bar"));
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/projects/2f9b30f706bc45d7923e055567be2e98/tags");
+   }
+
+   public void testHasTag() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response204());
+
+      boolean hasTag = api.getProjectApi().hasTag("2f9b30f706bc45d7923e055567be2e98", "foo");
+      assertTrue(hasTag);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "HEAD", "/projects/2f9b30f706bc45d7923e055567be2e98/tags/foo");
+   }
+
+   public void testAddTag() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response201());
+
+      api.getProjectApi().addTag("2f9b30f706bc45d7923e055567be2e98", "foo");
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "PUT", "/projects/2f9b30f706bc45d7923e055567be2e98/tags/foo");
+   }
+
+   public void testRemoveTag() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response204());
+
+      api.getProjectApi().removeTag("2f9b30f706bc45d7923e055567be2e98", "foo");
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "DELETE", "/projects/2f9b30f706bc45d7923e055567be2e98/tags/foo");
+   }
+
+   public void testSetTags() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(new MockResponse().setBody("{\"tags\":[\"foo\",\"bar\"]}"));
+
+      api.getProjectApi().setTags("2f9b30f706bc45d7923e055567be2e98", ImmutableSet.of("foo", "bar"));
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "PUT", "/projects/2f9b30f706bc45d7923e055567be2e98/tags", "{\"tags\":[\"foo\",\"bar\"]}");
+   }
+   
+   public void testRemoveAllTags() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response204());
+
+      api.getProjectApi().removeAllTags("2f9b30f706bc45d7923e055567be2e98");
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "DELETE", "/projects/2f9b30f706bc45d7923e055567be2e98/tags");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/RegionApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/RegionApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/RegionApiLiveTest.java
new file mode 100644
index 0000000..0e5bcfb
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/RegionApiLiveTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+import static com.google.common.collect.Iterables.any;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.openstack.keystone.v3.domain.Region;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiLiveTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+
+@Test(groups = "live", testName = "RegionApiLiveTest", singleThreaded = true)
+public class RegionApiLiveTest extends BaseV3KeystoneApiLiveTest {
+
+   private Region region;
+   
+   @BeforeClass
+   public void createTestRegion() {
+      region = api().create(getClass().getSimpleName(), null, null);
+      assertEquals(region.id(), getClass().getSimpleName());
+   }
+   
+   @Test
+   public void testListRegions() {
+      assertTrue(any(api().list(), new Predicate<Region>() {
+         @Override
+         public boolean apply(Region input) {
+            return input.id().equals(region.id());
+         }
+      }));
+   }
+   
+   @Test
+   public void testGetRegion() {
+      assertNotNull(api().get(region.id()));
+   }
+   
+   @Test
+   public void testUpdateRegion() {
+      api().update(region.id(), "Updated", null);
+      region = api().get(region.id());
+      assertEquals(region.description(), "Updated");
+   }
+   
+   @AfterClass(alwaysRun = true)
+   public void deleteRegion() {
+      assertTrue(api().delete(region.id()));
+   }
+   
+   private RegionApi api() {
+      return api.getRegionApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/RegionApiMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/RegionApiMockTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/RegionApiMockTest.java
new file mode 100644
index 0000000..bc7b1e0
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/RegionApiMockTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+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.List;
+
+import org.jclouds.openstack.keystone.v3.domain.Region;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiMockTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "RegionApiMockTest", singleThreaded = true)
+public class RegionApiMockTest extends BaseV3KeystoneApiMockTest {
+
+   public void testListRegions() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/regions.json"));
+
+      List<Region> regions = api.getRegionApi().list();
+      assertFalse(regions.isEmpty());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/regions");
+   }
+
+   public void testListRegionsReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      List<Region> regions = api.getRegionApi().list();
+      assertTrue(regions.isEmpty());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/regions");
+   }
+
+   public void testGetRegion() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/region.json"));
+
+      Region region = api.getRegionApi().get("RegionOne");
+      assertNotNull(region);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/regions/RegionOne");
+   }
+
+   public void testGetRegionReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      Region region = api.getRegionApi().get("RegionOne");
+      assertNull(region);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/regions/RegionOne");
+   }
+
+   public void testCreateRegion() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/region.json"));
+
+      Region region = api.getRegionApi().create("RegionOne", "Description", "12345");
+      assertNotNull(region);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "POST", "/regions",
+            "{\"region\":{\"id\":\"RegionOne\",\"description\":\"Description\",\"parent_region_id\":\"12345\"}}");
+   }
+
+   public void testUpdateRegion() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/region.json"));
+
+      Region region = api.getRegionApi().update("RegionOne", "Updated", null);
+      assertNotNull(region);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "PATCH", "/regions/RegionOne", "{\"region\":{\"description\":\"Updated\"}}");
+   }
+
+   public void testDeleteRegion() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response204());
+
+      boolean deleted = api.getRegionApi().delete("RegionOne");
+      assertTrue(deleted);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "DELETE", "/regions/RegionOne");
+   }
+
+   public void testDeleteRegionReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      boolean deleted = api.getRegionApi().delete("RegionOne");
+      assertFalse(deleted);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "DELETE", "/regions/RegionOne");
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/UserApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/UserApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/UserApiLiveTest.java
new file mode 100644
index 0000000..addcf39
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/UserApiLiveTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+import static com.google.common.collect.Iterables.any;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.openstack.keystone.v3.domain.User;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiLiveTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+
+@Test(groups = "live", testName = "UserApiLiveTest", singleThreaded = true)
+public class UserApiLiveTest extends BaseV3KeystoneApiLiveTest {
+
+   private User user;
+   
+   @BeforeClass
+   public void createTestUser() {
+      user = api().create(getClass().getSimpleName(), "p4ssw0rd", true, null, null);
+      assertNotNull(user);
+   }
+   
+   @Test
+   public void testListUsers() {
+      assertTrue(any(api().list(), new Predicate<User>() {
+         @Override
+         public boolean apply(User input) {
+            return input.id().equals(user.id());
+         }
+      }));
+   }
+   
+   @Test
+   public void testGetUser() {
+      assertNotNull(api().get(user.id()));
+   }
+   
+   @Test
+   public void testUpdateUser() {
+      api().update(user.id(), "Updated", null, null, null, null);
+      user = api().get(user.id());
+      assertEquals(user.name(), "Updated");
+   }
+   
+   @Test
+   public void testListGroups() {
+      assertNotNull(api().listGroups(user.id()));
+   }
+   
+   @Test
+   public void testListProjects() {
+      assertNotNull(api().listProjects(user.id()));
+   }
+   
+   @Test
+   public void testChangePassword() {
+      api().changePassword(user.id(), "p4ssw0rd", "Newp4ssw0rd");
+   }
+   
+   @AfterClass(alwaysRun = true)
+   public void deleteUser() {
+      assertTrue(api().delete(user.id()));
+   }
+   
+   private UserApi api() {
+      return api.getUserApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/UserApiMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/UserApiMockTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/UserApiMockTest.java
new file mode 100644
index 0000000..f31ae62
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/features/UserApiMockTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.openstack.keystone.v3.features;
+
+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.List;
+
+import org.jclouds.openstack.keystone.v3.domain.Group;
+import org.jclouds.openstack.keystone.v3.domain.Project;
+import org.jclouds.openstack.keystone.v3.domain.User;
+import org.jclouds.openstack.keystone.v3.internal.BaseV3KeystoneApiMockTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "UserApiMockTest", singleThreaded = true)
+public class UserApiMockTest extends BaseV3KeystoneApiMockTest {
+
+   public void testListUsers() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/users.json"));
+
+      List<User> users = api.getUserApi().list();
+      assertFalse(users.isEmpty());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/users");
+   }
+
+   public void testListUsersReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      List<User> users = api.getUserApi().list();
+      assertTrue(users.isEmpty());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/users");
+   }
+
+   public void testGetUser() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/user.json"));
+
+      User user = api.getUserApi().get("0bedc61110fd4e94a251260a47f18f29");
+      assertNotNull(user);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/users/0bedc61110fd4e94a251260a47f18f29");
+   }
+
+   public void testGetUserReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      User user = api.getUserApi().get("0bedc61110fd4e94a251260a47f18f29");
+      assertNull(user);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/users/0bedc61110fd4e94a251260a47f18f29");
+   }
+
+   public void testCreateUser() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/user.json"));
+
+      User user = api.getUserApi().create("user", "p4ssw0rd", true, "123", "789");
+      assertNotNull(user);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "POST", "/users", "{\"user\":{\"name\":\"user\",\"password\":\"p4ssw0rd\",\"enabled\":true,"
+            + "\"domain_id\":\"123\",\"default_project_id\":\"789\"}}");
+   }
+
+   public void testUpdateUser() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/user.json"));
+
+      User user = api.getUserApi().update("0bedc61110fd4e94a251260a47f18f29", "foo", null, null, null, null);
+      assertNotNull(user);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "PATCH", "/users/0bedc61110fd4e94a251260a47f18f29", "{\"user\":{\"name\":\"foo\"}}");
+   }
+
+   public void testDeleteUser() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response204());
+
+      boolean deleted = api.getUserApi().delete("0bedc61110fd4e94a251260a47f18f29");
+      assertTrue(deleted);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "DELETE", "/users/0bedc61110fd4e94a251260a47f18f29");
+   }
+
+   public void testDeleteUserReturns404() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response404());
+
+      boolean deleted = api.getUserApi().delete("0bedc61110fd4e94a251260a47f18f29");
+      assertFalse(deleted);
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "DELETE", "/users/0bedc61110fd4e94a251260a47f18f29");
+   }
+
+   public void testListGroups() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/groups.json"));
+
+      List<Group> groups = api.getUserApi().listGroups("0bedc61110fd4e94a251260a47f18f29");
+      assertFalse(groups.isEmpty());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/users/0bedc61110fd4e94a251260a47f18f29/groups");
+   }
+
+   public void testListProjects() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(jsonResponse("/v3/projects.json"));
+
+      List<Project> projects = api.getUserApi().listProjects("0bedc61110fd4e94a251260a47f18f29");
+      assertFalse(projects.isEmpty());
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "GET", "/users/0bedc61110fd4e94a251260a47f18f29/projects");
+   }
+
+   public void testChangePassword() throws InterruptedException {
+      enqueueAuthentication(server);
+      server.enqueue(response204());
+
+      api.getUserApi().changePassword("0bedc61110fd4e94a251260a47f18f29", "foo", "bar");
+
+      assertEquals(server.getRequestCount(), 2);
+      assertAuthentication(server);
+      assertSent(server, "POST", "/users/0bedc61110fd4e94a251260a47f18f29/password",
+            "{\"user\":{\"original_password\":\"foo\",\"password\":\"bar\"}}");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dd73410d/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/internal/BaseV3KeystoneApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/internal/BaseV3KeystoneApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/internal/BaseV3KeystoneApiLiveTest.java
new file mode 100644
index 0000000..6d08b46
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v3/internal/BaseV3KeystoneApiLiveTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.openstack.keystone.v3.internal;
+
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.SCOPE;
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.SERVICE_TYPE;
+
+import java.util.Properties;
+
+import org.jclouds.apis.BaseApiLiveTest;
+import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+import org.jclouds.openstack.keystone.auth.AuthenticationApi;
+import org.jclouds.openstack.keystone.auth.config.Authentication;
+import org.jclouds.openstack.keystone.v3.KeystoneApi;
+import org.jclouds.rest.ApiContext;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
+
+public class BaseV3KeystoneApiLiveTest extends BaseApiLiveTest<KeystoneApi> {
+
+   protected Supplier<String> token;
+   protected AuthenticationApi authenticationApi;
+
+   public BaseV3KeystoneApiLiveTest() {
+      provider = "openstack-keystone-3";
+   }
+
+   @Override
+   protected KeystoneApi create(Properties props, Iterable<Module> modules) {
+      ApiContext<KeystoneApi> ctx = newBuilder().modules(modules).overrides(props).build();
+      authenticationApi = ctx.utils().injector().getInstance(AuthenticationApi.class);
+      token = ctx.utils().injector().getInstance(Key.get(new TypeLiteral<Supplier<String>>() {
+      }, Authentication.class));
+      return ctx.getApi();
+   }
+
+   @Override
+   protected Properties setupProperties() {
+      Properties props = super.setupProperties();
+      setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
+      setIfTestSystemPropertyPresent(props, SCOPE);
+      String customServiceType = setIfTestSystemPropertyPresent(props, SERVICE_TYPE);
+      if (customServiceType == null) {
+         props.setProperty(SERVICE_TYPE, "identityv3");
+      }
+      return props;
+   }
+   
+   @Override
+   protected Iterable<Module> setupModules() {
+      ImmutableSet.Builder<Module> modules = ImmutableSet.builder();
+      modules.add(new OkHttpCommandExecutorServiceModule());
+      modules.add(new SLF4JLoggingModule());
+      return modules.build();
+   }
+
+}