@Override @SelectJson("extensions") @Consumes(MediaType.APPLICATION_JSON) public Set<Extension> expected() { return ImmutableSet.of( Extension.builder() .alias("RAX-PIE") .name("Public Image Extension") .namespace(URI.create("http://docs.rackspacecloud.com/servers/api/ext/pie/v1.0")) .updated( new SimpleDateFormatDateService() .iso8601SecondsDateParse("2011-01-22T13:25:27-06:00")) .description("Adds the capability to share an image with other users.") .links( ImmutableSet.of( Link.create( Relation.DESCRIBEDBY, "application/pdf", URI.create( "http://docs.rackspacecloud.com/servers/api/ext/cs-pie-20111111.pdf")), Link.create( Relation.DESCRIBEDBY, "application/vnd.sun.wadl+xml", URI.create("http://docs.rackspacecloud.com/servers/api/ext/cs-pie.wadl")))) .build(), Extension.builder() .alias("RAX-CBS") .name("Cloud Block Storage") .namespace(URI.create("http://docs.rackspacecloud.com/servers/api/ext/cbs/v1.0")) .updated( new SimpleDateFormatDateService() .iso8601SecondsDateParse("2011-01-12T11:22:33-06:00")) .description("Allows mounting cloud block storage volumes.") .links( ImmutableSet.of( Link.create( Relation.DESCRIBEDBY, "application/pdf", URI.create( "http://docs.rackspacecloud.com/servers/api/ext/cs-cbs-20111201.pdf")), Link.create( Relation.DESCRIBEDBY, "application/vnd.sun.wadl+xml", URI.create("http://docs.rackspacecloud.com/servers/api/ext/cs-cbs.wadl")))) .build()); }
public void testChangesHttpsToHttp() { assertEquals( fn.apply( Extension.builder() .alias("security_groups") .name("SecurityGroups") .namespace(URI.create("https://docs.openstack.org/ext/securitygroups/api/v1.1")) .updated( new SimpleDateFormatDateService() .iso8601SecondsDateParse("2011-07-21T00:00:00+00:00")) .description("Security group support") .build()), URI.create("http://docs.openstack.org/ext/securitygroups/api/v1.1")); }
public void testReturnsNamespace() { URI ns = URI.create("http://docs.openstack.org/ext/keypairs/api/v1.1"); assertEquals( fn.apply( Extension.builder() .alias("os-keypairs") .name("Keypairs") .namespace(ns) .updated( new SimpleDateFormatDateService() .iso8601SecondsDateParse("2011-08-08T00:00:00+00:00")) .description("Keypair Support") .build()), ns); }
@Test( groups = "unit", testName = "PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest") public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest { Extension keypairs = Extension.builder() .alias("os-keypairs") .name("Keypairs") .namespace(URI.create("http://docs.openstack.org/ext/keypairs/api/v1.1")) .updated( new SimpleDateFormatDateService() .iso8601SecondsDateParse("2011-08-08T00:00:00+00:00")) .description("Keypair Support") .build(); @org.jclouds.openstack.v2_0.services.Extension( of = ServiceType.COMPUTE, namespace = "http://docs.openstack.org/ext/keypairs/api/v1.1") interface KeyPairApi {} Extension floatingIps = Extension.builder() .alias("os-floating-ips") .name("Floating_ips") .namespace(URI.create("http://docs.openstack.org/ext/floating_ips/api/v1.1")) .updated( new SimpleDateFormatDateService() .iso8601SecondsDateParse("2011-06-16T00:00:00+00:00")) .description("Floating IPs support") .build(); @org.jclouds.openstack.v2_0.services.Extension( of = ServiceType.COMPUTE, name = "Floating_ips", alias = "os-floating-ips", namespace = "http://docs.openstack.org/ext/floating_ips/api/v1.1") interface FloatingIPApi {} interface NovaApi { @Delegate Optional<FloatingIPApi> getFloatingIPExtensionApi(String region); @Delegate Optional<KeyPairApi> getKeyPairExtensionApi(String region); } InvocationSuccess getFloatingIPExtension(List<Object> args) throws SecurityException, NoSuchMethodException { return InvocationSuccess.create( Invocation.create(method(NovaApi.class, "getFloatingIPExtensionApi", String.class), args), "foo"); } InvocationSuccess getKeyPairExtension(List<Object> args) throws SecurityException, NoSuchMethodException { return InvocationSuccess.create( Invocation.create(method(NovaApi.class, "getKeyPairExtensionApi", String.class), args), "foo"); } public void testPresentWhenExtensionsIncludeNamespaceFromAnnotationAbsentWhenNot() throws SecurityException, NoSuchMethodException { assertEquals( whenExtensionsInRegionInclude("region", keypairs, floatingIps) .apply(getFloatingIPExtension(ImmutableList.<Object>of("region"))), Optional.of("foo")); assertEquals( whenExtensionsInRegionInclude("region", keypairs, floatingIps) .apply(getKeyPairExtension(ImmutableList.<Object>of("region"))), Optional.of("foo")); assertEquals( whenExtensionsInRegionInclude("region", keypairs) .apply(getFloatingIPExtension(ImmutableList.<Object>of("region"))), Optional.absent()); assertEquals( whenExtensionsInRegionInclude("region", floatingIps) .apply(getKeyPairExtension(ImmutableList.<Object>of("region"))), Optional.absent()); } public void testRegionWithoutExtensionsReturnsAbsent() throws SecurityException, NoSuchMethodException { assertEquals( whenExtensionsInRegionInclude("region", floatingIps) .apply(getFloatingIPExtension(ImmutableList.<Object>of("differentregion"))), Optional.absent()); assertEquals( whenExtensionsInRegionInclude("region", keypairs) .apply(getKeyPairExtension(ImmutableList.<Object>of("differentregion"))), Optional.absent()); } /** * It is possible that the /extensions call returned the correct extension, but that the * namespaces were different, for whatever reason. One way to address this is to have a multimap * of the authoritative namespace to alternate ones, which could be wired up with guice */ public void testPresentWhenAliasForExtensionMapsToNamespace() throws SecurityException, NoSuchMethodException { Extension keypairsWithDifferentNamespace = keypairs .toBuilder() .namespace( URI.create("http://docs.openstack.org/ext/arbitrarilydifferent/keypairs/api/v1.1")) .build(); Multimap<URI, URI> aliases = ImmutableMultimap.of( keypairs.getNamespace(), keypairsWithDifferentNamespace.getNamespace()); assertEquals( whenExtensionsAndAliasesInRegionInclude( "region", ImmutableSet.of(keypairsWithDifferentNamespace), aliases) .apply(getKeyPairExtension(ImmutableList.<Object>of("region"))), Optional.of("foo")); assertEquals( whenExtensionsAndAliasesInRegionInclude( "region", ImmutableSet.of(keypairsWithDifferentNamespace), aliases) .apply(getFloatingIPExtension(ImmutableList.<Object>of("region"))), Optional.absent()); } /** * In devstack and going forward, namespaces are being deprecated. When namespace is missing (or * replaced with a "fake" /fake namespace), allow matching by name and alias. */ public void testPresentWhenNameSpaceIsFakeAndMatchByNameOrAlias() throws SecurityException, NoSuchMethodException { // Revert to alias Extension floatingIpsWithFakeNamespace = floatingIps.toBuilder().namespace(URI.create("http://docs.openstack.org/ext/fake")).build(); // Revert to name Extension floatingIpsWithFakeNamespaceAndAlias = floatingIps .toBuilder() .namespace(URI.create("http://docs.openstack.org/ext/fake")) .alias("fake") .build(); Multimap<URI, URI> aliases = ImmutableMultimap.of(); assertEquals( whenExtensionsAndAliasesInRegionInclude( "region", ImmutableSet.of(floatingIpsWithFakeNamespace), aliases) .apply(getFloatingIPExtension(ImmutableList.<Object>of("region"))), Optional.of("foo")); assertEquals( whenExtensionsAndAliasesInRegionInclude( "region", ImmutableSet.of(floatingIpsWithFakeNamespaceAndAlias), aliases) .apply(getFloatingIPExtension(ImmutableList.<Object>of("region"))), Optional.of("foo")); } public void testPresentWhenNameSpaceIsMissingAndMatchByNameOrAlias() throws SecurityException, NoSuchMethodException { // Revert to alias Extension floatingIpsWithMissingNamespace = floatingIps.toBuilder().namespace(null).build(); // Revert to name Extension floatingIpsWithMissingNamespaceAndAlias = floatingIps.toBuilder().namespace(null).alias("fake").build(); Multimap<URI, URI> aliases = ImmutableMultimap.of(); assertEquals( whenExtensionsAndAliasesInRegionInclude( "region", ImmutableSet.of(floatingIpsWithMissingNamespace), aliases) .apply(getFloatingIPExtension(ImmutableList.<Object>of("region"))), Optional.of("foo")); assertEquals( whenExtensionsAndAliasesInRegionInclude( "region", ImmutableSet.of(floatingIpsWithMissingNamespaceAndAlias), aliases) .apply(getFloatingIPExtension(ImmutableList.<Object>of("region"))), Optional.of("foo")); } private PresentWhenExtensionAnnotationMatchesExtensionSet whenExtensionsInRegionInclude( String region, Extension... extensions) { return whenExtensionsAndAliasesInRegionInclude( region, ImmutableSet.copyOf(extensions), ImmutableMultimap.<URI, URI>of()); } private PresentWhenExtensionAnnotationMatchesExtensionSet whenExtensionsAndAliasesInRegionInclude( String region, final Set<Extension> extensions, final Multimap<URI, URI> aliases) { final LoadingCache<String, Set<? extends Extension>> extensionsForRegion = CacheBuilder.newBuilder() .build( CacheLoader.from( Functions.forMap( ImmutableMap.<String, Set<? extends Extension>>of( region, extensions, "differentregion", ImmutableSet.<Extension>of())))); PresentWhenExtensionAnnotationMatchesExtensionSet fn = Guice.createInjector( new AbstractModule() { @Override protected void configure() { MapBinder<URI, URI> aliasBindings = MapBinder.newMapBinder( binder(), URI.class, URI.class, NamespaceAliases.class) .permitDuplicates(); for (URI key : aliases.keySet()) { for (URI value : aliases.get(key)) { aliasBindings.addBinding(key).toInstance(value); } } } @Provides LoadingCache<String, Set<? extends Extension>> getExtensions() { return extensionsForRegion; } }) .getInstance(PresentWhenExtensionAnnotationMatchesExtensionSet.class); return fn; } }