diff --git a/app/src/debug/java/com/artemzin/qualitymatters/network/OkHttpInterceptorsModule.java b/app/src/debug/java/com/artemzin/qualitymatters/network/OkHttpInterceptorsModule.java index 2684b8a..32c08d1 100644 --- a/app/src/debug/java/com/artemzin/qualitymatters/network/OkHttpInterceptorsModule.java +++ b/app/src/debug/java/com/artemzin/qualitymatters/network/OkHttpInterceptorsModule.java @@ -1,19 +1,17 @@ package com.artemzin.qualitymatters.network; import android.support.annotation.NonNull; - import com.facebook.stetho.okhttp3.StethoInterceptor; - -import java.util.List; - -import javax.inject.Singleton; - import dagger.Module; import dagger.Provides; import okhttp3.Interceptor; import okhttp3.logging.HttpLoggingInterceptor; import timber.log.Timber; +import javax.inject.Singleton; +import java.util.Arrays; +import java.util.List; + import static java.util.Collections.singletonList; /** @@ -28,9 +26,15 @@ public HttpLoggingInterceptor provideHttpLoggingInterceptor() { return new HttpLoggingInterceptor(message -> Timber.d(message)); } + @Provides @Singleton @NonNull + public HostSelectionInterceptor provideHostSelectionInterceptor() { + return new HostSelectionInterceptor(); + } + @Provides @OkHttpInterceptors @Singleton @NonNull - public List provideOkHttpInterceptors(@NonNull HttpLoggingInterceptor httpLoggingInterceptor) { - return singletonList(httpLoggingInterceptor); + public List provideOkHttpInterceptors(@NonNull HttpLoggingInterceptor httpLoggingInterceptor, + @NonNull HostSelectionInterceptor hostSelectionInterceptor) { + return Arrays.asList(httpLoggingInterceptor, hostSelectionInterceptor); } @Provides @OkHttpNetworkInterceptors @Singleton @NonNull diff --git a/app/src/functionalTests/java/com/artemzin/qualitymatters/functional_tests/rules/MockWebServerRule.java b/app/src/functionalTests/java/com/artemzin/qualitymatters/functional_tests/rules/MockWebServerRule.java index 5e7ceb4..38219d9 100644 --- a/app/src/functionalTests/java/com/artemzin/qualitymatters/functional_tests/rules/MockWebServerRule.java +++ b/app/src/functionalTests/java/com/artemzin/qualitymatters/functional_tests/rules/MockWebServerRule.java @@ -1,17 +1,14 @@ package com.artemzin.qualitymatters.functional_tests.rules; import android.support.annotation.NonNull; - import com.artemzin.qualitymatters.functional_tests.TestUtils; - +import okhttp3.mockwebserver.MockWebServer; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; import java.lang.reflect.Method; -import okhttp3.mockwebserver.MockWebServer; - /** * JUnit test rule for mocking web server! */ @@ -36,7 +33,7 @@ public void evaluate() throws Throwable { final MockWebServer mockWebServer = new MockWebServer(); mockWebServer.start(); - TestUtils.app().applicationComponent().changeableBaseUrl().setBaseUrl(mockWebServer.url("").toString()); + TestUtils.app().applicationComponent().hostSelectionInterceptor().setHost(mockWebServer.url("").toString()); if (!needsMockWebServer.setupMethod().isEmpty()) { final Method setupMethod = testClassInstance.getClass().getDeclaredMethod(needsMockWebServer.setupMethod(), MockWebServer.class); diff --git a/app/src/integrationTests/java/com/artemzin/qualitymatters/integration_tests/api/QualityMattersRestApiIntegrationTest.java b/app/src/integrationTests/java/com/artemzin/qualitymatters/integration_tests/api/QualityMattersRestApiIntegrationTest.java index 939bff9..18f2fbd 100644 --- a/app/src/integrationTests/java/com/artemzin/qualitymatters/integration_tests/api/QualityMattersRestApiIntegrationTest.java +++ b/app/src/integrationTests/java/com/artemzin/qualitymatters/integration_tests/api/QualityMattersRestApiIntegrationTest.java @@ -3,19 +3,18 @@ import com.artemzin.qualitymatters.QualityMattersIntegrationRobolectricTestRunner; import com.artemzin.qualitymatters.api.QualityMattersRestApi; import com.artemzin.qualitymatters.api.entities.Item; - +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import retrofit2.adapter.rxjava.HttpException; import java.io.IOException; import java.util.List; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import retrofit2.adapter.rxjava.HttpException; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; @@ -39,7 +38,7 @@ public void beforeEachTest() throws IOException { mockWebServer.start(); // Change base url to the mocked - QualityMattersIntegrationRobolectricTestRunner.qualityMattersApp().applicationComponent().changeableBaseUrl().setBaseUrl(mockWebServer.url("").toString()); + QualityMattersIntegrationRobolectricTestRunner.qualityMattersApp().applicationComponent().hostSelectionInterceptor().setHost(HttpUrl.parse(mockWebServer.url("").toString())); qualityMattersRestApi = QualityMattersIntegrationRobolectricTestRunner.qualityMattersApp().applicationComponent().qualityMattersApi(); } diff --git a/app/src/main/java/com/artemzin/qualitymatters/ApplicationComponent.java b/app/src/main/java/com/artemzin/qualitymatters/ApplicationComponent.java index 9121399..508ce72 100644 --- a/app/src/main/java/com/artemzin/qualitymatters/ApplicationComponent.java +++ b/app/src/main/java/com/artemzin/qualitymatters/ApplicationComponent.java @@ -1,9 +1,7 @@ package com.artemzin.qualitymatters; import android.support.annotation.NonNull; - import com.artemzin.qualitymatters.api.ApiModule; -import com.artemzin.qualitymatters.api.ChangeableBaseUrl; import com.artemzin.qualitymatters.api.QualityMattersRestApi; import com.artemzin.qualitymatters.developer_settings.DevMetricsProxy; import com.artemzin.qualitymatters.developer_settings.DeveloperSettingsComponent; @@ -12,6 +10,7 @@ import com.artemzin.qualitymatters.developer_settings.LeakCanaryProxy; import com.artemzin.qualitymatters.models.AnalyticsModel; import com.artemzin.qualitymatters.models.ModelsModule; +import com.artemzin.qualitymatters.network.HostSelectionInterceptor; import com.artemzin.qualitymatters.network.NetworkModule; import com.artemzin.qualitymatters.network.OkHttpInterceptorsModule; import com.artemzin.qualitymatters.performance.AsyncJobsModule; @@ -19,11 +18,10 @@ import com.artemzin.qualitymatters.ui.activities.MainActivity; import com.artemzin.qualitymatters.ui.fragments.ItemsFragment; import com.google.gson.Gson; +import dagger.Component; import javax.inject.Singleton; -import dagger.Component; - @Singleton @Component(modules = { ApplicationModule.class, @@ -44,9 +42,6 @@ public interface ApplicationComponent { @NonNull QualityMattersRestApi qualityMattersApi(); - @NonNull - ChangeableBaseUrl changeableBaseUrl(); - // Provide AsyncJobObserver from the real app to the tests without need in injection to the test. @NonNull AsyncJobsObserver asyncJobsObserver(); @@ -68,5 +63,7 @@ public interface ApplicationComponent { DevMetricsProxy devMetricsProxy(); + HostSelectionInterceptor hostSelectionInterceptor(); + void inject(@NonNull MainActivity mainActivity); } diff --git a/app/src/main/java/com/artemzin/qualitymatters/api/ApiModule.java b/app/src/main/java/com/artemzin/qualitymatters/api/ApiModule.java index f47e0fd..978d702 100644 --- a/app/src/main/java/com/artemzin/qualitymatters/api/ApiModule.java +++ b/app/src/main/java/com/artemzin/qualitymatters/api/ApiModule.java @@ -1,12 +1,8 @@ package com.artemzin.qualitymatters.api; import android.support.annotation.NonNull; - import com.artemzin.qualitymatters.BuildConfig; import com.google.gson.Gson; - -import javax.inject.Singleton; - import dagger.Module; import dagger.Provides; import okhttp3.OkHttpClient; @@ -14,25 +10,24 @@ import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; +import javax.inject.Singleton; + @Module public class ApiModule { @NonNull - private final ChangeableBaseUrl changeableBaseUrl; + private final String baseUrl; public ApiModule(@NonNull String baseUrl) { - changeableBaseUrl = new ChangeableBaseUrl(baseUrl); - } - - @Provides @NonNull @Singleton - public ChangeableBaseUrl provideChangeableBaseUrl() { - return changeableBaseUrl; + this.baseUrl = baseUrl; } - @Provides @NonNull @Singleton - public QualityMattersRestApi provideQualityMattersApi(@NonNull OkHttpClient okHttpClient, @NonNull Gson gson, @NonNull ChangeableBaseUrl changeableBaseUrl) { + @Provides + @NonNull + @Singleton + public QualityMattersRestApi provideQualityMattersApi(@NonNull OkHttpClient okHttpClient, @NonNull Gson gson) { return new Retrofit.Builder() - .baseUrl(changeableBaseUrl) + .baseUrl(baseUrl) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create(gson)) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) diff --git a/app/src/main/java/com/artemzin/qualitymatters/api/ChangeableBaseUrl.java b/app/src/main/java/com/artemzin/qualitymatters/api/ChangeableBaseUrl.java deleted file mode 100644 index 891e205..0000000 --- a/app/src/main/java/com/artemzin/qualitymatters/api/ChangeableBaseUrl.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.artemzin.qualitymatters.api; - -import android.support.annotation.NonNull; - -import java.util.concurrent.atomic.AtomicReference; - -import okhttp3.HttpUrl; -import retrofit2.BaseUrl; - -/** - * Such implementation allows us easily change base url in the integration and functional tests! - */ -public class ChangeableBaseUrl implements BaseUrl { - - @NonNull - private final AtomicReference baseUrl; - - public ChangeableBaseUrl(@NonNull String baseUrl) { - this.baseUrl = new AtomicReference<>(HttpUrl.parse(baseUrl)); - } - - public void setBaseUrl(@NonNull String baseUrl) { - this.baseUrl.set(HttpUrl.parse(baseUrl)); - } - - @Override @NonNull - public HttpUrl url() { - return baseUrl.get(); - } -} diff --git a/app/src/main/java/com/artemzin/qualitymatters/network/HostSelectionInterceptor.java b/app/src/main/java/com/artemzin/qualitymatters/network/HostSelectionInterceptor.java new file mode 100644 index 0000000..6c256e7 --- /dev/null +++ b/app/src/main/java/com/artemzin/qualitymatters/network/HostSelectionInterceptor.java @@ -0,0 +1,42 @@ +package com.artemzin.qualitymatters.network; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import okhttp3.HttpUrl; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; + +/** + * An interceptor that allows runtime changes to the URL hostname. + * As per https://gist.github.com/swankjesse/8571a8207a5815cca1fb + */ +public final class HostSelectionInterceptor implements Interceptor { + /** + * Using static variable in order to avoid adding this interceptor to ApplicationComponent + */ + private volatile HttpUrl hostUrl; + + public void setHost(@Nullable HttpUrl host) { + this.hostUrl = host; + } + + @Override + public Response intercept(@NonNull Chain chain) throws IOException { + Request request = chain.request(); + HttpUrl host = this.hostUrl; + if (host != null) { + HttpUrl newUrl = request.url().newBuilder() + .host(host.host()) + .port(host.port()) + .scheme(host.scheme()) + .build(); + request = request.newBuilder() + .url(newUrl) + .build(); + } + return chain.proceed(request); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/artemzin/qualitymatters/network/NetworkModule.java b/app/src/main/java/com/artemzin/qualitymatters/network/NetworkModule.java index 896d972..86365e2 100644 --- a/app/src/main/java/com/artemzin/qualitymatters/network/NetworkModule.java +++ b/app/src/main/java/com/artemzin/qualitymatters/network/NetworkModule.java @@ -1,16 +1,14 @@ package com.artemzin.qualitymatters.network; import android.support.annotation.NonNull; - -import java.util.List; - -import javax.inject.Singleton; - import dagger.Module; import dagger.Provides; import okhttp3.Interceptor; import okhttp3.OkHttpClient; +import javax.inject.Singleton; +import java.util.List; + @Module public class NetworkModule { diff --git a/app/src/release/java/com/artemzin/qualitymatters/network/OkHttpInterceptorsModule.java b/app/src/release/java/com/artemzin/qualitymatters/network/OkHttpInterceptorsModule.java index c05ad27..af944ba 100644 --- a/app/src/release/java/com/artemzin/qualitymatters/network/OkHttpInterceptorsModule.java +++ b/app/src/release/java/com/artemzin/qualitymatters/network/OkHttpInterceptorsModule.java @@ -1,16 +1,15 @@ package com.artemzin.qualitymatters.network; import android.support.annotation.NonNull; - -import java.util.List; - -import javax.inject.Singleton; - import dagger.Module; import dagger.Provides; import okhttp3.Interceptor; +import javax.inject.Singleton; +import java.util.List; + import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; /** * Provides OkHttp interceptors for release build. @@ -19,12 +18,17 @@ public class OkHttpInterceptorsModule { @Provides @OkHttpInterceptors @Singleton @NonNull - public List provideOkHttpInterceptors() { - return emptyList(); + public List provideOkHttpInterceptors(@NonNull HostSelectionInterceptor hostSelectionInterceptor) { + return singletonList(hostSelectionInterceptor); } @Provides @OkHttpNetworkInterceptors @Singleton @NonNull public List provideOkHttpNetworkInterceptors() { return emptyList(); } + + @Provides @Singleton @NonNull + public HostSelectionInterceptor provideHostSelectionInterceptor() { + return new HostSelectionInterceptor(); + } } diff --git a/app/src/unitTests/java/com/artemzin/qualitymatters/api/ChangeableBaseUrlTest.java b/app/src/unitTests/java/com/artemzin/qualitymatters/api/ChangeableBaseUrlTest.java deleted file mode 100644 index 6c9436e..0000000 --- a/app/src/unitTests/java/com/artemzin/qualitymatters/api/ChangeableBaseUrlTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.artemzin.qualitymatters.api; - -import org.junit.Test; - -import okhttp3.HttpUrl; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ChangeableBaseUrlTest { - - @Test - public void constructor_shouldUsePassedBaseUrl() { - ChangeableBaseUrl changeableBaseUrl = new ChangeableBaseUrl("https://artemzin.com"); - assertThat(changeableBaseUrl.url()).isEqualTo(HttpUrl.parse("https://artemzin.com")); - } - - @Test - public void setBaseUrl() { - ChangeableBaseUrl changeableBaseUrl = new ChangeableBaseUrl("https://1"); - changeableBaseUrl.setBaseUrl("https://2"); - assertThat(changeableBaseUrl.url()).isEqualTo(HttpUrl.parse("https://2")); - } -} \ No newline at end of file diff --git a/app/src/unitTests/java/com/artemzin/qualitymatters/network/HostSelectionInterceptorTest.java b/app/src/unitTests/java/com/artemzin/qualitymatters/network/HostSelectionInterceptorTest.java new file mode 100644 index 0000000..ddae70e --- /dev/null +++ b/app/src/unitTests/java/com/artemzin/qualitymatters/network/HostSelectionInterceptorTest.java @@ -0,0 +1,41 @@ +package com.artemzin.qualitymatters.network; + +import junit.framework.Assert; +import okhttp3.HttpUrl; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.internal.http.RealInterceptorChain; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.Collections; + +public class HostSelectionInterceptorTest { + + public static final String TEST_URL = "https://google.com/api/clients"; + public static final String TEST_URL_2 = "https://yahoo.com/api/clients"; + public static final String TEST_HOST = "https://yahoo.com/"; + private HostSelectionInterceptor interceptor; + private Interceptor.Chain chain; + + @Before + public void beforeEachTest() { + interceptor = new HostSelectionInterceptor(); + Request request = new Request.Builder().url(TEST_URL).build(); + chain = new RealInterceptorChain(Collections.emptyList(), null, null, null,0, + request, null, null, 10000, + 10000, 10000); +// Mockito.when(chain.request()).thenReturn(request); + } + + @Test + public void hostChanged() throws IOException { +// interceptor.intercept(chain); +// Assert.assertEquals(TEST_URL, chain.request().url().toString()); + interceptor.setHost(HttpUrl.parse(TEST_HOST)); + interceptor.intercept(chain); + Assert.assertEquals(TEST_URL_2, chain.request().url().toString()); + } + +} \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle index 46d57f2..ea66c76 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -23,7 +23,7 @@ ext.versions = [ rxJavaProguardRules : '1.1.8.0', rxLint : '1.6', supportLibs : '23.1.1', - okHttp : '3.2.0', + okHttp : '3.9.0', retrofit : '2.0.0-beta4', gson : '2.7', autoValue : '1.2', diff --git a/proguard/proguard-square-okhttp.pro b/proguard/proguard-square-okhttp.pro new file mode 100644 index 0000000..b3b1747 --- /dev/null +++ b/proguard/proguard-square-okhttp.pro @@ -0,0 +1,2 @@ +# OkHttp3 +-dontwarn okhttp3.**