diff --git a/android/build.gradle b/android/build.gradle index 426aad766..9821c0c24 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -43,19 +43,17 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } + lint { + baseline = file("lint-baseline.xml") + } + lintOptions { textOutput "stdout" checkAllWarnings true warningsAsErrors true - disable "UnusedResources" // Unused will be removed on release - disable "IconExpectedSize" // Using the material icons provided from Google - disable "GoogleAppIndexingApiWarning" // We might want to index our app later - disable "InvalidPackage" // Butterknife, Okio and Realm - disable "ResourceType" // Annotation binding - disable "GradleDependency" - disable "NewerVersionAvailable" - disable "DuplicatePlatformClasses" // xpp3 added by azure-identity + lintConfig file("lint.xml") } + sourceSets { main { java.srcDirs = ['../src/main/java'] diff --git a/android/lint-baseline.xml b/android/lint-baseline.xml new file mode 100644 index 000000000..11149ca54 --- /dev/null +++ b/android/lint-baseline.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/android/lint.xml b/android/lint.xml new file mode 100644 index 000000000..0e7a8f716 --- /dev/null +++ b/android/lint.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/spotBugsExcludeFilter.xml b/spotBugsExcludeFilter.xml index ffb0ea6f2..619fb292d 100644 --- a/spotBugsExcludeFilter.xml +++ b/spotBugsExcludeFilter.xml @@ -64,6 +64,7 @@ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubu + @@ -111,4 +112,4 @@ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubu - \ No newline at end of file + diff --git a/src/main/java/com/microsoft/graph/core/requests/GraphClientFactory.java b/src/main/java/com/microsoft/graph/core/requests/GraphClientFactory.java index baa38bd76..d20c9afae 100644 --- a/src/main/java/com/microsoft/graph/core/requests/GraphClientFactory.java +++ b/src/main/java/com/microsoft/graph/core/requests/GraphClientFactory.java @@ -1,8 +1,11 @@ package com.microsoft.graph.core.requests; +import com.azure.core.credential.TokenCredential; import com.microsoft.graph.core.CoreConstants; +import com.microsoft.graph.core.authentication.AzureIdentityAccessTokenProvider; import com.microsoft.graph.core.requests.middleware.GraphTelemetryHandler; import com.microsoft.graph.core.requests.options.GraphClientOption; +import com.microsoft.kiota.RequestOption; import com.microsoft.kiota.authentication.BaseBearerTokenAuthenticationProvider; import com.microsoft.kiota.http.KiotaClientFactory; import com.microsoft.kiota.http.middleware.AuthorizationHandler; @@ -36,7 +39,7 @@ public static OkHttpClient.Builder create() { * @return an OkHttpClient Builder instance. */ @Nonnull - public static OkHttpClient.Builder create(@Nonnull Interceptor... interceptors) { + public static OkHttpClient.Builder create(@Nonnull final Interceptor... interceptors) { return create(new GraphClientOption(), interceptors); } @@ -46,10 +49,31 @@ public static OkHttpClient.Builder create(@Nonnull Interceptor... interceptors) * @return an OkHttpClient Builder instance. */ @Nonnull - public static OkHttpClient.Builder create(@Nonnull List interceptors) { + public static OkHttpClient.Builder create(@Nonnull final List interceptors) { return create(new GraphClientOption(), interceptors.toArray(new Interceptor[0])); } + /** + * OkHttpClient Builder for Graph with authentication middleware that uses the specified TokenCredential. + * @param tokenCredential the TokenCredential to use for authentication. + * @return an OkHttpClient Builder instance. + */ + @Nonnull + public static OkHttpClient.Builder create(@Nonnull final TokenCredential tokenCredential) { + return create(tokenCredential, new RequestOption[0]); + } + + /** + * OkHttpClient Builder for Graph with authentication middleware that uses the specified TokenCredential and RequestOptions to override default graph interceptors. + * @param tokenCredential the TokenCredential to use for authentication. + * @param requestOptions custom request options to override default graph interceptors + * @return an OkHttpClient Builder instance. + */ + @Nonnull + public static OkHttpClient.Builder create(@Nonnull final TokenCredential tokenCredential, @Nonnull final RequestOption[] requestOptions) { + return create(new BaseBearerTokenAuthenticationProvider(new AzureIdentityAccessTokenProvider(tokenCredential)), requestOptions); + } + /** * OkHttpClient Builder for Graph with specified AuthenticationProvider. * Adds an AuthorizationHandler to the OkHttpClient Builder. @@ -57,9 +81,22 @@ public static OkHttpClient.Builder create(@Nonnull List interceptor * @return an OkHttpClient Builder instance. */ @Nonnull - public static OkHttpClient.Builder create(@Nonnull BaseBearerTokenAuthenticationProvider authenticationProvider) { + public static OkHttpClient.Builder create(@Nonnull final BaseBearerTokenAuthenticationProvider authenticationProvider) { + return create(authenticationProvider, new RequestOption[0]); + } + + /** + * OkHttpClient Builder for Graph with specified AuthenticationProvider and RequestOptions to override default graph interceptors + * @param authenticationProvider the AuthenticationProvider to use for requests. + * @param requestOptions custom request options to override default graph interceptors + * @return an OkHttpClient Builder instance. + */ + @Nonnull + public static OkHttpClient.Builder create(@Nonnull final BaseBearerTokenAuthenticationProvider authenticationProvider, @Nonnull final RequestOption[] requestOptions) { final GraphClientOption graphClientOption = new GraphClientOption(); - final Interceptor[] interceptors = createDefaultGraphInterceptors(graphClientOption); + final List requestOptionsList = new ArrayList<>(Arrays.asList(requestOptions)); + requestOptionsList.add(graphClientOption); + final Interceptor[] interceptors = createDefaultGraphInterceptors(requestOptionsList.toArray(new RequestOption[0])); final ArrayList interceptorList = new ArrayList<>(Arrays.asList(interceptors)); interceptorList.add(new AuthorizationHandler(authenticationProvider)); graphClientOption.featureTracker.setFeatureUsage(FeatureFlag.AUTH_HANDLER_FLAG); @@ -74,18 +111,12 @@ public static OkHttpClient.Builder create(@Nonnull BaseBearerTokenAuthentication * @return an OkHttpClient Builder instance. */ @Nonnull - public static OkHttpClient.Builder create(@Nonnull GraphClientOption graphClientOption, @Nonnull Interceptor... interceptors) { - final OkHttpClient.Builder builder = create(graphClientOption); - //Skip adding interceptor if that class of interceptor already exist. - final List appliedInterceptors = new ArrayList<>(); - for(Interceptor interceptor: builder.interceptors()) { - appliedInterceptors.add(interceptor.getClass().toString()); - } - for (Interceptor interceptor:interceptors){ - if(appliedInterceptors.contains(interceptor.getClass().toString())) { - continue; - } - builder.addInterceptor(interceptor); + public static OkHttpClient.Builder create(@Nonnull final GraphClientOption graphClientOption, @Nonnull final Interceptor... interceptors) { + final OkHttpClient.Builder builder = KiotaClientFactory.create(interceptors); + final List customInterceptors = builder.interceptors(); + final boolean telemetryHandlerExists = customInterceptors.stream().anyMatch(x -> x instanceof GraphTelemetryHandler); + if (!telemetryHandlerExists) { + customInterceptors.add(new GraphTelemetryHandler(graphClientOption)); } return builder; } @@ -97,7 +128,7 @@ public static OkHttpClient.Builder create(@Nonnull GraphClientOption graphClient * @return an OkHttpClient Builder instance. */ @Nonnull - public static OkHttpClient.Builder create(@Nonnull GraphClientOption graphClientOption, @Nonnull List interceptors) { + public static OkHttpClient.Builder create(@Nonnull final GraphClientOption graphClientOption, @Nonnull final List interceptors) { return create(graphClientOption, interceptors.toArray(new Interceptor[0])); } @@ -108,10 +139,21 @@ public static OkHttpClient.Builder create(@Nonnull GraphClientOption graphClient * @return an OkHttpClient Builder instance. */ @Nonnull - public static OkHttpClient.Builder create(@Nullable GraphClientOption graphClientOption) { - GraphClientOption options = graphClientOption != null ? graphClientOption : new GraphClientOption(); - return KiotaClientFactory.create(createDefaultGraphInterceptors(options)); + public static OkHttpClient.Builder create(@Nullable final GraphClientOption graphClientOption) { + GraphClientOption option = graphClientOption == null ? new GraphClientOption() : graphClientOption; + return KiotaClientFactory.create(createDefaultGraphInterceptors(option)); } + + /** + * The OkHttpClient Builder with optional GraphClientOption and RequestOptions to override default graph interceptors + * @param requestOptions custom request options to override default graph interceptors + * @return an OkHttpClient Builder instance. + */ + @Nonnull + public static OkHttpClient.Builder create(@Nonnull final RequestOption[] requestOptions) { + return KiotaClientFactory.create(createDefaultGraphInterceptors(requestOptions)); + } + /** * Creates the default Interceptors for use with Graph. * @@ -119,15 +161,46 @@ public static OkHttpClient.Builder create(@Nullable GraphClientOption graphClien * @return an array of interceptors. */ @Nonnull - public static Interceptor[] createDefaultGraphInterceptors(@Nonnull GraphClientOption graphClientOption) { - List handlers = new ArrayList<>(); - addDefaultFeatureUsages(graphClientOption); + public static Interceptor[] createDefaultGraphInterceptors(@Nonnull final GraphClientOption graphClientOption) { + return getDefaultGraphInterceptors(new RequestOption[]{ graphClientOption }).toArray(new Interceptor[0]); + } - handlers.add(new UrlReplaceHandler(new UrlReplaceHandlerOption(CoreConstants.ReplacementConstants.getDefaultReplacementPairs()))); + /** + * Creates the default Interceptors for use with Graph configured with the provided RequestOptions. + * @param requestOptions custom request options to override default graph interceptors + * @return an array of interceptors. + */ + @Nonnull + public static Interceptor[] createDefaultGraphInterceptors(@Nonnull final RequestOption[] requestOptions) { + Objects.requireNonNull(requestOptions, "parameter requestOptions cannot be null"); + return getDefaultGraphInterceptors(requestOptions).toArray(new Interceptor[0]); + } + + /** + * Creates the default Interceptors for use with Graph. + * @param requestOptions custom request options to override default graph interceptors + * @return a list of interceptors. + */ + private static List getDefaultGraphInterceptors(@Nonnull final RequestOption[] requestOptions) { + GraphClientOption graphClientOption = new GraphClientOption(); + UrlReplaceHandlerOption urlReplaceHandlerOption = new UrlReplaceHandlerOption(CoreConstants.ReplacementConstants.getDefaultReplacementPairs()); + for (RequestOption option : requestOptions) { + if (option instanceof UrlReplaceHandlerOption) { + urlReplaceHandlerOption = (UrlReplaceHandlerOption) option; + } + if (option instanceof GraphClientOption) { + graphClientOption = (GraphClientOption) option; + } + } + + List handlers = new ArrayList<>(); + handlers.add(new UrlReplaceHandler(urlReplaceHandlerOption)); handlers.add(new GraphTelemetryHandler(graphClientOption)); - handlers.addAll(Arrays.asList(KiotaClientFactory.createDefaultInterceptors())); - return handlers.toArray(new Interceptor[0]); + handlers.addAll(Arrays.asList(KiotaClientFactory.createDefaultInterceptors(requestOptions))); + addDefaultFeatureUsages(graphClientOption); + return handlers; } + //These are the default features used by the Graph Client private static void addDefaultFeatureUsages(GraphClientOption graphClientOption) { graphClientOption.featureTracker.setFeatureUsage(FeatureFlag.RETRY_HANDLER_FLAG); diff --git a/src/test/java/com/microsoft/graph/core/requests/GraphClientFactoryTest.java b/src/test/java/com/microsoft/graph/core/requests/GraphClientFactoryTest.java index fcc2972b9..001173c46 100644 --- a/src/test/java/com/microsoft/graph/core/requests/GraphClientFactoryTest.java +++ b/src/test/java/com/microsoft/graph/core/requests/GraphClientFactoryTest.java @@ -10,23 +10,88 @@ import java.io.IOException; import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.azure.core.credential.AccessToken; +import com.azure.core.credential.TokenCredential; import com.microsoft.graph.core.authentication.AzureIdentityAccessTokenProvider; import com.microsoft.graph.core.authentication.AzureIdentityAuthenticationProvider; +import com.microsoft.graph.core.requests.middleware.GraphTelemetryHandler; +import com.microsoft.graph.core.requests.options.GraphClientOption; +import com.microsoft.kiota.RequestOption; import com.microsoft.kiota.authentication.AccessTokenProvider; import com.microsoft.kiota.authentication.AllowedHostsValidator; import com.microsoft.kiota.authentication.BaseBearerTokenAuthenticationProvider; +import com.microsoft.kiota.http.middleware.HeadersInspectionHandler; +import com.microsoft.kiota.http.middleware.ParametersNameDecodingHandler; +import com.microsoft.kiota.http.middleware.RedirectHandler; +import com.microsoft.kiota.http.middleware.RetryHandler; +import com.microsoft.kiota.http.middleware.UrlReplaceHandler; +import com.microsoft.kiota.http.middleware.UserAgentHandler; +import com.microsoft.kiota.http.middleware.options.RetryHandlerOption; +import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import reactor.core.publisher.Mono; class GraphClientFactoryTest { private static final String ACCESS_TOKEN_STRING = "token"; + @Test + void testDefaultCreate() { + final OkHttpClient.Builder clientBuilder = GraphClientFactory.create(); + assertDefaultHandlersPresent(clientBuilder.interceptors()); + } + + @Test + void testCreateWithCustomInterceptorsAddsTelemetry() { + final OkHttpClient.Builder clientBuilder = GraphClientFactory.create( + new RetryHandler(), new RedirectHandler() + ); + + assertEquals(3, clientBuilder.interceptors().size()); + + for (Interceptor interceptor : clientBuilder.interceptors()) { + assertTrue( + interceptor instanceof GraphTelemetryHandler + || interceptor instanceof RetryHandler + || interceptor instanceof RedirectHandler + ); + } + } + + @Test + void testCreateWithGraphClientOption() { + final OkHttpClient.Builder clientBuilder = GraphClientFactory.create(new GraphClientOption()); + assertDefaultHandlersPresent(clientBuilder.interceptors()); + } + + @Test + void testCreateDefaultInterceptorsWithCustomOptions() { + Interceptor[] interceptors = GraphClientFactory.createDefaultGraphInterceptors( + new RequestOption[] {new RetryHandlerOption(null, 0, 0)} + ); + assertDefaultHandlersPresent(Arrays.asList(interceptors)); + + for (Interceptor interceptor : interceptors) { + if (interceptor instanceof RetryHandler) { + RetryHandlerOption retryOptions = ((RetryHandler) interceptor).getRetryOptions(); + Assertions.assertEquals(0, retryOptions.maxRetries()); + Assertions.assertEquals(0, retryOptions.delay()); + } + } + } + @Test void testCreateWithAuthenticationProvider() throws IOException { final BaseBearerTokenAuthenticationProvider mockAuthenticationProvider = @@ -42,6 +107,92 @@ void testCreateWithAuthenticationProvider() throws IOException { assertEquals("Bearer " + ACCESS_TOKEN_STRING, response.request().header("Authorization")); } + @Test + void testCreateWithTokenCredential() throws IOException { + final TokenCredential tokenCredential = mock(TokenCredential.class); + when(tokenCredential.getTokenSync(any())).thenReturn(new AccessToken(ACCESS_TOKEN_STRING, null)); + when(tokenCredential.getToken(any())).thenReturn(Mono.just(new AccessToken(ACCESS_TOKEN_STRING, null))); + + final OkHttpClient graphClient = GraphClientFactory.create(tokenCredential).addInterceptor(new MockResponseHandler()).build(); + Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/me").build(); + Response response = graphClient.newCall(request).execute(); + + assertEquals(200, response.code()); + assertNotNull(response.request()); + assertTrue(response.request().headers().names().contains("Authorization")); + assertEquals("Bearer " + ACCESS_TOKEN_STRING, response.request().header("Authorization")); + } + + @Test + void testCreateWithAuthenticationProviderAndCustomRequestOptions() throws IOException { + final BaseBearerTokenAuthenticationProvider mockAuthenticationProvider = + getMockAuthenticationProvider(); + var requestOptions = new ArrayList(); + requestOptions.add(new RetryHandlerOption(null, 0, 0)); + OkHttpClient graphClient = GraphClientFactory.create(mockAuthenticationProvider, requestOptions.toArray(new RequestOption[0])).addInterceptor(new MockResponseHandler()).build(); + + var interceptors = graphClient.interceptors(); + for (Interceptor interceptor : interceptors) { + if (interceptor instanceof RetryHandler) { + RetryHandlerOption retryOptions = ((RetryHandler) interceptor).getRetryOptions(); + Assertions.assertEquals(0, retryOptions.maxRetries()); + Assertions.assertEquals(0, retryOptions.delay()); + } + } + + Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/me") + .addHeader("CustomHeader", "CustomValue").build(); + Response response = graphClient.newCall(request).execute(); + + assertEquals(200, response.code()); + assertNotNull(response.request()); + assertTrue(response.request().headers().names().contains("Authorization")); + assertTrue(response.request().headers().names().contains("CustomHeader")); + assertEquals("Bearer " + ACCESS_TOKEN_STRING, response.request().header("Authorization")); + assertEquals("CustomValue", response.request().header("CustomHeader")); + } + + @Test + void testCreateWithCustomInterceptorsOverwritesDefaults() throws IOException { + + final Interceptor[] interceptors = {new GraphTelemetryHandler(), getDisabledRetryHandler(), + new RedirectHandler()}; + final OkHttpClient client = GraphClientFactory.create(interceptors).build(); + final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/users/").build(); + client.newCall(request).execute(); + + for (Interceptor clientInterceptor : client.interceptors()) { + if (clientInterceptor instanceof RetryHandler) { + RetryHandlerOption retryOptions = ((RetryHandler) clientInterceptor).getRetryOptions(); + Assertions.assertEquals(0, retryOptions.maxRetries()); + Assertions.assertEquals(0, retryOptions.delay()); + + } + + assertTrue(clientInterceptor instanceof GraphTelemetryHandler + || clientInterceptor instanceof RedirectHandler + || clientInterceptor instanceof RetryHandler); + } + } + + private void assertDefaultHandlersPresent(final List interceptors) { + HashSet> expectedInterceptors = new HashSet<>( + Arrays.asList( + GraphTelemetryHandler.class, + RetryHandler.class, + UrlReplaceHandler.class, + UserAgentHandler.class, + RedirectHandler.class, + ParametersNameDecodingHandler.class, + HeadersInspectionHandler.class + ) + ); + + for (Interceptor interceptor : interceptors) { + assertTrue(expectedInterceptors.contains(interceptor.getClass())); + } + } + private static BaseBearerTokenAuthenticationProvider getMockAuthenticationProvider() { final AccessTokenProvider mockAccessTokenProvider = mock(AzureIdentityAccessTokenProvider.class); when(mockAccessTokenProvider.getAuthorizationToken(any(URI.class), anyMap())) @@ -53,4 +204,11 @@ private static BaseBearerTokenAuthenticationProvider getMockAuthenticationProvid .thenReturn(mockAccessTokenProvider); return mockAuthenticationProvider; } + + private static @NotNull RetryHandler getDisabledRetryHandler() { + RetryHandlerOption retryHandlerOption = new RetryHandlerOption( + (delay, executionCount, request, response) -> false, 0, 0); + RetryHandler retryHandler = new RetryHandler(retryHandlerOption); + return retryHandler; + } } diff --git a/src/test/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandlerTest.java b/src/test/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandlerTest.java index b03f40615..06bf4f9e5 100644 --- a/src/test/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandlerTest.java +++ b/src/test/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandlerTest.java @@ -10,7 +10,9 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; + import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -29,23 +31,31 @@ void telemetryHandlerDefaultTests() throws IOException { final Response response = client.newCall(request).execute(); assertNotNull(response); + assertNotNull(response.request()); + assertNotNull(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME)); assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedCore)); - assertTrue(!response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(CoreConstants.Headers.ANDROID_VERSION_PREFIX)); // Android version is not going to be present on unit tests running on java platform - assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); + assertTrue(!response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains( + CoreConstants.Headers.ANDROID_VERSION_PREFIX)); // Android version is not going to be present on unit tests running on java platform + assertTrue( + response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); } @Test void arrayInterceptorsTest() throws IOException { final String expectedCore = CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" + CoreConstants.Headers.VERSION; - final Interceptor[] interceptors = {new GraphTelemetryHandler(), new RetryHandler(), new RedirectHandler()}; + final Interceptor[] interceptors = {new GraphTelemetryHandler(), new RetryHandler(), + new RedirectHandler()}; final OkHttpClient client = GraphClientFactory.create(interceptors).build(); final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/users/").build(); final Response response = client.newCall(request).execute(); assertNotNull(response); + assertNotNull(response.request()); + assertNotNull(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME)); assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedCore)); - assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); + assertTrue( + response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); } @Test @@ -58,8 +68,11 @@ void arrayInterceptorEmptyTest() throws IOException { final Response response = client.newCall(request).execute(); assertNotNull(response); + assertNotNull(response.request()); + assertNotNull(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME)); assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedCore)); - assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); + assertTrue( + response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); } @Test @@ -76,7 +89,7 @@ void testClientOptions() throws IOException { graphClientOption.setGraphServiceTargetVersion(serviceLibVer); final String expectedCoreVer = - CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" +coreLibVer; + CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" + coreLibVer; final String expectedClientEndpoint = CoreConstants.Headers.JAVA_VERSION_PREFIX + "-" + serviceLibVer + "/" + clientLibVer; @@ -84,8 +97,12 @@ void testClientOptions() throws IOException { final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/users/").build(); final Response response = client.newCall(request).execute(); + assertNotNull(response); + assertNotNull(response.request()); + assertNotNull(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME)); assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedCoreVer)); - assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedClientEndpoint)); + assertTrue( + response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedClientEndpoint)); assertTrue(response.request().header(CoreConstants.Headers.CLIENT_REQUEST_ID).contains(requestId)); } }