diff --git a/CHANGELOG.md b/CHANGELOG.md
index be5283f627e59..ef552d3b093a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,91 @@ All notable changes to this project are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). See the [CONTRIBUTING guide](./CONTRIBUTING.md#Changelog) for instructions on how to add changelog entries.
+## [Unreleased 3.0]
+### Added
+- Support for HTTP/2 (server-side) ([#3847](https://github.com/opensearch-project/OpenSearch/pull/3847))
+- Add getter for path field in NestedQueryBuilder ([#4636](https://github.com/opensearch-project/OpenSearch/pull/4636))
+- Allow mmap to use new JDK-19 preview APIs in Apache Lucene 9.4+ ([#5151](https://github.com/opensearch-project/OpenSearch/pull/5151))
+- Add events correlation engine plugin ([#6854](https://github.com/opensearch-project/OpenSearch/issues/6854))
+- Implement on behalf of token passing for extensions ([#8679](https://github.com/opensearch-project/OpenSearch/pull/8679), [#10664](https://github.com/opensearch-project/OpenSearch/pull/10664))
+- Provide service accounts tokens to extensions ([#9618](https://github.com/opensearch-project/OpenSearch/pull/9618))
+- [AdmissionControl] Added changes for AdmissionControl Interceptor and AdmissionControlService for RateLimiting ([#9286](https://github.com/opensearch-project/OpenSearch/pull/9286))
+- GHA to verify checklist items completion in PR descriptions ([#10800](https://github.com/opensearch-project/OpenSearch/pull/10800))
+- Allow to pass the list settings through environment variables (like [], ["a", "b", "c"], ...) ([#10625](https://github.com/opensearch-project/OpenSearch/pull/10625))
+- [Admission Control] Integrate CPU AC with ResourceUsageCollector and add CPU AC stats to nodes/stats ([#10887](https://github.com/opensearch-project/OpenSearch/pull/10887))
+
+### Dependencies
+- Bump `log4j-core` from 2.18.0 to 2.19.0
+- Bump `forbiddenapis` from 3.3 to 3.4
+- Bump `avro` from 1.11.1 to 1.11.2
+- Bump `woodstox-core` from 6.3.0 to 6.3.1
+- Bump `xmlbeans` from 5.1.0 to 5.1.1 ([#4354](https://github.com/opensearch-project/OpenSearch/pull/4354))
+- Bump `reactor-netty-core` from 1.0.19 to 1.0.22 ([#4447](https://github.com/opensearch-project/OpenSearch/pull/4447))
+- Bump `reactive-streams` from 1.0.3 to 1.0.4 ([#4488](https://github.com/opensearch-project/OpenSearch/pull/4488))
+- Bump `jempbox` from 1.8.16 to 1.8.17 ([#4550](https://github.com/opensearch-project/OpenSearch/pull/4550))
+- Update to Gradle 7.6 and JDK-19 ([#4973](https://github.com/opensearch-project/OpenSearch/pull/4973))
+- Update Apache Lucene to 9.5.0-snapshot-d5cef1c ([#5570](https://github.com/opensearch-project/OpenSearch/pull/5570))
+- Bump `maven-model` from 3.6.2 to 3.8.6 ([#5599](https://github.com/opensearch-project/OpenSearch/pull/5599))
+- Bump `maxmind-db` from 2.1.0 to 3.0.0 ([#5601](https://github.com/opensearch-project/OpenSearch/pull/5601))
+- Bump `wiremock-jre8-standalone` from 2.33.2 to 2.35.0
+- Bump `gson` from 2.10 to 2.10.1
+- Bump `com.google.code.gson:gson` from 2.10 to 2.10.1
+- Bump `com.maxmind.geoip2:geoip2` from 4.0.0 to 4.0.1
+- Bump `com.avast.gradle:gradle-docker-compose-plugin` from 0.16.11 to 0.16.12
+- Bump `org.apache.commons:commons-configuration2` from 2.8.0 to 2.9.0
+- Bump `com.netflix.nebula:nebula-publishing-plugin` from 19.2.0 to 20.3.0
+- Bump `io.opencensus:opencensus-api` from 0.18.0 to 0.31.1 ([#7291](https://github.com/opensearch-project/OpenSearch/pull/7291))
+- OpenJDK Update (April 2023 Patch releases) ([#7344](https://github.com/opensearch-project/OpenSearch/pull/7344)
+- Bump `com.google.http-client:google-http-client:1.43.2` from 1.42.0 to 1.43.2 ([7928](https://github.com/opensearch-project/OpenSearch/pull/7928)))
+- Add Opentelemetry dependencies ([#7543](https://github.com/opensearch-project/OpenSearch/issues/7543))
+- Bump `org.bouncycastle:bcprov-jdk15on` to `org.bouncycastle:bcprov-jdk15to18` version 1.75 ([#8247](https://github.com/opensearch-project/OpenSearch/pull/8247))
+- Bump `org.bouncycastle:bcmail-jdk15on` to `org.bouncycastle:bcmail-jdk15to18` version 1.75 ([#8247](https://github.com/opensearch-project/OpenSearch/pull/8247))
+- Bump `org.bouncycastle:bcpkix-jdk15on` to `org.bouncycastle:bcpkix-jdk15to18` version 1.75 ([#8247](https://github.com/opensearch-project/OpenSearch/pull/8247))
+- Bump JNA version from 5.5 to 5.13 ([#9963](https://github.com/opensearch-project/OpenSearch/pull/9963))
+- Bump `org.eclipse.jgit` from 6.5.0 to 6.7.0 ([#10147](https://github.com/opensearch-project/OpenSearch/pull/10147))
+- Bump OpenTelemetry from 1.30.1 to 1.31.0 ([#10617](https://github.com/opensearch-project/OpenSearch/pull/10617))
+- Bump OpenTelemetry from 1.31.0 to 1.32.0 and OpenTelemetry Semconv from 1.21.0-alpha to 1.23.1-alpha ([#11305](https://github.com/opensearch-project/OpenSearch/pull/11305))
+
+### Changed
+- [CCR] Add getHistoryOperationsFromTranslog method to fetch the history snapshot from translogs ([#3948](https://github.com/opensearch-project/OpenSearch/pull/3948))
+- Relax visibility of the HTTP_CHANNEL_KEY and HTTP_SERVER_CHANNEL_KEY to make it possible for the plugins to access associated Netty4HttpChannel / Netty4HttpServerChannel instance ([#4638](https://github.com/opensearch-project/OpenSearch/pull/4638))
+- Migrate client transports to Apache HttpClient / Core 5.x ([#4459](https://github.com/opensearch-project/OpenSearch/pull/4459))
+- Change http code on create index API with bad input raising NotXContentException from 500 to 400 ([#4773](https://github.com/opensearch-project/OpenSearch/pull/4773))
+- Improve summary error message for invalid setting updates ([#4792](https://github.com/opensearch-project/OpenSearch/pull/4792))
+- Return 409 Conflict HTTP status instead of 503 on failure to concurrently execute snapshots ([#8986](https://github.com/opensearch-project/OpenSearch/pull/5855))
+- Add task completion count in search backpressure stats API ([#10028](https://github.com/opensearch-project/OpenSearch/pull/10028/))
+- Deprecate CamelCase `PathHierarchy` tokenizer name in favor to lowercase `path_hierarchy` ([#10894](https://github.com/opensearch-project/OpenSearch/pull/10894))
+- Switched to more reliable OpenSearch Lucene snapshot location([#11728](https://github.com/opensearch-project/OpenSearch/pull/11728))
+- Added support for Google Application Default Credentials in repository-gcs ([#8394](https://github.com/opensearch-project/OpenSearch/pull/8394))
+
+### Deprecated
+
+### Removed
+- Remove deprecated code to add node name into log pattern of log4j property file ([#4568](https://github.com/opensearch-project/OpenSearch/pull/4568))
+- Unused object and import within TransportClusterAllocationExplainAction ([#4639](https://github.com/opensearch-project/OpenSearch/pull/4639))
+- Remove LegacyESVersion.V_7_0_* and V_7_1_* Constants ([#2768](https://https://github.com/opensearch-project/OpenSearch/pull/2768))
+- Remove LegacyESVersion.V_7_2_ and V_7_3_ Constants ([#4702](https://github.com/opensearch-project/OpenSearch/pull/4702))
+- Always auto release the flood stage block ([#4703](https://github.com/opensearch-project/OpenSearch/pull/4703))
+- Remove LegacyESVersion.V_7_4_ and V_7_5_ Constants ([#4704](https://github.com/opensearch-project/OpenSearch/pull/4704))
+- Remove Legacy Version support from Snapshot/Restore Service ([#4728](https://github.com/opensearch-project/OpenSearch/pull/4728))
+- Remove deprecated serialization logic from pipeline aggs ([#4847](https://github.com/opensearch-project/OpenSearch/pull/4847))
+- Remove unused private methods ([#4926](https://github.com/opensearch-project/OpenSearch/pull/4926))
+- Remove LegacyESVersion.V_7_8_ and V_7_9_ Constants ([#4855](https://github.com/opensearch-project/OpenSearch/pull/4855))
+- Remove LegacyESVersion.V_7_6_ and V_7_7_ Constants ([#4837](https://github.com/opensearch-project/OpenSearch/pull/4837))
+- Remove LegacyESVersion.V_7_10_ Constants ([#5018](https://github.com/opensearch-project/OpenSearch/pull/5018))
+- Remove Version.V_1_ Constants ([#5021](https://github.com/opensearch-project/OpenSearch/pull/5021))
+- Remove custom Map, List and Set collection classes ([#6871](https://github.com/opensearch-project/OpenSearch/pull/6871))
+
+### Fixed
+- Fix 'org.apache.hc.core5.http.ParseException: Invalid protocol version' under JDK 16+ ([#4827](https://github.com/opensearch-project/OpenSearch/pull/4827))
+- Fix compression support for h2c protocol ([#4944](https://github.com/opensearch-project/OpenSearch/pull/4944))
+- Don't over-allocate in HeapBufferedAsyncEntityConsumer in order to consume the response ([#9993](https://github.com/opensearch-project/OpenSearch/pull/9993))
+- Update supported version for max_shard_size parameter in Shrink API ([#11439](https://github.com/opensearch-project/OpenSearch/pull/11439))
+- Fix typo in API annotation check message ([11836](https://github.com/opensearch-project/OpenSearch/pull/11836))
+- Update supported version for must_exist parameter in update aliases API ([#11872](https://github.com/opensearch-project/OpenSearch/pull/11872))
+
+### Security
+
## [Unreleased 2.x]
### Added
- [Admission control] Add Resource usage collector service and resource usage tracker ([#10695](https://github.com/opensearch-project/OpenSearch/pull/10695))
diff --git a/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleApplicationDefaultCredentials.java b/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleApplicationDefaultCredentials.java
new file mode 100644
index 0000000000000..5002ab9a2e704
--- /dev/null
+++ b/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleApplicationDefaultCredentials.java
@@ -0,0 +1,33 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.repositories.gcs;
+
+import com.google.auth.oauth2.GoogleCredentials;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+
+/**
+ * This class facilitates to fetch Application Default Credentials
+ * see How Application Default Credentials works
+ */
+public class GoogleApplicationDefaultCredentials {
+ private static final Logger logger = LogManager.getLogger(GoogleApplicationDefaultCredentials.class);
+
+ public GoogleCredentials get() {
+ GoogleCredentials credentials = null;
+ try {
+ credentials = SocketAccess.doPrivilegedIOException(GoogleCredentials::getApplicationDefault);
+ } catch (IOException e) {
+ logger.error("Failed to retrieve \"Application Default Credentials\"", e);
+ }
+ return credentials;
+ }
+}
diff --git a/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleCloudStorageService.java b/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleCloudStorageService.java
index c9ebb3acaf3e5..83a4146c99b99 100644
--- a/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleCloudStorageService.java
+++ b/plugins/repository-gcs/src/main/java/org/opensearch/repositories/gcs/GoogleCloudStorageService.java
@@ -36,6 +36,7 @@
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.ServiceOptions;
import com.google.cloud.http.HttpTransportOptions;
@@ -70,6 +71,16 @@ public class GoogleCloudStorageService {
*/
private volatile Map clientCache = emptyMap();
+ final private GoogleApplicationDefaultCredentials googleApplicationDefaultCredentials;
+
+ public GoogleCloudStorageService() {
+ this.googleApplicationDefaultCredentials = new GoogleApplicationDefaultCredentials();
+ }
+
+ public GoogleCloudStorageService(GoogleApplicationDefaultCredentials googleApplicationDefaultCredentials) {
+ this.googleApplicationDefaultCredentials = googleApplicationDefaultCredentials;
+ }
+
/**
* Refreshes the client settings and clears the client cache. Subsequent calls to
* {@code GoogleCloudStorageService#client} will return new clients constructed
@@ -213,10 +224,11 @@ StorageOptions createStorageOptions(
storageOptionsBuilder.setProjectId(clientSettings.getProjectId());
}
if (clientSettings.getCredential() == null) {
- logger.warn(
- "\"Application Default Credentials\" are not supported out of the box."
- + " Additional file system permissions have to be granted to the plugin."
- );
+ logger.info("\"Application Default Credentials\" will be in use");
+ final GoogleCredentials credentials = googleApplicationDefaultCredentials.get();
+ if (credentials != null) {
+ storageOptionsBuilder.setCredentials(credentials);
+ }
} else {
ServiceAccountCredentials serviceAccountCredentials = clientSettings.getCredential();
// override token server URI
diff --git a/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/GoogleCloudStorageServiceTests.java b/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/GoogleCloudStorageServiceTests.java
index a531555debefb..58e412684ed5a 100644
--- a/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/GoogleCloudStorageServiceTests.java
+++ b/plugins/repository-gcs/src/test/java/org/opensearch/repositories/gcs/GoogleCloudStorageServiceTests.java
@@ -33,8 +33,10 @@
package org.opensearch.repositories.gcs;
import com.google.auth.Credentials;
+import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.http.HttpTransportOptions;
import com.google.cloud.storage.Storage;
+import com.google.cloud.storage.StorageOptions;
import org.opensearch.common.settings.MockSecureSettings;
import org.opensearch.common.settings.Setting;
import org.opensearch.common.settings.Settings;
@@ -42,30 +44,38 @@
import org.opensearch.core.common.bytes.BytesReference;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.test.OpenSearchTestCase;
+import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Base64;
import java.util.Locale;
import java.util.UUID;
+import org.mockito.Mockito;
+
import static org.opensearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
public class GoogleCloudStorageServiceTests extends OpenSearchTestCase {
+ final TimeValue connectTimeValue = TimeValue.timeValueNanos(randomIntBetween(0, 2000000));
+ final TimeValue readTimeValue = TimeValue.timeValueNanos(randomIntBetween(0, 2000000));
+ final String applicationName = randomAlphaOfLength(randomIntBetween(1, 10)).toLowerCase(Locale.ROOT);
+ final String endpoint = randomFrom("http://", "https://")
+ + randomFrom("www.opensearch.org", "www.googleapis.com", "localhost/api", "google.com/oauth")
+ + ":"
+ + randomIntBetween(1, 65535);
+ final String projectIdName = randomAlphaOfLength(randomIntBetween(1, 10)).toLowerCase(Locale.ROOT);
+
public void testClientInitializer() throws Exception {
final String clientName = randomAlphaOfLength(randomIntBetween(1, 10)).toLowerCase(Locale.ROOT);
- final TimeValue connectTimeValue = TimeValue.timeValueNanos(randomIntBetween(0, 2000000));
- final TimeValue readTimeValue = TimeValue.timeValueNanos(randomIntBetween(0, 2000000));
- final String applicationName = randomAlphaOfLength(randomIntBetween(1, 10)).toLowerCase(Locale.ROOT);
- final String endpoint = randomFrom("http://", "https://")
- + randomFrom("www.opensearch.org", "www.googleapis.com", "localhost/api", "google.com/oauth")
- + ":"
- + randomIntBetween(1, 65535);
- final String projectIdName = randomAlphaOfLength(randomIntBetween(1, 10)).toLowerCase(Locale.ROOT);
final Settings settings = Settings.builder()
.put(
GoogleCloudStorageClientSettings.CONNECT_TIMEOUT_SETTING.getConcreteSettingForNamespace(clientName).getKey(),
@@ -82,31 +92,35 @@ public void testClientInitializer() throws Exception {
.put(GoogleCloudStorageClientSettings.ENDPOINT_SETTING.getConcreteSettingForNamespace(clientName).getKey(), endpoint)
.put(GoogleCloudStorageClientSettings.PROJECT_ID_SETTING.getConcreteSettingForNamespace(clientName).getKey(), projectIdName)
.build();
- final GoogleCloudStorageService service = new GoogleCloudStorageService();
+ GoogleCredentials mockGoogleCredentials = Mockito.mock(GoogleCredentials.class);
+ GoogleApplicationDefaultCredentials mockDefaultCredentials = Mockito.mock(GoogleApplicationDefaultCredentials.class);
+ Mockito.when(mockDefaultCredentials.get()).thenReturn(mockGoogleCredentials);
+
+ final GoogleCloudStorageService service = new GoogleCloudStorageService(mockDefaultCredentials);
service.refreshAndClearCache(GoogleCloudStorageClientSettings.load(settings));
GoogleCloudStorageOperationsStats statsCollector = new GoogleCloudStorageOperationsStats("bucket");
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> service.client("another_client", "repo", statsCollector)
);
- assertThat(e.getMessage(), Matchers.startsWith("Unknown client name"));
+ MatcherAssert.assertThat(e.getMessage(), Matchers.startsWith("Unknown client name"));
assertSettingDeprecationsAndWarnings(
new Setting>[] { GoogleCloudStorageClientSettings.APPLICATION_NAME_SETTING.getConcreteSettingForNamespace(clientName) }
);
final Storage storage = service.client(clientName, "repo", statsCollector);
- assertThat(storage.getOptions().getApplicationName(), Matchers.containsString(applicationName));
- assertThat(storage.getOptions().getHost(), Matchers.is(endpoint));
- assertThat(storage.getOptions().getProjectId(), Matchers.is(projectIdName));
- assertThat(storage.getOptions().getTransportOptions(), Matchers.instanceOf(HttpTransportOptions.class));
- assertThat(
+ MatcherAssert.assertThat(storage.getOptions().getApplicationName(), Matchers.containsString(applicationName));
+ MatcherAssert.assertThat(storage.getOptions().getHost(), Matchers.is(endpoint));
+ MatcherAssert.assertThat(storage.getOptions().getProjectId(), Matchers.is(projectIdName));
+ MatcherAssert.assertThat(storage.getOptions().getTransportOptions(), Matchers.instanceOf(HttpTransportOptions.class));
+ MatcherAssert.assertThat(
((HttpTransportOptions) storage.getOptions().getTransportOptions()).getConnectTimeout(),
Matchers.is((int) connectTimeValue.millis())
);
- assertThat(
+ MatcherAssert.assertThat(
((HttpTransportOptions) storage.getOptions().getTransportOptions()).getReadTimeout(),
Matchers.is((int) readTimeValue.millis())
);
- assertThat(storage.getOptions().getCredentials(), Matchers.nullValue(Credentials.class));
+ MatcherAssert.assertThat(storage.getOptions().getCredentials(), Matchers.instanceOf(Credentials.class));
}
public void testReinitClientSettings() throws Exception {
@@ -122,33 +136,33 @@ public void testReinitClientSettings() throws Exception {
final GoogleCloudStorageService storageService = plugin.storageService;
GoogleCloudStorageOperationsStats statsCollector = new GoogleCloudStorageOperationsStats("bucket");
final Storage client11 = storageService.client("gcs1", "repo1", statsCollector);
- assertThat(client11.getOptions().getProjectId(), equalTo("project_gcs11"));
+ MatcherAssert.assertThat(client11.getOptions().getProjectId(), equalTo("project_gcs11"));
final Storage client12 = storageService.client("gcs2", "repo2", statsCollector);
- assertThat(client12.getOptions().getProjectId(), equalTo("project_gcs12"));
+ MatcherAssert.assertThat(client12.getOptions().getProjectId(), equalTo("project_gcs12"));
// client 3 is missing
final IllegalArgumentException e1 = expectThrows(
IllegalArgumentException.class,
() -> storageService.client("gcs3", "repo3", statsCollector)
);
- assertThat(e1.getMessage(), containsString("Unknown client name [gcs3]."));
+ MatcherAssert.assertThat(e1.getMessage(), containsString("Unknown client name [gcs3]."));
// update client settings
plugin.reload(settings2);
// old client 1 not changed
- assertThat(client11.getOptions().getProjectId(), equalTo("project_gcs11"));
+ MatcherAssert.assertThat(client11.getOptions().getProjectId(), equalTo("project_gcs11"));
// new client 1 is changed
final Storage client21 = storageService.client("gcs1", "repo1", statsCollector);
- assertThat(client21.getOptions().getProjectId(), equalTo("project_gcs21"));
+ MatcherAssert.assertThat(client21.getOptions().getProjectId(), equalTo("project_gcs21"));
// old client 2 not changed
- assertThat(client12.getOptions().getProjectId(), equalTo("project_gcs12"));
+ MatcherAssert.assertThat(client12.getOptions().getProjectId(), equalTo("project_gcs12"));
// new client2 is gone
final IllegalArgumentException e2 = expectThrows(
IllegalArgumentException.class,
() -> storageService.client("gcs2", "repo2", statsCollector)
);
- assertThat(e2.getMessage(), containsString("Unknown client name [gcs2]."));
+ MatcherAssert.assertThat(e2.getMessage(), containsString("Unknown client name [gcs2]."));
// client 3 emerged
final Storage client23 = storageService.client("gcs3", "repo3", statsCollector);
- assertThat(client23.getOptions().getProjectId(), equalTo("project_gcs23"));
+ MatcherAssert.assertThat(client23.getOptions().getProjectId(), equalTo("project_gcs23"));
}
}
@@ -193,4 +207,72 @@ public void testToTimeout() {
assertEquals(-1, GoogleCloudStorageService.toTimeout(TimeValue.ZERO).intValue());
assertEquals(0, GoogleCloudStorageService.toTimeout(TimeValue.MINUS_ONE).intValue());
}
+
+ /**
+ * The following method test the Google Application Default Credential instead of
+ * using service account file.
+ * Considered use of JUnit Mocking due to static method GoogleCredentials.getApplicationDefault
+ * and avoiding environment variables to set which later use GCE.
+ * @throws Exception
+ */
+ public void testApplicationDefaultCredential() throws Exception {
+ GoogleCloudStorageClientSettings settings = getGCSClientSettingsWithoutCredentials();
+ GoogleCredentials mockGoogleCredentials = Mockito.mock(GoogleCredentials.class);
+ HttpTransportOptions mockHttpTransportOptions = Mockito.mock(HttpTransportOptions.class);
+ GoogleApplicationDefaultCredentials mockDefaultCredentials = Mockito.mock(GoogleApplicationDefaultCredentials.class);
+ Mockito.when(mockDefaultCredentials.get()).thenReturn(mockGoogleCredentials);
+
+ GoogleCloudStorageService service = new GoogleCloudStorageService(mockDefaultCredentials);
+ StorageOptions storageOptions = service.createStorageOptions(settings, mockHttpTransportOptions);
+ assertNotNull(storageOptions);
+ assertEquals(storageOptions.getCredentials().toString(), mockGoogleCredentials.toString());
+ }
+
+ /**
+ * The application default credential throws exception when there are
+ * no Environment Variables provided or Google Compute Engine is not running
+ * @throws Exception
+ */
+ public void testApplicationDefaultCredentialsWhenNoSettingProvided() throws Exception {
+ GoogleCloudStorageClientSettings settings = getGCSClientSettingsWithoutCredentials();
+ HttpTransportOptions mockHttpTransportOptions = Mockito.mock(HttpTransportOptions.class);
+ GoogleCloudStorageService service = new GoogleCloudStorageService();
+ StorageOptions storageOptions = service.createStorageOptions(settings, mockHttpTransportOptions);
+
+ Exception exception = assertThrows(IOException.class, GoogleCredentials::getApplicationDefault);
+ assertNotNull(storageOptions);
+ assertNull(storageOptions.getCredentials());
+ MatcherAssert.assertThat(exception.getMessage(), containsString("The Application Default Credentials are not available"));
+ }
+
+ /**
+ * The application default credential throws IOException when it is
+ * used without GoogleCloudStorageService
+ */
+ public void testDefaultCredentialsThrowsExceptionWithoutGCStorageService() {
+ GoogleApplicationDefaultCredentials googleApplicationDefaultCredentials = new GoogleApplicationDefaultCredentials();
+ GoogleCredentials credentials = googleApplicationDefaultCredentials.get();
+ assertNull(credentials);
+ Exception exception = assertThrows(IOException.class, GoogleCredentials::getApplicationDefault);
+ MatcherAssert.assertThat(exception.getMessage(), containsString("The Application Default Credentials are not available"));
+ }
+
+ /**
+ * This is a helper method to provide GCS Client settings without credentials
+ * @return GoogleCloudStorageClientSettings
+ * @throws URISyntaxException
+ */
+ private GoogleCloudStorageClientSettings getGCSClientSettingsWithoutCredentials() throws URISyntaxException {
+ return new GoogleCloudStorageClientSettings(
+ null,
+ endpoint,
+ projectIdName,
+ connectTimeValue,
+ readTimeValue,
+ applicationName,
+ new URI(""),
+ new ProxySettings(Proxy.Type.DIRECT, null, 0, null, null)
+ );
+ }
+
}