diff --git a/examples/pom.xml b/examples/pom.xml
index dae76a2..e4d6a18 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -6,7 +6,7 @@
io.harness.featureflags
examples
- 1.2.4
+ 1.2.5
8
@@ -33,7 +33,7 @@
io.harness
ff-java-server-sdk
- 1.2.4
+ 1.2.5
diff --git a/pom.xml b/pom.xml
index 0955556..78ef544 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.harness
ff-java-server-sdk
- 1.2.4
+ 1.2.5
jar
Harness Feature Flag Java Server SDK
Harness Feature Flag Java Server SDK
diff --git a/src/main/java/io/harness/cf/client/connector/HarnessConnector.java b/src/main/java/io/harness/cf/client/connector/HarnessConnector.java
index dddf78e..dbbcc00 100644
--- a/src/main/java/io/harness/cf/client/connector/HarnessConnector.java
+++ b/src/main/java/io/harness/cf/client/connector/HarnessConnector.java
@@ -32,7 +32,7 @@ public class HarnessConnector implements Connector, AutoCloseable {
private final HarnessConfig options;
private String token;
- private String environment;
+ private String environmentUuid;
private String cluster;
private String environmentIdentifier;
private String accountID;
@@ -196,36 +196,50 @@ protected void processToken(@NonNull final String token) {
Claim claim = gson.fromJson(decoded, Claim.class);
log.debug("Claims successfully parsed from decoded payload");
- environment = claim.getEnvironment();
+ environmentUuid = claim.getEnvironment();
cluster = claim.getClusterIdentifier();
- accountID = claim.getAccountID();
- environmentIdentifier = claim.getEnvironmentIdentifier();
+ accountID = emptyToNull(claim.getAccountID());
+ environmentIdentifier = getEnvOrUuidEnv(claim.getEnvironmentIdentifier(), environmentUuid);
- api.getApiClient().addDefaultHeader("Harness-EnvironmentID", environmentIdentifier);
- api.getApiClient().addDefaultHeader("Harness-AccountID", accountID);
- metricsApi.getApiClient().addDefaultHeader("Harness-EnvironmentID", environmentIdentifier);
- metricsApi.getApiClient().addDefaultHeader("Harness-AccountID", accountID);
+ if (environmentIdentifier != null) {
+ api.getApiClient().addDefaultHeader("Harness-EnvironmentID", environmentIdentifier);
+ metricsApi.getApiClient().addDefaultHeader("Harness-EnvironmentID", environmentIdentifier);
+ }
+
+ if (accountID != null) {
+ api.getApiClient().addDefaultHeader("Harness-AccountID", accountID);
+ metricsApi.getApiClient().addDefaultHeader("Harness-AccountID", accountID);
+ }
log.info(
"Token successfully processed, environment {}, cluster {}, account {}, environmentIdentifier {}",
- environment,
+ environmentUuid,
cluster,
accountID,
environmentIdentifier);
}
+ private String getEnvOrUuidEnv(String env, String envUuid) {
+ String envToReturn = emptyToNull(env);
+ return (envToReturn == null) ? emptyToNull(envUuid) : envToReturn;
+ }
+
+ private String emptyToNull(String jsonValue) {
+ return (jsonValue != null && !jsonValue.trim().isEmpty()) ? jsonValue : null;
+ }
+
@Override
public List getFlags() throws ConnectorException {
final String requestId = UUID.randomUUID().toString();
MDC.put(REQUEST_ID_KEY, requestId);
- log.info("Fetching flags on env {} and cluster {}", this.environment, this.cluster);
+ log.info("Fetching flags on env {} and cluster {}", this.environmentUuid, this.cluster);
List featureConfig = new ArrayList<>();
try {
- featureConfig = api.getFeatureConfig(environment, cluster);
+ featureConfig = api.getFeatureConfig(environmentUuid, cluster);
log.info(
"Total configurations fetched: {} on env {} and cluster {}",
featureConfig.size(),
- this.environment,
+ this.environmentUuid,
this.cluster);
if (log.isTraceEnabled()) {
log.trace("Got the following features: " + featureConfig);
@@ -234,7 +248,7 @@ public List getFlags() throws ConnectorException {
} catch (ApiException e) {
log.error(
"Exception was raised while fetching the flags on env {} and cluster {}",
- this.environment,
+ this.environmentUuid,
this.cluster,
e);
throw new ConnectorException(e.getMessage(), e.getCode(), e.getMessage());
@@ -248,21 +262,21 @@ public FeatureConfig getFlag(@NonNull final String identifier) throws ConnectorE
final String requestId = UUID.randomUUID().toString();
MDC.put(REQUEST_ID_KEY, requestId);
log.debug(
- "Fetch flag {} from env {} and cluster {}", identifier, this.environment, this.cluster);
+ "Fetch flag {} from env {} and cluster {}", identifier, this.environmentUuid, this.cluster);
try {
FeatureConfig featureConfigByIdentifier =
- api.getFeatureConfigByIdentifier(identifier, environment, cluster);
+ api.getFeatureConfigByIdentifier(identifier, environmentUuid, cluster);
log.debug(
"Flag {} successfully fetched from env {} and cluster {}",
identifier,
- this.environment,
+ this.environmentUuid,
this.cluster);
return featureConfigByIdentifier;
} catch (ApiException e) {
log.error(
"Exception was raised while fetching the flag {} on env {} and cluster {}",
identifier,
- this.environment,
+ this.environmentUuid,
this.cluster,
e);
throw new ConnectorException(e.getMessage(), e.getCode(), e.getMessage());
@@ -276,20 +290,22 @@ public List getSegments() throws ConnectorException {
final String requestId = UUID.randomUUID().toString();
MDC.put(REQUEST_ID_KEY, requestId);
log.debug(
- "Fetching target groups on environment {} and cluster {}", this.environment, this.cluster);
+ "Fetching target groups on environment {} and cluster {}",
+ this.environmentUuid,
+ this.cluster);
List allSegments = new ArrayList<>();
try {
- allSegments = api.getAllSegments(environment, cluster);
+ allSegments = api.getAllSegments(environmentUuid, cluster);
log.debug(
"Total target groups fetched: {} on env {} and cluster {}",
allSegments.size(),
- this.environment,
+ this.environmentUuid,
this.cluster);
return allSegments;
} catch (ApiException e) {
log.error(
"Exception was raised while fetching the target groups on env {} and cluster {} : httpCode={} message={}",
- this.environment,
+ this.environmentUuid,
this.cluster,
e.getCode(),
e.getMessage(),
@@ -307,21 +323,22 @@ public Segment getSegment(@NonNull final String identifier) throws ConnectorExce
log.debug(
"Fetching the target group {} on environment {} and cluster {}",
identifier,
- this.environment,
+ this.environmentUuid,
this.cluster);
try {
- Segment segmentByIdentifier = api.getSegmentByIdentifier(identifier, environment, cluster);
+ Segment segmentByIdentifier =
+ api.getSegmentByIdentifier(identifier, environmentUuid, cluster);
log.debug(
"Segment {} successfully fetched from env {} and cluster {}",
identifier,
- this.environment,
+ this.environmentUuid,
this.cluster);
return segmentByIdentifier;
} catch (ApiException e) {
log.error(
"Exception was raised while fetching the target group {} on env {} and cluster {}",
identifier,
- this.environment,
+ this.environmentUuid,
this.cluster,
e);
throw new ConnectorException(e.getMessage(), e.getCode(), e.getMessage());
@@ -334,17 +351,18 @@ public Segment getSegment(@NonNull final String identifier) throws ConnectorExce
public void postMetrics(@NonNull final Metrics metrics) throws ConnectorException {
final String requestId = UUID.randomUUID().toString();
MDC.put(REQUEST_ID_KEY, requestId);
- log.debug("Uploading metrics on environment {} and cluster {}", this.environment, this.cluster);
+ log.debug(
+ "Uploading metrics on environment {} and cluster {}", this.environmentUuid, this.cluster);
try {
- metricsApi.postMetrics(environment, cluster, metrics);
+ metricsApi.postMetrics(environmentUuid, cluster, metrics);
log.debug(
"Metrics uploaded successfully on environment {} and cluster {}",
- this.environment,
+ this.environmentUuid,
this.cluster);
} catch (ApiException e) {
log.error(
"Exception was raised while uploading metrics on env {} and cluster {}",
- this.environment,
+ this.environmentUuid,
this.cluster,
e);
throw new ConnectorException(e.getMessage(), e.getCode(), e.getMessage());
@@ -366,8 +384,14 @@ public Service stream(@NonNull final Updater updater) throws ConnectorException
map.put("Authorization", "Bearer " + token);
map.put("API-Key", apiKey);
map.put("Harness-SDK-Info", HARNESS_SDK_INFO);
- map.put("Harness-EnvironmentID", environmentIdentifier);
- map.put("Harness-AccountID", accountID);
+
+ if (environmentIdentifier != null) {
+ map.put("Harness-EnvironmentID", environmentIdentifier);
+ }
+
+ if (accountID != null) {
+ map.put("Harness-AccountID", accountID);
+ }
log.info("Initialize new EventSource instance");
eventSource =
@@ -431,4 +455,15 @@ private static boolean isNullOrEmpty(String string) {
options,
retryBackOffDelay);
}
+
+ HarnessConnector(
+ @NonNull String apiKey,
+ @NonNull HarnessConfig options,
+ ClientApi clientApi,
+ MetricsApi metricsApi) {
+ this.apiKey = apiKey;
+ this.options = options;
+ this.api = clientApi;
+ this.metricsApi = metricsApi;
+ }
}
diff --git a/src/test/java/io/harness/cf/client/api/CfClientTest.java b/src/test/java/io/harness/cf/client/api/CfClientTest.java
index b9c23e7..b003b77 100644
--- a/src/test/java/io/harness/cf/client/api/CfClientTest.java
+++ b/src/test/java/io/harness/cf/client/api/CfClientTest.java
@@ -32,6 +32,7 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
class CfClientTest {
@@ -511,6 +512,72 @@ void shouldRetryThenReAuthenticateWhen403IsReturnedOnGetAllSegments() throws Exc
}
}
+ @ParameterizedTest
+ @NullSource()
+ @ValueSource(strings = {"dummyAccId", "", " ", "\t", "\n", "\r"})
+ void shouldTestVariousJwtAccountIDs(String nextAccountId) throws Exception {
+ BaseConfig config =
+ BaseConfig.builder()
+ .pollIntervalInSeconds(1)
+ .analyticsEnabled(false)
+ .streamEnabled(true)
+ .debug(false)
+ .build();
+
+ JwtMissingFieldsAuthDispatcher webserverDispatcher =
+ new JwtMissingFieldsAuthDispatcher("devEnv", nextAccountId);
+
+ try (MockWebServer mockSvr = new MockWebServer()) {
+ mockSvr.setDispatcher(webserverDispatcher);
+ mockSvr.start();
+
+ try (CfClient client =
+ new CfClient(
+ makeConnectorWithMinimalRetryBackOff(mockSvr.getHostName(), mockSvr.getPort()),
+ config)) {
+
+ client.waitForInitialization();
+ webserverDispatcher.waitForAllEndpointsToBeCalled(15);
+ webserverDispatcher.getErrors().forEach(Throwable::printStackTrace);
+
+ assertTrue(webserverDispatcher.getErrors().isEmpty());
+ }
+ }
+ }
+
+ @ParameterizedTest
+ @NullSource()
+ @ValueSource(strings = {"dummyAccId", "", " ", "\t", "\n", "\r"})
+ void shouldTestVariousJwtEnvironmentIdentifiers(String nextEnvId) throws Exception {
+ BaseConfig config =
+ BaseConfig.builder()
+ .pollIntervalInSeconds(1)
+ .analyticsEnabled(false)
+ .streamEnabled(true)
+ .debug(false)
+ .build();
+
+ JwtMissingFieldsAuthDispatcher webserverDispatcher =
+ new JwtMissingFieldsAuthDispatcher(nextEnvId, "dummyAccount");
+
+ try (MockWebServer mockSvr = new MockWebServer()) {
+ mockSvr.setDispatcher(webserverDispatcher);
+ mockSvr.start();
+
+ try (CfClient client =
+ new CfClient(
+ makeConnectorWithMinimalRetryBackOff(mockSvr.getHostName(), mockSvr.getPort()),
+ config)) {
+
+ client.waitForInitialization();
+ webserverDispatcher.waitForAllEndpointsToBeCalled(15);
+ webserverDispatcher.getErrors().forEach(Throwable::printStackTrace);
+
+ assertTrue(webserverDispatcher.getErrors().isEmpty());
+ }
+ }
+ }
+
static class DummyCache implements Cache {
@Override
diff --git a/src/test/java/io/harness/cf/client/api/dispatchers/CannedResponses.java b/src/test/java/io/harness/cf/client/api/dispatchers/CannedResponses.java
index ce87b7f..2860992 100644
--- a/src/test/java/io/harness/cf/client/api/dispatchers/CannedResponses.java
+++ b/src/test/java/io/harness/cf/client/api/dispatchers/CannedResponses.java
@@ -39,6 +39,12 @@ public static MockResponse makeAuthResponse(int httpCode) {
return makeMockJsonResponse(httpCode, "{\"authToken\": \"" + makeDummyJwtToken() + "\"}");
}
+ public static MockResponse makeAuthResponse(
+ int httpCode, String envUuid, String env, String accountId) {
+ return makeMockJsonResponse(
+ httpCode, "{\"authToken\": \"" + makeDummyJwtToken(envUuid, env, accountId) + "\"}");
+ }
+
public static MockResponse makeMockStreamResponse(int httpCode, Event... events) {
final StringBuilder builder = new StringBuilder();
@@ -72,17 +78,35 @@ public static CannedResponses.Event makeFlagPatchEvent(String identifier, int ve
}
public static String makeDummyJwtToken() {
+ return makeDummyJwtToken(
+ "00000000-0000-0000-0000-000000000000", "Production", "aaaaa_BBBBB-cccccccccc");
+ }
+
+ public static String makeDummyJwtToken(String envUuid, String env, String accountID) {
final String header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
- final String payload =
- "{\"environment\":\"00000000-0000-0000-0000-000000000000\","
- + "\"environmentIdentifier\":\"Production\","
- + "\"project\":\"00000000-0000-0000-0000-000000000000\","
+ String payload = "{";
+
+ if (envUuid != null) {
+ payload += "\"environment\":\"" + envUuid + "\",";
+ }
+
+ if (env != null) {
+ payload += "\"environmentIdentifier\":\"" + env + "\",";
+ }
+
+ if (accountID != null) {
+ payload += "\"accountID\":\"" + accountID + "\",";
+ }
+
+ payload +=
+ "\"project\":\"00000000-0000-0000-0000-000000000000\","
+ "\"projectIdentifier\":\"dev\","
- + "\"accountID\":\"aaaaa_BBBBB-cccccccccc\","
+ "\"organization\":\"00000000-0000-0000-0000-000000000000\","
+ "\"organizationIdentifier\":\"default\","
+ "\"clusterIdentifier\":\"1\","
- + "\"key_type\":\"Server\"}";
+ + "\"key_type\":\"Server\""
+ + "}";
+
final byte[] hmac256 = new byte[32];
return Base64.getEncoder().encodeToString(header.getBytes(StandardCharsets.UTF_8))
+ "."
diff --git a/src/test/java/io/harness/cf/client/api/dispatchers/JwtMissingFieldsAuthDispatcher.java b/src/test/java/io/harness/cf/client/api/dispatchers/JwtMissingFieldsAuthDispatcher.java
new file mode 100644
index 0000000..48ce8df
--- /dev/null
+++ b/src/test/java/io/harness/cf/client/api/dispatchers/JwtMissingFieldsAuthDispatcher.java
@@ -0,0 +1,128 @@
+package io.harness.cf.client.api.dispatchers;
+
+import static io.harness.cf.client.api.TestUtils.makeBasicFeatureJson;
+import static io.harness.cf.client.api.TestUtils.makeSegmentsJson;
+import static io.harness.cf.client.api.dispatchers.CannedResponses.*;
+import static io.harness.cf.client.api.dispatchers.Endpoints.*;
+
+import io.harness.cf.client.api.testutils.PollingAtomicLong;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+import lombok.Getter;
+import lombok.SneakyThrows;
+import okhttp3.Headers;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.RecordedRequest;
+import okhttp3.mockwebserver.SocketPolicy;
+import org.jetbrains.annotations.NotNull;
+
+public class JwtMissingFieldsAuthDispatcher extends TestWebServerDispatcher {
+ private final AtomicInteger version = new AtomicInteger(2);
+ @Getter private final PollingAtomicLong endpointsHit;
+ @Getter private final List errors = new ArrayList<>();
+
+ private final String jwtEnvironmentIdentifier;
+ private final String jwtAccountId;
+ /* Set to null whatever fields you're testing in the JWT token */
+ public JwtMissingFieldsAuthDispatcher(String jwtEnvironmentIdentifier, String jwtAccountId) {
+ this.jwtEnvironmentIdentifier = jwtEnvironmentIdentifier;
+ this.jwtAccountId = jwtAccountId;
+ endpointsHit = new PollingAtomicLong(5);
+ }
+
+ @Override
+ @SneakyThrows
+ @NotNull
+ public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) {
+ System.out.printf(
+ "DISPATCH GOT ------> %s jwtEnvironmentIdentifier='%s' jwtAccountId='%s'\n",
+ recordedRequest.getPath(), jwtEnvironmentIdentifier, jwtAccountId);
+
+ endpointsHit.incrementAndGet();
+
+ switch (Objects.requireNonNull(recordedRequest.getPath())) {
+ case AUTH_ENDPOINT:
+ return makeAuthResponse(
+ 200, "00000000-0000-0000-0000-000000000000", jwtEnvironmentIdentifier, jwtAccountId);
+ case FEATURES_ENDPOINT:
+ assertHeaders(recordedRequest);
+ return makeMockJsonResponse(200, makeBasicFeatureJson());
+ case SEGMENTS_ENDPOINT:
+ assertHeaders(recordedRequest);
+ return makeMockJsonResponse(200, makeSegmentsJson());
+ case STREAM_ENDPOINT:
+ assertHeaders(recordedRequest);
+ return makeMockStreamResponse(
+ 200, makeFlagPatchEvent("simplebool", version.getAndIncrement()));
+ case SIMPLE_BOOL_FLAG_ENDPOINT:
+ assertHeaders(recordedRequest);
+ return makeMockSingleBoolFlagResponse(200, "simplebool", "off", version.get());
+ // TODO add metrics here
+ default:
+ throw new UnsupportedOperationException(
+ "ERROR: url not mapped " + recordedRequest.getPath());
+ }
+ }
+
+ private MockResponse makeAssertFailResp(String msg) {
+ return new MockResponse()
+ .setSocketPolicy(SocketPolicy.SHUTDOWN_SERVER_AFTER_RESPONSE)
+ .setResponseCode(-1)
+ .setStatus(msg);
+ }
+
+ private void assertHeaders(RecordedRequest recordedRequest) {
+ final Headers headers = recordedRequest.getHeaders();
+ final String url = recordedRequest.getPath();
+
+ System.out.print(headers);
+
+ final String accountVal = headers.get("Harness-AccountID");
+ if (jwtAccountId == null || jwtAccountId.trim().isEmpty()) {
+ if (accountVal != null) {
+ errors.add(
+ new RuntimeException(
+ String.format(
+ "Harness-AccountID=%s header should not be present on req '%s'",
+ accountVal, url)));
+ }
+ } else {
+ if (!jwtAccountId.equals(accountVal)) {
+ errors.add(
+ new RuntimeException(
+ String.format(
+ "Harness-AccountID=%s header does not match JWT accountID '%s' on req '%s'",
+ accountVal, jwtAccountId, url)));
+ }
+ }
+
+ final String envIdVal = headers.get("Harness-EnvironmentID");
+ if (jwtEnvironmentIdentifier == null || jwtEnvironmentIdentifier.trim().isEmpty()) {
+ if (!"00000000-0000-0000-0000-000000000000".equals(envIdVal)) {
+ errors.add(
+ new RuntimeException(
+ String.format(
+ "Harness-EnvironmentID=%s header should fallback to UUID when environmentIdentifier is null on req '%s'",
+ envIdVal, url)));
+ }
+ } else {
+ if (!jwtEnvironmentIdentifier.equals(envIdVal)) {
+ errors.add(
+ new RuntimeException(
+ String.format(
+ "Harness-EnvironmentID=%s does not match JWT environmentIdentifier '%s' on req '%s'",
+ envIdVal, jwtEnvironmentIdentifier, url)));
+ }
+ }
+ }
+
+ public void waitForAllEndpointsToBeCalled(int waitTimeSeconds) throws InterruptedException {
+ endpointsHit.waitForMinimumValueToBeReached(
+ waitTimeSeconds,
+ "auth/feat/seg/stream/flag",
+ "Did not get minimum number of endpoint calls");
+ Thread.sleep(500); // give time for resp to get back
+ }
+}
diff --git a/src/test/java/io/harness/cf/client/connector/HarnessConnectorTest.java b/src/test/java/io/harness/cf/client/connector/HarnessConnectorTest.java
index 4cc52a3..3700ca6 100644
--- a/src/test/java/io/harness/cf/client/connector/HarnessConnectorTest.java
+++ b/src/test/java/io/harness/cf/client/connector/HarnessConnectorTest.java
@@ -1,11 +1,23 @@
package io.harness.cf.client.connector;
-import static org.junit.jupiter.api.Assertions.assertInstanceOf;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import io.harness.cf.ApiClient;
+import io.harness.cf.api.ClientApi;
+import io.harness.cf.api.MetricsApi;
import io.harness.cf.client.api.MissingSdkKeyException;
+import io.harness.cf.client.api.dispatchers.CannedResponses;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.stubbing.Answer;
class HarnessConnectorTest {
@@ -30,4 +42,136 @@ void shouldThrowExceptionWhenNullApiKeyIsGiven() {
"Exception was not thrown");
assertInstanceOf(NullPointerException.class, thrown);
}
+
+ Answer makeCaptureHeadersAnswer(Map capturedHeaders) {
+ return params -> {
+ String h = String.valueOf((String) params.getArgument(0));
+ String v = String.valueOf((String) params.getArgument(1));
+ System.out.printf("adding %s=%s\n", h, v);
+ capturedHeaders.put(h, v);
+ return null;
+ };
+ }
+
+ void setupHeaderCaptures(
+ ClientApi mockClientApi,
+ Map capturedApiHeaders,
+ MetricsApi mockMetricsApi,
+ Map capturedMetricApiHeaders) {
+ final ApiClient mockInternalApiClient = mock(ApiClient.class);
+ when(mockClientApi.getApiClient()).thenReturn(mockInternalApiClient);
+ when(mockInternalApiClient.addDefaultHeader(anyString(), anyString()))
+ .thenAnswer(makeCaptureHeadersAnswer(capturedApiHeaders));
+
+ final ApiClient mockInternalMetricsApiClient = mock(ApiClient.class);
+ when(mockMetricsApi.getApiClient()).thenReturn(mockInternalMetricsApiClient);
+ when(mockInternalMetricsApiClient.addDefaultHeader(anyString(), anyString()))
+ .thenAnswer(makeCaptureHeadersAnswer(capturedMetricApiHeaders));
+ }
+
+ @ParameterizedTest
+ @NullSource()
+ @ValueSource(strings = {"", " ", "\t", "\n", "\r"})
+ void shouldParseJwtTokenWithMissingAccountId(String accountId) {
+ final Map apiHeaders = new HashMap<>();
+ final Map metricApiHeaders = new HashMap<>();
+
+ final ClientApi mockClientApi = mock(ClientApi.class);
+ final MetricsApi mockMetricsApi = mock(MetricsApi.class);
+ setupHeaderCaptures(mockClientApi, apiHeaders, mockMetricsApi, metricApiHeaders);
+
+ final HarnessConnector connector =
+ new HarnessConnector(
+ "dummy_sdk_key", mock(HarnessConfig.class), mockClientApi, mockMetricsApi);
+
+ final String token = CannedResponses.makeDummyJwtToken("dummyUUID", "dev", accountId);
+ connector.processToken(token);
+
+ for (Map nextMap : Arrays.asList(apiHeaders, metricApiHeaders)) {
+ System.out.print(nextMap);
+ assertEquals(2, nextMap.size());
+ assertEquals("Bearer " + token, nextMap.get("Authorization"));
+ assertEquals("dev", nextMap.get("Harness-EnvironmentID"));
+ assertFalse(nextMap.containsKey("Harness-AccountID"));
+ }
+ }
+
+ @Test
+ void shouldAddHarnessEnvironmentIdHeader() {
+ final Map apiHeaders = new HashMap<>();
+ final Map metricApiHeaders = new HashMap<>();
+
+ final ClientApi mockClientApi = mock(ClientApi.class);
+ final MetricsApi mockMetricsApi = mock(MetricsApi.class);
+ setupHeaderCaptures(mockClientApi, apiHeaders, mockMetricsApi, metricApiHeaders);
+
+ final HarnessConnector connector =
+ new HarnessConnector(
+ "dummy_sdk_key", mock(HarnessConfig.class), mockClientApi, mockMetricsApi);
+
+ final String token = CannedResponses.makeDummyJwtToken("dummyUUID", "non_uuid_env_name", "acc");
+ connector.processToken(token);
+
+ for (Map nextMap : Arrays.asList(apiHeaders, metricApiHeaders)) {
+ System.out.print(nextMap);
+ assertEquals(3, nextMap.size());
+ assertEquals("Bearer " + token, nextMap.get("Authorization"));
+ assertEquals("non_uuid_env_name", nextMap.get("Harness-EnvironmentID"));
+ assertEquals("acc", nextMap.get("Harness-AccountID"));
+ }
+ }
+
+ @ParameterizedTest
+ @NullSource()
+ @ValueSource(strings = {"", " ", "\t", "\n", "\r"})
+ void shouldAddHarnessEnvironmentIdHeaderButFallbackToUuidEnvIfEnvNotPresent(String env) {
+ final Map apiHeaders = new HashMap<>();
+ final Map metricApiHeaders = new HashMap<>();
+
+ final ClientApi mockClientApi = mock(ClientApi.class);
+ final MetricsApi mockMetricsApi = mock(MetricsApi.class);
+ setupHeaderCaptures(mockClientApi, apiHeaders, mockMetricsApi, metricApiHeaders);
+
+ final HarnessConnector connector =
+ new HarnessConnector(
+ "dummy_sdk_key", mock(HarnessConfig.class), mockClientApi, mockMetricsApi);
+
+ final String token = CannedResponses.makeDummyJwtToken("dummyUUID", env, "acc");
+ connector.processToken(token);
+
+ for (Map nextMap : Arrays.asList(apiHeaders, metricApiHeaders)) {
+ System.out.print(nextMap);
+ assertEquals(3, nextMap.size());
+ assertEquals("Bearer " + token, nextMap.get("Authorization"));
+ assertEquals("dummyUUID", nextMap.get("Harness-EnvironmentID"));
+ assertEquals("acc", nextMap.get("Harness-AccountID"));
+ }
+ }
+
+ @ParameterizedTest
+ @NullSource()
+ @ValueSource(strings = {"", " ", "\t", "\n", "\r"})
+ void shouldNotAddHarnessEnvironmentIdHeaderIfNeitherEnvOrEnvUuidPresent(String env) {
+ final Map apiHeaders = new HashMap<>();
+ final Map metricApiHeaders = new HashMap<>();
+
+ final ClientApi mockClientApi = mock(ClientApi.class);
+ final MetricsApi mockMetricsApi = mock(MetricsApi.class);
+ setupHeaderCaptures(mockClientApi, apiHeaders, mockMetricsApi, metricApiHeaders);
+
+ final HarnessConnector connector =
+ new HarnessConnector(
+ "dummy_sdk_key", mock(HarnessConfig.class), mockClientApi, mockMetricsApi);
+
+ final String token = CannedResponses.makeDummyJwtToken(null, env, "acc");
+ connector.processToken(token);
+
+ for (Map nextMap : Arrays.asList(apiHeaders, metricApiHeaders)) {
+ System.out.print(nextMap);
+ assertEquals(2, nextMap.size());
+ assertEquals("Bearer " + token, nextMap.get("Authorization"));
+ assertEquals("acc", nextMap.get("Harness-AccountID"));
+ assertFalse(nextMap.containsKey("Harness-EnvironmentID"));
+ }
+ }
}