/**
* Copyright (C) 2009-2015 Dell, Inc.
* See annotations for authorship information
*
* ====================================================================
* Licensed 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.dasein.cloud;
import org.dasein.cloud.test.TestNewCloudProvider;
import org.dasein.cloud.test.TestOldCloudProvider;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Properties;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
/**
* Tests all possible mechanisms of connecting providers, contexts, and clouds as well as the possible permutations of
* using them. The following combinations must be addressed:
* <ol>
* <li>A client using the old connection methods to connect to a legacy Dasein Cloud implementation (old client + old implementation)</li>
* <li>A newer client using the 2014.03+ connection methods to a legacy Dasein Cloud implementation (new client + old implementation)</li>
* <li>A client using the old connection methods to connect to a refactored Dasein Cloud implementation (old client + new implementation)</li>
* <li>A newer client using the 2014.03+ connection methods to a refactored Dasein Cloud implementation (new client + new implementation)</li>
* </ol>
* <p>
* The tests should specifically validate that all forms of fetching data (new + old) work once a connection has been established. It is OK
* that only new methods or only old methods work prior to connect since, in general, only the client doing the connection is
* interacting with the context at that point (and hopefully won't be mixing old and new calls during that process).
* </p>
* <p>Created by George Reese: 3/1/14 9:12 AM</p>
* @author George Reese
* @since 2014.03
* @version 2014.03 (issue #123)
*/
public class CloudConnectTestCase {
static public final String ACCOUNT = "account";
static public final String REGION = "region";
static public final ProviderContext.Value<byte[][]> KEYS = new ProviderContext.Value<byte[][]>("apiKeys", new byte[][] { "public".getBytes(), "private".getBytes() });
static public final ProviderContext.Value<String> VERSION = new ProviderContext.Value<String>("version", "1");
static public final ProviderContext.Value<byte[][]> X509 = new ProviderContext.Value<byte[][]>("x509", new byte[][] { "x509c".getBytes(), "x509k".getBytes() });
private Cloud newCloud;
private String cloudName;
private String effectiveAccountNumber;
private String providerName;
private String endpoint;
static private int testNumber = 0;
@Before
public void setUp() {
testNumber++;
cloudName = "Cloud " + testNumber;
providerName = "Provider " + testNumber;
endpoint = "https://example.com/" + testNumber;
effectiveAccountNumber = ACCOUNT;
if( newCloud == null ) {
newCloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
}
}
@After
public void tearDown() {
}
/********************************** NEW IMPLEMENTATION, OLD CLIENT **********************************/
@SuppressWarnings("deprecation")
private void checkConnectionIntegrityForOldClientMethods(@Nullable ProviderContext ctx) {
assertNotNull("The context resulting from context creation may not be null", ctx);
assertNotNull("No context was created", ctx);
byte[] b = ctx.getAccessPublic();
byte[] v = ctx.getAccessPrivate();
assertNotNull("No public key was found in the provider context", b);
assertNotNull("No private key was found in the provider context", v);
String pub = new String(b);
String priv = new String(v);
assertEquals("Public key is not public", "public", pub);
assertEquals("Private key is not private", "private", priv);
b = ctx.getX509Cert();
v = ctx.getX509Key();
assertNotNull("No X509 cert was found in the provider context", b);
assertNotNull("No X509 key was found in the provider context", v);
pub = new String(b);
priv = new String(v);
assertEquals("X509 certificate is not public", "x509c", pub);
assertEquals("X509 key is not private", "x509k", priv);
Properties props = ctx.getCustomProperties();
assertNotNull("Custom properties may not be null", props);
assertFalse("Custom properties for test cloud should contain values", props.isEmpty());
String version = props.getProperty("version");
assertEquals("The set version does not match the test value", "1", version);
assertEquals("The cloud name does not match the set value", cloudName, ctx.getCloudName());
assertEquals("The provider name does not match the set value", providerName, ctx.getProviderName());
assertEquals("The endpoint does not match the set value", endpoint, ctx.getEndpoint());
}
private void checkConnectionIntegrityForNewClientMethods(@Nonnull Cloud cloud, @Nullable ProviderContext ctx, @Nullable CloudProvider provider) {
assertNotNull("The context resulting from context creation may not be null", ctx);
assertNotNull("Cloud provider resulting from a connect may not be null", provider);
assertTrue("Cloud provider was not connected", provider.isConnected());
assertNotNull("The cloud name should not be null", provider.getCloudName());
assertNotNull("The provider name should not be null", provider.getProviderName());
ContextRequirements requirements = provider.getContextRequirements();
assertNotNull("The context requirements may not be null", requirements);
if( provider.getClass().getName().equals(TestNewCloudProvider.class.getName()) ) {
assertEquals("There should be exactly three fields required for the test provider", 3, requirements.getConfigurableValues().size());
}
else {
assertEquals("There should be exactly two fields required for the test provider", 2, requirements.getConfigurableValues().size());
}
assertEquals("The cloud does not match", cloud, ctx.getCloud());
assertEquals("The account numbers do not match", ACCOUNT, ctx.getAccountNumber());
assertEquals("The region values do not match", REGION, ctx.getRegionId());
assertEquals("The effective account number does not match the required value", effectiveAccountNumber, ctx.getEffectiveAccountNumber());
for( ContextRequirements.Field f : requirements.getConfigurableValues() ) {
Object value = ctx.getConfigurationValue(f.name);
assertNotNull("The value for " + f.name + " should have been set for these tests", value);
Object full = ctx.getConfigurationValue(f);
assertEquals("The two configurable value methods for " + f.name + " should return the same value", full, value);
}
}
@Test
public void registerCloud() {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
assertNotNull("The registered cloud may not be null", cloud);
assertEquals("The cloud name does not match what was registered", cloudName, cloud.getCloudName());
assertEquals("The provider name does not match what was registered", providerName, cloud.getProviderName());
assertEquals("The endpoint does not match what was registered", endpoint, cloud.getEndpoint());
assertEquals("Thew provider class does not match what was registered", TestNewCloudProvider.class, cloud.getProviderClass());
}
@Test
public void getCloudInstanceAfterFormalRegister() {
Cloud sharedCloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
Cloud cloud = Cloud.getInstance(sharedCloud.getEndpoint());
assertNotNull("Unable to locate the registred cloud", cloud);
assertEquals("The cloud name does not match what was registered", sharedCloud.getCloudName(), cloud.getCloudName());
assertEquals("The provider name does not match what was registered", sharedCloud.getProviderName(), cloud.getProviderName());
assertEquals("The endpoint does not match what was registered", sharedCloud.getEndpoint(), cloud.getEndpoint());
assertEquals("The provider class does not match what was registered", sharedCloud.getProviderClass(), cloud.getProviderClass());
}
@Test
public void getCloudFromBogusInstance() {
Cloud cloud = Cloud.getInstance("https://example.com/bogus");
assertNull("A bogus cloud was surprisingly found", cloud);
}
@Test
public void buildProvider() throws InstantiationException, IllegalAccessException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
CloudProvider p = cloud.buildProvider();
assertNotNull("No provider was built", p);
assertFalse("Cloud provider is connected without any connect operation", p.isConnected());
}
@Test
public void verifyServices() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS);
CloudProvider p = ctx.connect();
assertFalse("Test provider should have no admin services", p.hasAdminServices());
assertFalse("Test provider should have no compute services", p.hasComputeServices());
assertFalse("Test provider should have no converged infrastructure services", p.hasCIServices());
assertFalse("Test provider should have no identity services", p.hasIdentityServices());
assertFalse("Test provider should have no network services", p.hasNetworkServices());
assertFalse("Test provider should have no platform services", p.hasPlatformServices());
assertFalse("Test provider should have no storage services", p.hasStorageServices());
}
@Test
public void newConnectWithNewImpl() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS, X509, VERSION);
CloudProvider p = ctx.connect();
checkConnectionIntegrityForOldClientMethods(ctx);
checkConnectionIntegrityForNewClientMethods(cloud, ctx, p);
}
@SuppressWarnings("deprecation")
@Test
public void oldConnectWithNewImpl() throws CloudException, InternalException, IllegalAccessException, InstantiationException {
CloudProvider p = TestNewCloudProvider.class.newInstance();
ProviderContext ctx = new ProviderContext(ACCOUNT, REGION);
ctx.setEndpoint(endpoint);
ctx.setAccessKeys(KEYS.value[0], KEYS.value[1]);
ctx.setX509Cert(X509.value[0]);
ctx.setX509Key(X509.value[1]);
Properties props = new Properties();
props.setProperty("version", VERSION.value);
ctx.setCustomProperties(props);
p.connect(ctx);
checkConnectionIntegrityForOldClientMethods(ctx);
checkConnectionIntegrityForNewClientMethods(Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class), ctx, p);
}
@Test
public void newConnectWithOldImpl() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestOldCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS, X509, VERSION);
CloudProvider p = ctx.connect();
checkConnectionIntegrityForOldClientMethods(ctx);
checkConnectionIntegrityForNewClientMethods(cloud, ctx, p);
}
@SuppressWarnings("deprecation")
@Test
public void oldConnectWithOldImpl() throws CloudException, InternalException, IllegalAccessException, InstantiationException {
CloudProvider p = TestOldCloudProvider.class.newInstance();
ProviderContext ctx = new ProviderContext(ACCOUNT, REGION);
ctx.setEndpoint(endpoint);
ctx.setAccessKeys(KEYS.value[0], KEYS.value[1]);
ctx.setX509Cert(X509.value[0]);
ctx.setX509Key(X509.value[1]);
Properties props = new Properties();
props.setProperty("version", VERSION.value);
ctx.setCustomProperties(props);
p.connect(ctx);
checkConnectionIntegrityForOldClientMethods(ctx);
checkConnectionIntegrityForNewClientMethods(Cloud.register(providerName, cloudName, endpoint, TestOldCloudProvider.class), ctx, p);
}
@Test
public void closeWithNewConnectAndNewImpl() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS);
CloudProvider p = ctx.connect();
p.close();
assertFalse("The cloud provider was not closed", p.isConnected());
}
@SuppressWarnings("deprecation")
@Test
public void closeWithOldConnectAndNewImpl() throws CloudException, InternalException, IllegalAccessException, InstantiationException {
CloudProvider p = TestNewCloudProvider.class.newInstance();
ProviderContext ctx = new ProviderContext(ACCOUNT, REGION);
ctx.setEndpoint(endpoint);
ctx.setAccessKeys(KEYS.value[0], KEYS.value[1]);
ctx.setX509Cert(X509.value[0]);
ctx.setX509Key(X509.value[1]);
Properties props = new Properties();
props.setProperty("version", VERSION.value);
ctx.setCustomProperties(props);
p.connect(ctx);
p.close();
assertFalse("The cloud provider was not closed", p.isConnected());
}
@Test
public void closeWithNewConnectAndOldImpl() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestOldCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS);
CloudProvider p = ctx.connect();
p.close();
assertFalse("The cloud provider was not closed", p.isConnected());
}
@SuppressWarnings("deprecation")
@Test
public void closeWithOldConnectAndOldImpl() throws CloudException, InternalException, IllegalAccessException, InstantiationException {
CloudProvider p = TestOldCloudProvider.class.newInstance();
ProviderContext ctx = new ProviderContext(ACCOUNT, REGION);
ctx.setEndpoint(endpoint);
ctx.setAccessKeys(KEYS.value[0], KEYS.value[1]);
ctx.setX509Cert(X509.value[0]);
ctx.setX509Key(X509.value[1]);
Properties props = new Properties();
props.setProperty("version", VERSION.value);
ctx.setCustomProperties(props);
p.connect(ctx);
p.close();
assertFalse("The cloud provider was not closed", p.isConnected());
}
@Test
public void holdWithNewConnectAndNewImpl() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS);
CloudProvider p = ctx.connect();
p.hold();
p.close();
try {
assertTrue("Cloud provider was closed prior to hold being released", p.isConnected());
}
finally {
p.release();
}
}
@SuppressWarnings("deprecation")
@Test
public void holdWithOldConnectAndNewImpl() throws CloudException, InternalException, IllegalAccessException, InstantiationException {
CloudProvider p = TestNewCloudProvider.class.newInstance();
ProviderContext ctx = new ProviderContext(ACCOUNT, REGION);
ctx.setEndpoint(endpoint);
ctx.setAccessKeys(KEYS.value[0], KEYS.value[1]);
ctx.setX509Cert(X509.value[0]);
ctx.setX509Key(X509.value[1]);
Properties props = new Properties();
props.setProperty("version", VERSION.value);
ctx.setCustomProperties(props);
p.connect(ctx);
p.hold();
p.close();
try {
assertTrue("Cloud provider was closed prior to hold being released", p.isConnected());
}
finally {
p.release();
}
}
@Test
public void holdWithNewConnectAndOldImpl() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestOldCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS);
CloudProvider p = ctx.connect();
p.hold();
p.close();
try {
assertTrue("Cloud provider was closed prior to hold being released", p.isConnected());
}
finally {
p.release();
}
}
@SuppressWarnings("deprecation")
@Test
public void holdWithOldConnectAndOldImpl() throws CloudException, InternalException, IllegalAccessException, InstantiationException {
CloudProvider p = TestOldCloudProvider.class.newInstance();
ProviderContext ctx = new ProviderContext(ACCOUNT, REGION);
ctx.setEndpoint(endpoint);
ctx.setAccessKeys(KEYS.value[0], KEYS.value[1]);
ctx.setX509Cert(X509.value[0]);
ctx.setX509Key(X509.value[1]);
Properties props = new Properties();
props.setProperty("version", VERSION.value);
ctx.setCustomProperties(props);
p.connect(ctx);
p.hold();
p.close();
try {
assertTrue("Cloud provider was closed prior to hold being released", p.isConnected());
}
finally {
p.release();
}
}
@Test
public void releaseWithNewConnectAndNewImpl() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS);
CloudProvider p = ctx.connect();
p.hold();
p.close();
try {
try { Thread.sleep(1000L); }
catch( InterruptedException e ) { }
}
finally {
p.release();
}
try { Thread.sleep(2000L); }
catch( InterruptedException e ) { }
assertFalse("Cloud provider was not properly closed after release", p.isConnected());
}
@SuppressWarnings("deprecation")
@Test
public void releaseWithOldConnectAndNewImpl() throws CloudException, InternalException, IllegalAccessException, InstantiationException {
CloudProvider p = TestNewCloudProvider.class.newInstance();
ProviderContext ctx = new ProviderContext(ACCOUNT, REGION);
ctx.setEndpoint(endpoint);
ctx.setAccessKeys(KEYS.value[0], KEYS.value[1]);
ctx.setX509Cert(X509.value[0]);
ctx.setX509Key(X509.value[1]);
Properties props = new Properties();
props.setProperty("version", VERSION.value);
ctx.setCustomProperties(props);
p.connect(ctx);
p.hold();
p.close();
try {
try { Thread.sleep(1000L); }
catch( InterruptedException e ) { }
}
finally {
p.release();
}
try { Thread.sleep(2000L); }
catch( InterruptedException e ) { }
assertFalse("Cloud provider was not properly closed after release", p.isConnected());
}
@Test
public void releaseWithNewConnectAndOldImpl() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestOldCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS);
CloudProvider p = ctx.connect();
p.hold();
p.close();
try {
try { Thread.sleep(1000L); }
catch( InterruptedException e ) { }
}
finally {
p.release();
}
try { Thread.sleep(2000L); }
catch( InterruptedException e ) { }
assertFalse("Cloud provider was not properly closed after release", p.isConnected());
}
@SuppressWarnings("deprecation")
@Test
public void releaseWithOldConnectAndOldImpl() throws CloudException, InternalException, IllegalAccessException, InstantiationException {
CloudProvider p = TestOldCloudProvider.class.newInstance();
ProviderContext ctx = new ProviderContext(ACCOUNT, REGION);
ctx.setEndpoint(endpoint);
ctx.setAccessKeys(KEYS.value[0], KEYS.value[1]);
ctx.setX509Cert(X509.value[0]);
ctx.setX509Key(X509.value[1]);
Properties props = new Properties();
props.setProperty("version", VERSION.value);
ctx.setCustomProperties(props);
p.connect(ctx);
p.hold();
p.close();
try {
try { Thread.sleep(1000L); }
catch( InterruptedException e ) { }
}
finally {
p.release();
}
try { Thread.sleep(2000L); }
catch( InterruptedException e ) { }
assertFalse("Cloud provider was not properly closed after release", p.isConnected());
}
@Test
public void testContext() throws CloudException, InternalException {
Cloud cloud = Cloud.register(providerName, cloudName, endpoint, TestNewCloudProvider.class);
ProviderContext ctx = cloud.createContext(ACCOUNT, REGION, KEYS);
CloudProvider p = ctx.connect();
assertNull("The default context test in the test provider should always return null", p.testContext());
}
}