1
0
mirror of https://github.com/square/okhttp.git synced 2025-08-08 23:42:08 +03:00

Improve PlatformRule autodetection (#4920)

Run more platforms in circleci.
Auto detect platform in IDE.
Surface more platform assumptions in tests.
This commit is contained in:
Yuri Schimke
2019-04-10 19:31:35 +01:00
committed by GitHub
parent f8c3305032
commit 9e12bc4d60
16 changed files with 235 additions and 137 deletions

View File

@@ -1,5 +1,53 @@
# Check https://circleci.com/docs/2.0/language-java/ for more details
version: 2.1
commands:
runtests:
description: "Run tests"
parameters:
platform:
type: string
steps:
- restore_cache:
keys:
# restore compilation and wrapper from previous branch/job build or master
- v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}
- v4-master-compile
- run:
name: Run tests
command: ./gradlew --build-cache --parallel --continue test
environment:
GRADLE_OPTS: -Dorg.gradle.daemon=false -Dokhttp.platform=<< parameters.platform >> -Dorg.gradle.workers.max=3 -Xmx1G
- save_cache:
paths:
- ~/.gradle/caches
- ~/.gradle/wrapper
key: v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}
when: always
- run:
name: Save test results
command: |
mkdir -p ~/test-results/junit/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/junit/ \;
when: always
- store_test_results:
name: Store test results
path: ~/test-results
- run:
name: Save gradle reports
command: |
mkdir -p ~/reports/
tar cf - */build/reports | (cd ~/reports/; tar xf -)
when: always
- store_artifacts:
name: Store gradle reports
path: ~/reports
jobs:
compile:
docker:
@@ -49,7 +97,7 @@ jobs:
- run:
name: Run checks
command: ./gradlew --parallel --build-cache check -x test
command: ./gradlew --parallel --continue --build-cache check -x test
environment:
GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.workers.max=3 -Xmx1G
@@ -75,47 +123,22 @@ jobs:
steps:
- checkout
- restore_cache:
keys:
# restore compilation and wrapper from previous branch/job build or master
# master-compile is published on each build (cron or master commit) so is fresher
- v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}
- v4-master-compile
- runtests:
platform: jdk8
- run:
name: Run tests
command: ./gradlew --parallel --build-cache test
environment:
GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.workers.max=3 -Xmx1G
testjdk8alpn:
docker:
- image: circleci/openjdk:8u171-jdk
- save_cache:
paths:
- ~/.gradle/caches
- ~/.gradle/wrapper
key: v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}
when: always
environment:
JVM_OPTS: -Xmx1g
TERM: dumb
- run:
name: Save test results
command: |
mkdir -p ~/test-results/junit/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/junit/ \;
when: always
steps:
- checkout
- store_test_results:
name: Store test results
path: ~/test-results
- run:
name: Save gradle reports
command: |
mkdir -p ~/reports/
tar cf - */build/reports | (cd ~/reports/; tar xf -)
when: always
- store_artifacts:
name: Store gradle reports
path: ~/reports
- runtests:
platform: jdk8alpn
testjdk11:
docker:
@@ -128,46 +151,8 @@ jobs:
steps:
- checkout
- restore_cache:
keys:
# restore compilation and wrapper from previous branch/job build or master
- v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}
- v4-master-compile
- run:
name: Run tests
command: ./gradlew --build-cache --parallel test
environment:
GRADLE_OPTS: -Dorg.gradle.daemon=false -Dokhttp.platform=jdk9 -Dorg.gradle.workers.max=3 -Xmx1G
- save_cache:
paths:
- ~/.gradle/caches
- ~/.gradle/wrapper
key: v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}
when: always
- run:
name: Save test results
command: |
mkdir -p ~/test-results/junit/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/junit/ \;
when: always
- store_test_results:
name: Store test results
path: ~/test-results
- run:
name: Save gradle reports
command: |
mkdir -p ~/reports/
tar cf - */build/reports | (cd ~/reports/; tar xf -)
when: always
- store_artifacts:
name: Store gradle reports
path: ~/reports
- runtests:
platform: jdk9
testconscrypt:
docker:
@@ -180,46 +165,8 @@ jobs:
steps:
- checkout
- restore_cache:
keys:
# restore compilation and wrapper from previous branch/job build or master
- v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}
- v4-master-compile
- run:
name: Run tests
command: ./gradlew --build-cache --parallel test
environment:
GRADLE_OPTS: -Dorg.gradle.daemon=false -Dokhttp.platform=conscrypt -Dorg.gradle.workers.max=3 -Xmx1G
- save_cache:
paths:
- ~/.gradle/caches
- ~/.gradle/wrapper
key: v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}
when: always
- run:
name: Save test results
command: |
mkdir -p ~/test-results/junit/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/junit/ \;
when: always
- store_test_results:
name: Store test results
path: ~/test-results
- run:
name: Save gradle reports
command: |
mkdir -p ~/reports/
tar cf - */build/reports | (cd ~/reports/; tar xf -)
when: always
- store_artifacts:
name: Store gradle reports
path: ~/reports
- runtests:
platform: conscrypt
workflows:
version: 2
@@ -233,7 +180,11 @@ workflows:
filters:
branches:
ignore: master
- testjdk8
- testjdk8:
filters:
branches:
only: master
- testjdk8alpn
- testjdk11:
filters:
branches:
@@ -257,6 +208,9 @@ workflows:
- testjdk8:
requires:
- compile
- testjdk8alpn:
requires:
- compile
- testjdk11:
requires:
- compile

View File

@@ -116,7 +116,7 @@ subprojects { project ->
}
}
if (platform == "jdk8") {
if (platform == "jdk8alpn") {
// Add alpn-boot on Java 8 so we can use HTTP/2 without a stable API.
def alpnBootVersion = alpnBootVersion()
if (alpnBootVersion != null) {

View File

@@ -25,6 +25,7 @@ import javax.net.ssl.HostnameVerifier;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.PlatformRule;
import okhttp3.Protocol;
import okhttp3.RecordingHostnameVerifier;
import okhttp3.Request;
@@ -51,6 +52,7 @@ import static org.junit.Assume.assumeThat;
public final class HttpLoggingInterceptorTest {
private static final MediaType PLAIN = MediaType.get("text/plain; charset=utf-8");
@Rule public final PlatformRule platform = new PlatformRule();
@Rule public final MockWebServer server = new MockWebServer();
private final HandshakeCertificates handshakeCertificates = localhost();
@@ -784,6 +786,8 @@ public final class HttpLoggingInterceptorTest {
}
@Test public void duplexRequestsAreNotLogged() throws Exception {
platform.assumeHttp2Support();
server.useHttps(handshakeCertificates.sslSocketFactory(), false); // HTTP/2
url = server.url("/");

View File

@@ -20,6 +20,7 @@ import java.net.UnknownHostException;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.PlatformRule;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
@@ -41,6 +42,7 @@ import static org.junit.Assert.fail;
public final class LoggingEventListenerTest {
private static final MediaType PLAIN = MediaType.get("text/plain");
@Rule public final PlatformRule platform = new PlatformRule();
@Rule public final MockWebServer server = new MockWebServer();
private final HandshakeCertificates handshakeCertificates = localhost();
@@ -139,6 +141,8 @@ public final class LoggingEventListenerTest {
assertThat(response.body()).isNotNull();
response.body().bytes();
platform.assumeHttp2Support();
logRecorder
.assertLogMatch("callStart: Request\\{method=GET, url=" + url + ", tags=\\{\\}\\}")
.assertLogMatch("dnsStart: " + url.host())

View File

@@ -2,5 +2,7 @@ dependencies {
api project(':okhttp')
api deps.junit
api deps.assertj
api deps.conscrypt
compileOnly deps.jsr305
}

View File

@@ -15,6 +15,9 @@
*/
package okhttp3
import okhttp3.internal.platform.ConscryptPlatform
import okhttp3.internal.platform.Jdk8WithJettyBootPlatform
import okhttp3.internal.platform.Jdk9Platform
import okhttp3.internal.platform.Platform
import org.conscrypt.Conscrypt
import org.hamcrest.CoreMatchers.equalTo
@@ -29,6 +32,7 @@ import java.security.Security
*
* Also allows a test file to state general platform assumptions, or for individual test.
*/
@Suppress("unused", "MemberVisibilityCanBePrivate")
open class PlatformRule @JvmOverloads constructor(
val requiredPlatformName: String? = null,
val platform: Platform? = null
@@ -55,30 +59,60 @@ open class PlatformRule @JvmOverloads constructor(
fun isJdk9() = getPlatformSystemProperty() == JDK9_PROPERTY
fun isJdk8() = getPlatformSystemProperty() == DEFAULT_PROPERTY
fun isJdk8() = getPlatformSystemProperty() == JDK8_PROPERTY
fun isJdk8Alpn() = getPlatformSystemProperty() == JDK8_ALPN_PROPERTY
fun hasHttp2Support() = !isJdk8()
fun assumeConscrypt() {
assumeThat(getPlatformSystemProperty(), equalTo(CONSCRYPT_PROPERTY))
assumeThat(getPlatformSystemProperty(), equalTo(
CONSCRYPT_PROPERTY))
}
fun assumeJdk9() {
assumeThat(getPlatformSystemProperty(), equalTo(JDK9_PROPERTY))
assumeThat(getPlatformSystemProperty(), equalTo(
JDK9_PROPERTY))
}
fun assumeJdk8() {
assumeThat(getPlatformSystemProperty(), equalTo(DEFAULT_PROPERTY))
assumeThat(getPlatformSystemProperty(), equalTo(
JDK8_PROPERTY))
}
fun assumeJdk8Alpn() {
assumeThat(getPlatformSystemProperty(), equalTo(
JDK8_ALPN_PROPERTY))
}
fun assumeHttp2Support() {
assumeThat(getPlatformSystemProperty(), not(
JDK8_PROPERTY))
}
fun assumeNotConscrypt() {
assumeThat(getPlatformSystemProperty(), not(CONSCRYPT_PROPERTY))
assumeThat(getPlatformSystemProperty(), not(
CONSCRYPT_PROPERTY))
}
fun assumeNotJdk9() {
assumeThat(getPlatformSystemProperty(), not(JDK9_PROPERTY))
assumeThat(getPlatformSystemProperty(), not(
JDK9_PROPERTY))
}
fun assumeNotJdk8() {
assumeThat(getPlatformSystemProperty(), not(DEFAULT_PROPERTY))
assumeThat(getPlatformSystemProperty(), not(
JDK8_PROPERTY))
}
fun assumeNotJdk8Alpn() {
assumeThat(getPlatformSystemProperty(), not(
JDK8_ALPN_PROPERTY))
}
fun assumeNotHttp2Support() {
assumeThat(getPlatformSystemProperty(), equalTo(
JDK8_PROPERTY))
}
fun assumeJettyBootEnabled() {
@@ -86,24 +120,46 @@ open class PlatformRule @JvmOverloads constructor(
}
companion object {
val PROPERTY_NAME = "okhttp.platform"
val CONSCRYPT_PROPERTY = "conscrypt"
val DEFAULT_PROPERTY = "default"
val JDK9_PROPERTY = "jdk9"
const val PROPERTY_NAME = "okhttp.platform"
const val CONSCRYPT_PROPERTY = "conscrypt"
const val JDK9_PROPERTY = "jdk9"
const val JDK8_ALPN_PROPERTY = "jdk8alpn"
const val JDK8_PROPERTY = "jdk8"
init {
if (getPlatformSystemProperty() == CONSCRYPT_PROPERTY && Security.getProviders()[0].name != "Conscrypt") {
if (!Conscrypt.isAvailable()) {
System.err.println("Warning: Conscrypt not available")
}
val provider = Conscrypt.newProviderBuilder().provideTrustManager(true).build()
Security.insertProviderAt(provider, 1)
} else if (getPlatformSystemProperty() == DEFAULT_PROPERTY) {
} else if (getPlatformSystemProperty() == JDK8_ALPN_PROPERTY) {
if (!isAlpnBootEnabled()) {
System.err.println("Warning: ALPN Boot not enabled")
}
} else if (getPlatformSystemProperty() == JDK8_PROPERTY) {
if (isAlpnBootEnabled()) {
System.err.println("Warning: ALPN Boot enabled unintentionally")
}
}
}
@JvmStatic
fun getPlatformSystemProperty(): String = System.getProperty(PROPERTY_NAME, DEFAULT_PROPERTY)
fun getPlatformSystemProperty(): String {
var property: String? = System.getProperty(PROPERTY_NAME)
if (property == null) {
property = when (Platform.get()) {
is ConscryptPlatform -> CONSCRYPT_PROPERTY
is Jdk8WithJettyBootPlatform -> CONSCRYPT_PROPERTY
is Jdk9Platform -> JDK9_PROPERTY
else -> JDK8_PROPERTY
}
}
return property
}
@JvmStatic
fun conscrypt() = PlatformRule(CONSCRYPT_PROPERTY)
@@ -112,7 +168,10 @@ open class PlatformRule @JvmOverloads constructor(
fun jdk9() = PlatformRule(JDK9_PROPERTY)
@JvmStatic
fun jdk8() = PlatformRule(DEFAULT_PROPERTY)
fun jdk8() = PlatformRule(JDK8_PROPERTY)
@JvmStatic
fun jdk8alpn() = PlatformRule(JDK8_ALPN_PROPERTY)
@JvmStatic
fun isAlpnBootEnabled(): Boolean = try {

View File

@@ -186,7 +186,7 @@ open class Platform {
@JvmStatic
fun get(): Platform = platform
internal fun resetForTests(platform: Platform = findPlatform()) {
fun resetForTests(platform: Platform = findPlatform()) {
this.platform = platform
}

View File

@@ -2831,6 +2831,8 @@ public final class CallTest {
}
@Test public void unsuccessfulExpectContinuePermitsConnectionReuseWithHttp2() throws Exception {
platform.assumeHttp2Support();
enableProtocol(Protocol.HTTP_2);
server.enqueue(new MockResponse());
@@ -3230,6 +3232,8 @@ public final class CallTest {
}
@Test public void interceptorGetsHttp2() throws Exception {
platform.assumeHttp2Support();
enableProtocol(Protocol.HTTP_2);
// Capture the protocol as it is observed by the interceptor.
@@ -3662,6 +3666,8 @@ public final class CallTest {
}
@Test public void clientReadsHeadersDataTrailersHttp2() throws IOException {
platform.assumeHttp2Support();
MockResponse mockResponse = new MockResponse()
.clearHeaders()
.addHeader("h1", "v1")

View File

@@ -52,6 +52,7 @@ public final class ConnectionCoalescingTest {
@Before public void setUp() throws Exception {
platform.assumeNotConscrypt();
platform.assumeHttp2Support();
rootCa = new HeldCertificate.Builder()
.serialNumber(1L)

View File

@@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
public final class ConnectionReuseTest {
@Rule public final PlatformRule platform = new PlatformRule();
@Rule public final TestRule timeout = new Timeout(30_000);
@Rule public final MockWebServer server = new MockWebServer();
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
@@ -347,6 +348,7 @@ public final class ConnectionReuseTest {
}
private void enableHttp2() {
platform.assumeHttp2Support();
enableHttpsAndAlpn(Protocol.HTTP_2, Protocol.HTTP_1_1);
}

View File

@@ -19,7 +19,6 @@ import okhttp3.internal.platform.ConscryptPlatform
import okhttp3.internal.platform.Platform
import org.assertj.core.api.Assertions.assertThat
import org.conscrypt.Conscrypt
import org.conscrypt.OpenSSLContextImpl
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue

View File

@@ -30,6 +30,7 @@ import okhttp3.mockwebserver.internal.duplex.MockDuplexResponseBody;
import okhttp3.tls.HandshakeCertificates;
import okio.BufferedSink;
import okio.BufferedSource;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@@ -42,6 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
public final class DuplexTest {
@Rule public final PlatformRule platform = new PlatformRule();
@Rule public final TestRule timeout = new Timeout(30_000, TimeUnit.MILLISECONDS);
@Rule public final MockWebServer server = new MockWebServer();
@Rule public OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
@@ -53,6 +55,11 @@ public final class DuplexTest {
.eventListener(listener)
.build();
@Before
public void checkHttp2() {
platform.assumeHttp2Support();
}
@Test public void http1DoesntSupportDuplex() throws IOException {
Call call = client.newCall(new Request.Builder()
.url(server.url("/"))

View File

@@ -72,6 +72,8 @@ import static org.junit.Assume.assumeThat;
public final class EventListenerTest {
public static final Matcher<Response> anyResponse = CoreMatchers.any(Response.class);
@Rule public final PlatformRule platform = new PlatformRule();
@Rule public final MockWebServer server = new MockWebServer();
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
@Rule public final Timeout timeoutRule = new Timeout(20, TimeUnit.SECONDS);
@@ -859,6 +861,8 @@ public final class EventListenerTest {
}
@Test public void responseBodyFailHttp2OverHttps() throws IOException {
platform.assumeHttp2Support();
enableTlsWithTunnel(false);
server.setProtocols(asList(Protocol.HTTP_2, Protocol.HTTP_1_1));
responseBodyFail(Protocol.HTTP_2);
@@ -955,6 +959,8 @@ public final class EventListenerTest {
}
@Test public void requestBodyFailHttp2OverHttps() {
platform.assumeHttp2Support();
enableTlsWithTunnel(false);
server.setProtocols(asList(Protocol.HTTP_2, Protocol.HTTP_1_1));
@@ -1074,6 +1080,8 @@ public final class EventListenerTest {
}
@Test public void requestBodySuccessHttp2OverHttps() throws IOException {
platform.assumeHttp2Support();
enableTlsWithTunnel(false);
server.setProtocols(asList(Protocol.HTTP_2, Protocol.HTTP_1_1));
requestBodySuccess(RequestBody.create(MediaType.get("text/plain"), "Hello"), equalTo(5L),

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2019 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okhttp3
import okhttp3.internal.platform.Platform
import org.junit.Rule
import org.junit.Test
/**
* Sanity test for checking which environment and IDE is picking up.
*/
class PlatformRuleTest {
@Suppress("RedundantVisibilityModifier")
@JvmField
@Rule public val platform = PlatformRule()
@Test
fun testMode() {
println(PlatformRule.getPlatformSystemProperty())
println(Platform.get().javaClass.simpleName)
}
}

View File

@@ -1567,6 +1567,8 @@ public final class URLConnectionTest {
}
@Test public void postBodyRetransmittedAfterAuthorizationFail_HTTP_2() throws Exception {
platform.assumeHttp2Support();
enableProtocol(Protocol.HTTP_2);
postBodyRetransmittedAfterAuthorizationFail("abc");
}
@@ -1577,6 +1579,8 @@ public final class URLConnectionTest {
}
@Test public void postEmptyBodyRetransmittedAfterAuthorizationFail_HTTP_2() throws Exception {
platform.assumeHttp2Support();
enableProtocol(Protocol.HTTP_2);
postBodyRetransmittedAfterAuthorizationFail("");
}
@@ -3297,6 +3301,8 @@ public final class URLConnectionTest {
}
@Test public void setsNegotiatedProtocolHeader_HTTP_2() throws Exception {
platform.assumeHttp2Support();
setsNegotiatedProtocolHeader(Protocol.HTTP_2);
}
@@ -3608,6 +3614,8 @@ public final class URLConnectionTest {
}
@Test public void streamedBodyIsRetriedOnHttp2Shutdown() throws Exception {
platform.assumeHttp2Support();
enableProtocol(Protocol.HTTP_2);
server.enqueue(new MockResponse()
.setSocketPolicy(SocketPolicy.DISCONNECT_AT_END)

View File

@@ -41,6 +41,7 @@ import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.OkHttpClientTestRule;
import okhttp3.PlatformRule;
import okhttp3.Protocol;
import okhttp3.RecordingCookieJar;
import okhttp3.RecordingHostnameVerifier;
@@ -98,6 +99,7 @@ public final class HttpOverHttp2Test {
return asList(Protocol.H2_PRIOR_KNOWLEDGE, Protocol.HTTP_2);
}
@Rule public final PlatformRule platform = new PlatformRule();
@Rule public final TemporaryFolder tempDir = new TemporaryFolder();
@Rule public final MockWebServer server = new MockWebServer();
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
@@ -116,6 +118,13 @@ public final class HttpOverHttp2Test {
this.protocol = protocol;
}
@Before
public void checkHttp2() {
if (protocol == Protocol.HTTP_2) {
platform.assumeHttp2Support();
}
}
private OkHttpClient buildH2PriorKnowledgeClient() {
return clientTestRule.client.newBuilder()
.protocols(asList(Protocol.H2_PRIOR_KNOWLEDGE))