This is an automated email from the ASF dual-hosted git repository.
gaul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jclouds.git
The following commit(s) were added to refs/heads/master by this push:
new 17fd80c JCLOUDS-1557 - Azure local server support
17fd80c is described below
commit 17fd80cd5a10ed2ab6886ad436f51b62ad0a826d
Author: davidsloan <[email protected]>
AuthorDate: Tue Dec 8 02:14:03 2020 +0000
JCLOUDS-1557 - Azure local server support
Co-authored-by: David Sloan <[email protected]>
---
.../filters/SharedKeyLiteAuthentication.java | 24 +++---
.../util/storageurl/AppendAccountToEndpoint.java | 58 +++++++++++++++
.../util/storageurl/StorageAccountInVhost.java | 55 ++++++++++++++
.../util/storageurl/StorageUrlSupplier.java | 26 +++++++
.../storage/util/storageurl/TrailingSlashUtil.java | 28 +++++++
.../blobstore/AzureBlobRequestSigner.java | 12 ++-
.../config/AzureBlobStoreContextModule.java | 23 +++---
.../config/AppendAccountToEndpointModule.java | 30 ++++++++
.../filters/SharedKeyLiteAuthenticationTest.java | 15 +++-
.../storageurl/AppendAccountToEndpointTest.java | 87 ++++++++++++++++++++++
.../util/storageurl/StorageAccountInVhostTest.java | 87 ++++++++++++++++++++++
11 files changed, 414 insertions(+), 31 deletions(-)
diff --git
a/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java
index 6405800..c2cdf98 100644
---
a/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java
+++
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java
@@ -21,14 +21,12 @@ import static com.google.common.io.ByteStreams.readBytes;
import static org.jclouds.crypto.Macs.asByteProcessor;
import static org.jclouds.util.Patterns.NEWLINE_PATTERN;
import static org.jclouds.util.Strings2.toInputStream;
-import org.jclouds.http.Uris.UriBuilder;
+import java.net.URI;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
-import org.jclouds.http.Uris;
-import java.net.URI;
import javax.annotation.Resource;
import javax.inject.Inject;
@@ -36,12 +34,8 @@ import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
import org.jclouds.Constants;
+import org.jclouds.azure.storage.util.storageurl.StorageUrlSupplier;
import org.jclouds.crypto.Crypto;
import org.jclouds.date.TimeStamp;
import org.jclouds.domain.Credentials;
@@ -49,16 +43,23 @@ import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils;
+import org.jclouds.http.Uris;
+import org.jclouds.http.Uris.UriBuilder;
import org.jclouds.http.internal.SignatureWire;
import org.jclouds.logging.Logger;
import org.jclouds.util.Strings2;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.io.ByteProcessor;
import com.google.common.net.HttpHeaders;
@@ -76,7 +77,6 @@ public class SharedKeyLiteAuthentication implements
HttpRequestFilter {
private final Provider<String> timeStampProvider;
private final Crypto crypto;
private final String credential;
- private final String identity;
private final HttpUtils utils;
private final URI storageUrl;
private final boolean isSAS;
@@ -88,13 +88,13 @@ public class SharedKeyLiteAuthentication implements
HttpRequestFilter {
@Inject
public SharedKeyLiteAuthentication(SignatureWire signatureWire,
@org.jclouds.location.Provider Supplier<Credentials> creds,
@TimeStamp Provider<String> timeStampProvider,
- Crypto crypto, HttpUtils utils, @Named("sasAuth") boolean
sasAuthentication) {
+ Crypto crypto, HttpUtils utils, @Named("sasAuth") boolean
sasAuthentication,
+ StorageUrlSupplier storageUrlSupplier) {
this.crypto = crypto;
this.utils = utils;
this.signatureWire = signatureWire;
- this.storageUrl = URI.create("https://" + creds.get().identity +
".blob.core.windows.net/");
+ this.storageUrl = storageUrlSupplier.get();
this.creds = creds;
- this.identity = creds.get().identity;
this.credential = creds.get().credential;
this.timeStampProvider = timeStampProvider;
this.isSAS = sasAuthentication;
diff --git
a/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/AppendAccountToEndpoint.java
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/AppendAccountToEndpoint.java
new file mode 100644
index 0000000..31de79f
--- /dev/null
+++
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/AppendAccountToEndpoint.java
@@ -0,0 +1,58 @@
+/*
+ * 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.azure.storage.util.storageurl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
+import org.jclouds.domain.Credentials;
+import org.jclouds.location.Provider;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import static
org.jclouds.azure.storage.util.storageurl.TrailingSlashUtil.ensureTrailingSlash;
+import java.net.URI;
+
+@Singleton
+public class AppendAccountToEndpoint implements StorageUrlSupplier {
+
+ private final Supplier<URI> endpointSupplier;
+ private final Supplier<Credentials> credentialsSupplier;
+
+ @Inject
+ public AppendAccountToEndpoint(@Provider Supplier<URI> endpointSupplier,
@Provider Supplier<Credentials> credentialsSupplier) {
+ this.endpointSupplier = endpointSupplier;
+ this.credentialsSupplier = credentialsSupplier;
+ }
+
+ @Override
+ public URI get() {
+
+ URI endpoint = endpointSupplier.get();
+
+ Preconditions.checkNotNull(endpoint, "An endpoint must be configured in
order to use AppendAccountToEndpoint module");
+
+ String endpointTrailingSlash = new
StringBuilder(ensureTrailingSlash(endpoint))
+ .append(credentialsSupplier.get().identity)
+ .append("/")
+ .toString();
+
+ return URI.create(endpointTrailingSlash);
+
+ }
+
+}
diff --git
a/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/StorageAccountInVhost.java
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/StorageAccountInVhost.java
new file mode 100644
index 0000000..6835650
--- /dev/null
+++
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/StorageAccountInVhost.java
@@ -0,0 +1,55 @@
+/*
+ * 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.azure.storage.util.storageurl;
+
+import com.google.common.base.Supplier;
+import org.jclouds.domain.Credentials;
+import org.jclouds.location.Provider;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.net.URI;
+import static
org.jclouds.azure.storage.util.storageurl.TrailingSlashUtil.ensureTrailingSlash;
+
+@Singleton
+public class StorageAccountInVhost implements StorageUrlSupplier {
+
+ private final Supplier<URI> endpointSupplier;
+ private final Supplier<Credentials> credentialsSupplier;
+
+ @Inject
+ public StorageAccountInVhost(@Provider Supplier<URI> endpointSupplier,
@Provider Supplier<Credentials> credentialsSupplier) {
+ this.endpointSupplier = endpointSupplier;
+ this.credentialsSupplier = credentialsSupplier;
+ }
+
+ @Override
+ public URI get() {
+
+ URI endpoint = endpointSupplier.get();
+
+ String uri = endpoint == null ? buildUri() :
ensureTrailingSlash(endpoint);
+
+ return URI.create(uri);
+
+ }
+
+ private String buildUri() {
+ return "https://" + credentialsSupplier.get().identity +
".blob.core.windows.net/";
+ }
+
+}
diff --git
a/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/StorageUrlSupplier.java
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/StorageUrlSupplier.java
new file mode 100644
index 0000000..8fe7c2f
--- /dev/null
+++
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/StorageUrlSupplier.java
@@ -0,0 +1,26 @@
+/*
+ * 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.azure.storage.util.storageurl;
+
+import com.google.common.base.Supplier;
+import com.google.inject.ImplementedBy;
+
+import java.net.URI;
+
+@ImplementedBy(StorageAccountInVhost.class)
+public interface StorageUrlSupplier extends Supplier<URI> {
+}
diff --git
a/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/TrailingSlashUtil.java
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/TrailingSlashUtil.java
new file mode 100644
index 0000000..36b2dba
--- /dev/null
+++
b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/storageurl/TrailingSlashUtil.java
@@ -0,0 +1,28 @@
+/*
+ * 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.azure.storage.util.storageurl;
+
+import java.net.URI;
+
+public class TrailingSlashUtil {
+
+ static String ensureTrailingSlash(URI endpointUri) {
+ String endpoint = endpointUri.toString();
+ return endpoint.endsWith("/") ? endpoint : endpoint + "/";
+ }
+
+}
diff --git
a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobRequestSigner.java
b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobRequestSigner.java
index 523f527..28edabb 100644
---
a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobRequestSigner.java
+++
b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobRequestSigner.java
@@ -21,11 +21,13 @@ import static
com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.Date;
import java.util.concurrent.TimeUnit;
+
import javax.inject.Inject;
-import javax.inject.Singleton;
import javax.inject.Named;
+import javax.inject.Singleton;
import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
+import org.jclouds.azure.storage.util.storageurl.StorageUrlSupplier;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
@@ -36,6 +38,7 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.Uris;
import org.jclouds.http.options.GetOptions;
import org.jclouds.javax.annotation.Nullable;
+
import com.google.common.base.Supplier;
import com.google.common.net.HttpHeaders;
import com.google.inject.Provider;
@@ -53,17 +56,18 @@ public class AzureBlobRequestSigner implements
BlobRequestSigner {
private final DateService dateService;
private final SharedKeyLiteAuthentication auth;
private final String credential;
- private final boolean isSAS;
+ private final boolean isSAS;
@Inject
public AzureBlobRequestSigner(
BlobToHttpGetOptions blob2HttpGetOptions, @TimeStamp Provider<String>
timeStampProvider,
DateService dateService, SharedKeyLiteAuthentication auth,
- @org.jclouds.location.Provider Supplier<Credentials> creds,
@Named("sasAuth") boolean sasAuthentication)
+ @org.jclouds.location.Provider Supplier<Credentials> creds,
@Named("sasAuth") boolean sasAuthentication,
+ StorageUrlSupplier storageUriSupplier)
throws SecurityException, NoSuchMethodException {
this.identity = creds.get().identity;
this.credential = creds.get().credential;
- this.storageUrl = URI.create("https://" + creds.get().identity +
".blob.core.windows.net/");
+ this.storageUrl = storageUriSupplier.get();
this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions,
"blob2HttpGetOptions");
this.timeStampProvider = checkNotNull(timeStampProvider,
"timeStampProvider");
this.dateService = checkNotNull(dateService, "dateService");
diff --git
a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java
b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java
index 68ceef3a..25e9972 100644
---
a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java
+++
b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java
@@ -16,27 +16,24 @@
*/
package org.jclouds.azureblob.blobstore.config;
-import java.util.concurrent.TimeUnit;
-
-import javax.inject.Singleton;
-import javax.inject.Named;
-
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.Scopes;
import org.jclouds.azureblob.AzureBlobClient;
import org.jclouds.azureblob.blobstore.AzureBlobRequestSigner;
import org.jclouds.azureblob.blobstore.AzureBlobStore;
+import org.jclouds.azureblob.config.InsufficientAccessRightsException;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.attr.ConsistencyModel;
-import org.jclouds.azureblob.config.InsufficientAccessRightsException;
-
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
-import com.google.inject.Scopes;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.util.concurrent.TimeUnit;
public class AzureBlobStoreContextModule extends AbstractModule {
diff --git
a/providers/azureblob/src/main/java/org/jclouds/azureblob/config/AppendAccountToEndpointModule.java
b/providers/azureblob/src/main/java/org/jclouds/azureblob/config/AppendAccountToEndpointModule.java
new file mode 100644
index 0000000..d67b323
--- /dev/null
+++
b/providers/azureblob/src/main/java/org/jclouds/azureblob/config/AppendAccountToEndpointModule.java
@@ -0,0 +1,30 @@
+/*
+ * 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.azureblob.config;
+
+import com.google.inject.AbstractModule;
+import org.jclouds.azure.storage.util.storageurl.AppendAccountToEndpoint;
+import org.jclouds.azure.storage.util.storageurl.StorageUrlSupplier;
+
+public class AppendAccountToEndpointModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ bind(StorageUrlSupplier.class).to(AppendAccountToEndpoint.class);
+ }
+
+}
diff --git
a/providers/azureblob/src/test/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthenticationTest.java
b/providers/azureblob/src/test/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthenticationTest.java
index 29672f4..e34965e 100644
---
a/providers/azureblob/src/test/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthenticationTest.java
+++
b/providers/azureblob/src/test/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthenticationTest.java
@@ -44,6 +44,7 @@ public class SharedKeyLiteAuthenticationTest {
private SharedKeyLiteAuthentication filter;
private SharedKeyLiteAuthentication filterSAS;
private SharedKeyLiteAuthentication filterSASQuestionMark;
+ private SharedKeyLiteAuthentication filterSASCustomEndpoint;
@DataProvider(parallel = true)
public Object[][] dataProvider() {
@@ -67,8 +68,11 @@ public class SharedKeyLiteAuthenticationTest {
{ HttpRequest.builder().method(HttpMethod.GET).endpoint("https://"
+ ACCOUNT
+ ".blob.core.windows.net/movies/MOV1.avi").build(),
filterSAS,
"https://foo.blob.core.windows.net/movies/MOV1.avi?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-02-13T17%3A18%3A22Z&st=2019-02-13T09%3A18%3A22Z&spr=https&sig=sMnaKSD94CzEPeGnWauTT0wBNIn%2B4ySkZO5PEAW7zs%3D"
},
{ HttpRequest.builder().method(HttpMethod.GET).endpoint("https://"
+ ACCOUNT
- + ".blob.core.windows.net/movies/MOV1.avi").build(),
filterSASQuestionMark,
"https://foo.blob.core.windows.net/movies/MOV1.avi?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-02-13T17%3A18%3A22Z&st=2019-02-13T09%3A18%3A22Z&spr=https&sig=sMnaKSD94CzEPeGnWauTT0wBNIn%2B4ySkZO5PEAW7zs%3D"
} };
- }
+ + ".blob.core.windows.net/movies/MOV1.avi").build(),
filterSASQuestionMark,
"https://foo.blob.core.windows.net/movies/MOV1.avi?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-02-13T17%3A18%3A22Z&st=2019-02-13T09%3A18%3A22Z&spr=https&sig=sMnaKSD94CzEPeGnWauTT0wBNIn%2B4ySkZO5PEAW7zs%3D"
},
+ {
HttpRequest.builder().method(HttpMethod.GET).endpoint("http://my-custom-endpoint.net/movies/MOV1.avi").build(),
filterSASCustomEndpoint,
+
"http://my-custom-endpoint.net/movies/MOV1.avi?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-02-13T17%3A18%3A22Z&st=2019-02-13T09%3A18%3A22Z&spr=https&sig=sMnaKSD94CzEPeGnWauTT0wBNIn%2B4ySkZO5PEAW7zs%3D"
} };
+
+}
/**
* NOTE this test is dependent on how frequently the timestamp updates. At
@@ -167,5 +171,12 @@ public class SharedKeyLiteAuthenticationTest {
.modules(ImmutableSet.<Module> of(new MockModule(), new
NullLoggingModule()))
.buildInjector();
filterSASQuestionMark =
injector.getInstance(SharedKeyLiteAuthentication.class);
+ injector = ContextBuilder
+ .newBuilder("azureblob")
+ .endpoint("http://my-custom-endpoint.net")
+ .credentials(ACCOUNT,
"?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-02-13T17:18:22Z&st=2019-02-13T09:18:22Z&spr=https&sig=sMnaKSD94CzEPeGnWauTT0wBNIn%2B4ySkZO5PEAW7zs%3D")
+ .modules(ImmutableSet.<Module> of(new MockModule(), new
NullLoggingModule()))
+ .buildInjector();
+ filterSASCustomEndpoint =
injector.getInstance(SharedKeyLiteAuthentication.class);
}
}
diff --git
a/providers/azureblob/src/test/java/org/jclouds/azure/storage/util/storageurl/AppendAccountToEndpointTest.java
b/providers/azureblob/src/test/java/org/jclouds/azure/storage/util/storageurl/AppendAccountToEndpointTest.java
new file mode 100644
index 0000000..980324c
--- /dev/null
+++
b/providers/azureblob/src/test/java/org/jclouds/azure/storage/util/storageurl/AppendAccountToEndpointTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.azure.storage.util.storageurl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import org.jclouds.ContextBuilder;
+import org.jclouds.azureblob.config.AppendAccountToEndpointModule;
+import org.jclouds.domain.Credentials;
+import org.jclouds.logging.config.NullLoggingModule;
+import org.jclouds.rest.internal.BaseRestApiTest;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit")
+public class AppendAccountToEndpointTest {
+
+ private static final String ACCOUNT = "foo";
+
+ @Test(expectedExceptions = NullPointerException.class)
+ void testThrowsErrorWhenNoEndpointSupplied() {
+
+ AppendAccountToEndpoint target = new AppendAccountToEndpoint(
+ () -> null,
+ () -> new Credentials(ACCOUNT, "creds")
+ );
+ target.get();
+ }
+
+ @Test
+ void testCustomEndpointWithoutTrailingSlash() {
+
+ AppendAccountToEndpoint target = new AppendAccountToEndpoint(
+ () -> URI.create("http://localhost:10000"),
+ () -> new Credentials(ACCOUNT, "creds")
+ );
+
+ assertEquals(target.get().toString(), "http://localhost:10000/foo/");
+ }
+
+ @Test
+ void testCustomEndpointWithTrailingSlash() {
+
+ AppendAccountToEndpoint target = new AppendAccountToEndpoint(
+ () -> URI.create("http://localhost:10000/"),
+ () -> new Credentials(ACCOUNT, "creds")
+ );
+
+ assertEquals(target.get().toString(), "http://localhost:10000/foo/");
+
+ }
+
+ @Test
+ void testInsideContext() {
+ String adjustedUri = ContextBuilder
+ .newBuilder("azureblob")
+ .endpoint("http://localhost:10000")
+ .credentials(ACCOUNT, "?creds")
+ .modules(ImmutableSet.<Module> of(new
BaseRestApiTest.MockModule(), new NullLoggingModule(), new
AppendAccountToEndpointModule()))
+ .buildInjector()
+ .getInstance(AppendAccountToEndpoint.class)
+ .get()
+ .toString();
+
+ assertEquals(adjustedUri, "http://localhost:10000/foo/");
+
+ }
+
+
+}
diff --git
a/providers/azureblob/src/test/java/org/jclouds/azure/storage/util/storageurl/StorageAccountInVhostTest.java
b/providers/azureblob/src/test/java/org/jclouds/azure/storage/util/storageurl/StorageAccountInVhostTest.java
new file mode 100644
index 0000000..5bf23e8
--- /dev/null
+++
b/providers/azureblob/src/test/java/org/jclouds/azure/storage/util/storageurl/StorageAccountInVhostTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.azure.storage.util.storageurl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import com.google.inject.util.Modules;
+import org.jclouds.ContextBuilder;
+import org.jclouds.azureblob.config.AppendAccountToEndpointModule;
+import org.jclouds.domain.Credentials;
+import org.jclouds.logging.config.NullLoggingModule;
+import org.jclouds.rest.internal.BaseRestApiTest;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit")
+public class StorageAccountInVhostTest {
+
+ private static final String ACCOUNT = "foo";
+
+ @Test
+ void testDefaultEndpointWhenNoneSupplied() {
+
+ StorageAccountInVhost target = new StorageAccountInVhost(
+ () -> null,
+ () -> new Credentials(ACCOUNT, "creds")
+ );
+
+ assertEquals(target.get().toString(),
"https://foo.blob.core.windows.net/");
+ }
+
+ @Test
+ void testCustomEndpointWithoutTrailingSlash() {
+
+ StorageAccountInVhost target = new StorageAccountInVhost(
+ () -> URI.create("https://foo2.blob.core.windows.net/"),
+ () -> new Credentials(ACCOUNT, "creds")
+ );
+
+ assertEquals(target.get().toString(),
"https://foo2.blob.core.windows.net/");
+ }
+
+ @Test
+ void testCustomEndpointWithTrailingSlash() {
+
+ StorageAccountInVhost target = new StorageAccountInVhost(
+ () -> URI.create("https://foo2.blob.core.windows.net/"),
+ () -> new Credentials(ACCOUNT, "creds")
+ );
+
+ assertEquals(target.get().toString(),
"https://foo2.blob.core.windows.net/");
+
+ }
+
+ @Test
+ void testInsideContext() {
+ String adjustedUri = ContextBuilder
+ .newBuilder("azureblob")
+ .endpoint("https://foo2.blob.core.windows.net")
+ .credentials(ACCOUNT, "?creds")
+ .modules(ImmutableSet.<Module> of(new
BaseRestApiTest.MockModule(), new NullLoggingModule()))
+ .buildInjector()
+ .getInstance(StorageAccountInVhost.class)
+ .get()
+ .toString();
+ Modules.override(new AppendAccountToEndpointModule());
+ assertEquals(adjustedUri, "https://foo2.blob.core.windows.net/");
+
+ }
+}