Skip to content

Commit

Permalink
Run tests on Android
Browse files Browse the repository at this point in the history
This is currently completely manual. In a follow-up it would be nice
to get this running in CI.

On a Pixel 3A emulator running Android 30 I observed test crashes in
the following tests:

    selectSpanningMultipleSegments
    readLargeNioBufferOnlyReadsOneSegment
    gzipSink
    gzipSource

I needed to rename BufferedSourceTest to BufferedSourceJavaTest, and similarly
for BufferedSinkJavaTest and ByteStringJavaTest. We were seeing simple name
collisions in these tests which I believe were previously preventing these tests
from being executed.
  • Loading branch information
squarejesse committed Dec 27, 2020
1 parent 137d44f commit f14edb7
Show file tree
Hide file tree
Showing 18 changed files with 165 additions and 19 deletions.
44 changes: 44 additions & 0 deletions android-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
Android Test
============

This module runs Okio's test suite on a connected Android emulator or device. It requires the same
set-up as [OkHttp's android-test module][okhttp_android_test].

In brief, configure the Android SDK and PATH:

```
export ANDROID_SDK_ROOT=/Users/$USER/Library/Android/sdk
export PATH=$PATH:$ANDROID_SDK_ROOT/tools/bin:$ANDROID_SDK_ROOT/platform-tools
```

Use `logcat` to stream test logs:

```
adb logcat '*:E' TestRunner:D TaskRunner:D GnssHAL_GnssInterface:F DeviceStateChecker:F memtrack:F
```

Then run the tests:

```
./gradlew :android-test:connectedCheck
```


### Watch Out For Crashing Failures

Some of Okio's tests can cause the test process to crash. The test will be reported as a failure
with a message like this:

> Test failed to run to completion. Reason: 'Instrumentation run failed due to 'Process crashed.''.
> Check device logcat for details
When this happens, it's possible that tests are missing from the test run! One workaround is to
exclude the crashing test and re-run the rest. You can confirm that the test run completed normally
if a `run finished` line is printed in the logcat logs:

```
01-01 00:00:00.000 12345 23456 I TestRunner: run finished: 2976 tests, 0 failed, 3 ignored
```


[okhttp_android_test]: https://github.com/square/okhttp/tree/master/android-test
66 changes: 66 additions & 0 deletions android-test/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
apply plugin: 'com.android.library'
apply plugin: 'org.jetbrains.kotlin.android'

buildscript {
repositories {
mavenCentral()
gradlePluginPortal()
google()
}
}

def isIDE = properties.containsKey('android.injected.invoked.from.ide') ||
(System.getenv("XPC_SERVICE_NAME") ?: "").contains("intellij") ||
System.getenv("IDEA_INITIAL_DIRECTORY") != null

android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}

kotlinOptions {
freeCompilerArgs += "-Xmulti-platform"
}

compileSdkVersion 30

defaultConfig {
minSdkVersion 15
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

if (!isIDE) {
sourceSets {
named("androidTest") {
it.java.srcDirs += [
project.file("../okio-testing/src/commonMain/kotlin"),
project.file("../okio/src/commonMain/kotlin"),
project.file("../okio/src/commonTest/java"),
project.file("../okio/src/commonTest/kotlin"),
project.file("../okio/src/hashFunctions/kotlin"),
project.file("../okio/src/jvmMain/kotlin"),
project.file("../okio/src/jvmTest/java"),
project.file("../okio/src/jvmTest/kotlin"),
]
}
}
}
}


dependencies {
androidTestImplementation deps.androidx.testExtJunit
androidTestImplementation deps.androidx.testRunner
androidTestImplementation deps.animalSniffer.annotations
androidTestImplementation deps.kotlin.stdLib.common
androidTestImplementation deps.kotlin.test.annotations
androidTestImplementation deps.kotlin.test.common
androidTestImplementation deps.kotlin.test.jdk
androidTestImplementation deps.kotlin.time
androidTestImplementation deps.test.assertj
androidTestImplementation deps.test.junit
}
6 changes: 6 additions & 0 deletions android-test/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="okio.android.test">
<application
android:usesCleartextTraffic="true" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
3 changes: 3 additions & 0 deletions android-test/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">android-test</string>
</resources>
5 changes: 5 additions & 0 deletions android-test/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false">
</base-config>
</network-security-config>
11 changes: 11 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ buildscript {
]

ext.deps = [
'android': [
"gradlePlugin": "com.android.tools.build:gradle:4.0.2",
],
'androidx': [
'testExtJunit': "androidx.test.ext:junit:1.1.2",
'testRunner': "androidx.test:runner:1.3.0",
],
'kotlin': [
'gradlePlugin': "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}",
'stdLib': [
Expand Down Expand Up @@ -59,6 +66,7 @@ buildscript {
]

dependencies {
classpath deps.android.gradlePlugin
classpath deps.kotlin.gradlePlugin
classpath deps.animalSniffer.gradlePlugin
classpath deps.japicmp
Expand All @@ -74,6 +82,8 @@ buildscript {
repositories {
mavenCentral()
gradlePluginPortal()
jcenter()
google()
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
maven { url 'https://kotlin.bintray.com/kotlinx/' }
}
Expand All @@ -91,6 +101,7 @@ subprojects {
repositories {
mavenCentral()
jcenter()
google()
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
maven { url 'https://kotlin.bintray.com/kotlinx/' }
}
Expand Down
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
android.enableJetifier=true
android.useAndroidX=true

# Publishing SHA 256 and 512 hashses of maven-metadata is not supported by Sonatype and Nexus.
# See https://github.com/gradle/gradle/issues/11308 and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,7 @@ abstract class AbstractBufferedSourceTest internal constructor(
assertTrue(source.exhausted())
}

/** Note that this test crashes the VM on Android. */
@Test fun selectSpanningMultipleSegments() {
val commonPrefix = randomBytes(Segment.SIZE + 10)
val a = Buffer().write(commonPrefix).writeUtf8("a").readByteString()
Expand Down
10 changes: 6 additions & 4 deletions okio/src/commonTest/kotlin/okio/AbstractFilesystemTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ abstract class AbstractFilesystemTest(
fun canonicalizeDotReturnsCurrentWorkingDirectory() {
if (filesystem is FakeFilesystem || filesystem is ForwardingFilesystem) return
val cwd = filesystem.canonicalize(".".toPath())
assertTrue(cwd.toString()) {
cwd.toString().endsWith("okio${Path.directorySeparator}okio") ||
cwd.toString().endsWith("${Path.directorySeparator}okio-okio-test") ||
cwd.toString().contains("/CoreSimulator/Devices/")
val cwdString = cwd.toString()
assertTrue(cwdString) {
cwdString.endsWith("okio${Path.directorySeparator}okio") ||
cwdString.endsWith("${Path.directorySeparator}okio-parent-okio-test") || // JS
cwdString.contains("/CoreSimulator/Devices/") || // iOS simulator.
cwdString == "/" // Android emulator.
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* Tests solely for the behavior of RealBufferedSink's implementation. For generic
* BufferedSink behavior use BufferedSinkTest.
*/
public final class RealBufferedSinkTest {
public final class BufferedSinkJavaTest {
@Test public void inputStreamCloses() throws Exception {
BufferedSink sink = Okio.buffer((Sink) new Buffer());
OutputStream out = sink.outputStream();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
* Tests solely for the behavior of RealBufferedSource's implementation. For generic
* BufferedSource behavior use BufferedSourceTest.
*/
public final class RealBufferedSourceTest {
public final class BufferedSourceJavaTest {
@Test public void inputStreamTracksSegments() throws Exception {
Buffer source = new Buffer();
source.writeUtf8("a");
Expand Down
2 changes: 2 additions & 0 deletions okio/src/jvmTest/java/okio/BufferedSourceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,7 @@ private void assertLongDecimalString(String s, long expected) throws IOException
assertTrue(source.exhausted());
}

/** Note that this test crashes the VM on Android. */
@Test public void selectSpanningMultipleSegments() throws IOException {
ByteString commonPrefix = TestUtil.randomBytes(SEGMENT_SIZE + 10);
ByteString a = new Buffer().write(commonPrefix).writeUtf8("a").readByteString();
Expand Down Expand Up @@ -1458,6 +1459,7 @@ private void assertLongDecimalString(String s, long expected) throws IOException
assertEquals(expected, new String(data));
}

/** Note that this test crashes the VM on Android. */
@Test public void readLargeNioBufferOnlyReadsOneSegment() throws Exception {
String expected = factory.isOneByteAtATime()
? "a"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import static org.junit.Assert.fail;

@RunWith(Parameterized.class)
public final class ByteStringTest {
public final class ByteStringJavaTest {
interface Factory {
Factory BYTE_STRING = new Factory() {
@Override public ByteString decodeHex(String hex) {
Expand Down Expand Up @@ -286,23 +286,23 @@ public static List<Object[]> parameters() {
try {
ByteString.encodeString("hello", null);
fail();
} catch (IllegalArgumentException expected) {
} catch (NullPointerException expected) {
}
}

@Test public void encodeNullString() throws Exception {
try {
ByteString.encodeString(null, Charset.forName("UTF-8"));
fail();
} catch (IllegalArgumentException expected) {
} catch (NullPointerException expected) {
}
}

@Test public void decodeNullCharset() throws Exception {
try {
ByteString.of().string(null);
fail();
} catch (IllegalArgumentException expected) {
} catch (NullPointerException expected) {
}
}

Expand Down
2 changes: 2 additions & 0 deletions okio/src/jvmTest/java/okio/LargeStreamsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public final class LargeStreamsTest {
assertEquals(SHA256_RANDOM_FOUR_GIB_PLUS_1, hashingSink.hash());
}

/** Note that this test hangs on Android. */
@Test public void gzipSource() throws Exception {
Pipe pipe = new Pipe(1024 * 1024);

Expand All @@ -71,6 +72,7 @@ public final class LargeStreamsTest {
assertEquals(SHA256_RANDOM_FOUR_GIB_PLUS_1, hashingSink.hash());
}

/** Note that this test hangs on Android. */
@Test public void gzipSink() throws Exception {
Pipe pipe = new Pipe(1024 * 1024);

Expand Down
6 changes: 0 additions & 6 deletions okio/src/jvmTest/java/okio/OkioTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,6 @@ public final class OkioTest {
Okio.buffer((Sink) null);
fail();
} catch (NullPointerException expected) {
assertEquals("Parameter specified as non-null is null: "
+ "method okio.Okio__OkioKt.buffer, parameter $this$buffer",
expected.getMessage());
}
}

Expand All @@ -157,9 +154,6 @@ public final class OkioTest {
Okio.buffer((Source) null);
fail();
} catch (NullPointerException expected) {
assertEquals("Parameter specified as non-null is null: "
+ "method okio.Okio__OkioKt.buffer, parameter $this$buffer",
expected.getMessage());
}
}

Expand Down
6 changes: 3 additions & 3 deletions okio/src/jvmTest/kotlin/okio/JvmTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ import kotlin.test.Test
@ExperimentalFilesystem
class JvmTest {
@Test
fun `base directory consistent with java io File`() {
fun baseDirectoryConsistentWithJavaIoFile() {
assertThat(Filesystem.SYSTEM.canonicalize(".".toPath()).toString())
.isEqualTo(File("").canonicalFile.toString())
}

@Test
fun `java io File to okio Path`() {
fun javaIoFileToOkioPath() {
val javaIoFile = File("/foo/bar/baz")
val okioPath = "/foo/bar/baz".toPath(Path.directorySeparator)
assertThat(javaIoFile.toOkioPath()).isEqualTo(okioPath)
assertThat(okioPath.toFile()).isEqualTo(javaIoFile)
}

@Test
fun `nio Path to okio Path`() {
fun nioPathToOkioPath() {
val nioPath = Paths.get("/foo/bar/baz")
val okioPath = "/foo/bar/baz".toPath(Path.directorySeparator)
assertThat(nioPath.toOkioPath()).isEqualTo(okioPath)
Expand Down
8 changes: 8 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
rootProject.name = 'okio-parent'

include ':okio'
include ':okio-testing'
include ':okio:jvm:japicmp'
include ':okio:jvm:jmh'
include ':samples'

enableFeaturePreview("GRADLE_METADATA")

// The Android test module doesn't work in IntelliJ. Use Android Studio or the command line.
if (properties.containsKey('android.injected.invoked.from.ide') ||
System.getenv('ANDROID_SDK_ROOT') != null) {
include ':android-test'
}

0 comments on commit f14edb7

Please sign in to comment.