diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/spi/DefaultDatastoreRpc.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/spi/DefaultDatastoreRpc.java index 2f245260b325..e20bd9a3f9d6 100644 --- a/gcloud-java-datastore/src/main/java/com/google/gcloud/spi/DefaultDatastoreRpc.java +++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/spi/DefaultDatastoreRpc.java @@ -32,6 +32,7 @@ import com.google.api.services.datastore.client.DatastoreException; import com.google.api.services.datastore.client.DatastoreFactory; import com.google.api.services.datastore.client.DatastoreOptions.Builder; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.gcloud.datastore.DatastoreOptions; import com.google.gcloud.spi.DatastoreRpc.DatastoreRpcException.Reason; @@ -40,6 +41,10 @@ import org.json.JSONObject; import org.json.JSONTokener; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; @@ -62,14 +67,45 @@ public class DefaultDatastoreRpc implements DatastoreRpc { } public DefaultDatastoreRpc(DatastoreOptions options) { + String normalizedHost = normalizeHost(options.host()); client = DatastoreFactory.get().create( new Builder() .dataset(options.projectId()) - .host(options.host()) + .host(normalizedHost) .initializer(options.httpRequestInitializer()) .build()); } + private static String normalizeHost(String host) { + host = host.toLowerCase(); + if (includesScheme(host)) { + Preconditions.checkArgument(!(host.startsWith("https://") && isLocalHost(host)), + "\"https\" is not supported for localhost. Use \"http\" instead."); + return host; + } + return "http://" + host; + } + + private static boolean isLocalHost(String host) { + if (host != null) { + try { + String normalizedHost = host; + if (!includesScheme(normalizedHost)) { + normalizedHost = "http://" + normalizedHost; + } + InetAddress hostAddr = InetAddress.getByName(new URL(normalizedHost).getHost()); + return hostAddr.isAnyLocalAddress() || hostAddr.isLoopbackAddress(); + } catch (UnknownHostException | MalformedURLException e) { + // ignore + } + } + return false; + } + + private static boolean includesScheme(String url) { + return url.startsWith("http://") || url.startsWith("https://"); + } + private static DatastoreRpcException translate(DatastoreException exception) { String message = exception.getMessage(); String reasonStr = ""; diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/RemoteGcsHelper.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/RemoteGcsHelper.java index 60cad7032178..e4d92b71a940 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/RemoteGcsHelper.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/RemoteGcsHelper.java @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableMap; import com.google.gcloud.AuthCredentials; import com.google.gcloud.storage.BlobInfo; +import com.google.gcloud.RetryParams; import com.google.gcloud.storage.Storage; import com.google.gcloud.storage.StorageException; import com.google.gcloud.storage.StorageOptions; @@ -96,50 +97,37 @@ public static String generateBucketName() { } /** - * Creates a {@code RemoteGcsHelper} object. + * Creates a {@code RemoteGcsHelper} object for the given project id and JSON key path. * + * @param projectId id of the project to be used for running the tests + * @param keyPath path to the JSON key to be used for running the tests * @param options creation options * @return A {@code RemoteGcsHelper} object for the provided options. - * @throws com.google.gcloud.storage.testing.RemoteGcsHelper.GcsHelperException if environment variables - * {@code GCLOUD_TESTS_PROJECT_ID} and {@code GCLOUD_TESTS_KEY} are not set or if the file - * pointed by {@code GCLOUD_TESTS_KEY} does not exist + * @throws com.google.gcloud.storage.testing.RemoteGcsHelper.GcsHelperException if the file pointed by + * {@code keyPath} does not exist */ - public static RemoteGcsHelper create(Option... options) throws GcsHelperException { + public static RemoteGcsHelper create(String projectId, String keyPath, Option... options) + throws GcsHelperException { boolean keyFromClassPath = false; Map, Option> optionsMap = Option.asImmutableMap(options); if (optionsMap.containsKey(KeyFromClasspath.class)) { keyFromClassPath = ((KeyFromClasspath) optionsMap.get(KeyFromClasspath.class)).keyFromClasspath(); } - String projectId = System.getenv(PROJECT_ID_ENV_VAR); - String stringKeyPath = System.getenv(PRIVATE_KEY_ENV_VAR); - if (projectId == null) { - String message = "Environment variable " + PROJECT_ID_ENV_VAR + " not set"; - if (log.isLoggable(Level.WARNING)) { - log.log(Level.WARNING, message); - } - throw new GcsHelperException(message); - } - if (stringKeyPath == null) { - String message = "Environment variable " + PRIVATE_KEY_ENV_VAR + " not set"; - if (log.isLoggable(Level.WARNING)) { - log.log(Level.WARNING, message); - } - throw new GcsHelperException(message); - } try { InputStream keyFileStream; if (keyFromClassPath) { - keyFileStream = RemoteGcsHelper.class.getResourceAsStream(stringKeyPath); + keyFileStream = RemoteGcsHelper.class.getResourceAsStream(keyPath); if (keyFileStream == null) { - throw new FileNotFoundException(stringKeyPath + " not found in classpath"); + throw new FileNotFoundException(keyPath + " not found in classpath"); } } else { - keyFileStream = new FileInputStream(stringKeyPath); + keyFileStream = new FileInputStream(keyPath); } StorageOptions storageOptions = StorageOptions.builder() .authCredentials(AuthCredentials.createForJson(keyFileStream)) .projectId(projectId) + .retryParams(RetryParams.getDefaultInstance()) .build(); return new RemoteGcsHelper(storageOptions); } catch (FileNotFoundException ex) { @@ -155,6 +143,36 @@ public static RemoteGcsHelper create(Option... options) throws GcsHelperExceptio } } + /** + * Creates a {@code RemoteGcsHelper} object. Project id and path to JSON key are read from two + * environment variables: {@code GCLOUD_TESTS_PROJECT_ID} and {@code GCLOUD_TESTS_KEY}. + * + * @param options creation options + * @return A {@code RemoteGcsHelper} object for the provided options. + * @throws com.google.gcloud.storage.testing.RemoteGcsHelper.GcsHelperException if environment variables + * {@code GCLOUD_TESTS_PROJECT_ID} and {@code GCLOUD_TESTS_KEY} are not set or if the file + * pointed by {@code GCLOUD_TESTS_KEY} does not exist + */ + public static RemoteGcsHelper create(Option... options) throws GcsHelperException { + String projectId = System.getenv(PROJECT_ID_ENV_VAR); + String keyPath = System.getenv(PRIVATE_KEY_ENV_VAR); + if (projectId == null) { + String message = "Environment variable " + PROJECT_ID_ENV_VAR + " not set"; + if (log.isLoggable(Level.WARNING)) { + log.log(Level.WARNING, message); + } + throw new GcsHelperException(message); + } + if (keyPath == null) { + String message = "Environment variable " + PRIVATE_KEY_ENV_VAR + " not set"; + if (log.isLoggable(Level.WARNING)) { + log.log(Level.WARNING, message); + } + throw new GcsHelperException(message); + } + return create(projectId, keyPath, options); + } + private static class DeleteBucketTask implements Callable { private Storage storage; diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java index 424bb061cf74..4c3ff1fa9a7c 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java @@ -67,7 +67,7 @@ public static void beforeClass() { @AfterClass public static void afterClass() throws ExecutionException, TimeoutException, InterruptedException { - if (!RemoteGcsHelper.forceDelete(storage, bucket, 5, TimeUnit.SECONDS)) { + if (storage != null && !RemoteGcsHelper.forceDelete(storage, bucket, 5, TimeUnit.SECONDS)) { if (log.isLoggable(Level.WARNING)) { log.log(Level.WARNING, "Deletion of bucket {0} timed out, bucket is not empty", bucket); }