diff --git a/sdks/android/Mentat/build.gradle b/sdks/android/Mentat/build.gradle index 22784c91..4a79f52c 100644 --- a/sdks/android/Mentat/build.gradle +++ b/sdks/android/Mentat/build.gradle @@ -29,9 +29,13 @@ buildscript { classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' - classpath 'gradle.plugin.org.mozilla.rust-android-gradle:plugin:0.0.4' + classpath 'gradle.plugin.org.mozilla.rust-android-gradle:plugin:0.1.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files + + // Yes, this is unusual. We want to access some host-specific + // computation at build time. + classpath 'net.java.dev.jna:jna:4.5.2' } } diff --git a/sdks/android/Mentat/library/build.gradle b/sdks/android/Mentat/library/build.gradle index c0f3d9c7..680ec094 100644 --- a/sdks/android/Mentat/library/build.gradle +++ b/sdks/android/Mentat/library/build.gradle @@ -6,6 +6,8 @@ apply plugin: 'com.jfrog.bintray' // Simply applying this plugin gets bintray to publish a pom file. apply plugin: 'com.github.dcendents.android-maven' +import com.sun.jna.Platform + android { compileSdkVersion rootProject.ext.build['compileSdkVersion'] defaultConfig { @@ -26,6 +28,9 @@ android { sourceSets { androidTest.assets.srcDirs += '../../../../fixtures' + + test.resources.srcDirs += '../../../../fixtures' + test.resources.srcDirs += "$buildDir/rustResources" } // TODO silences: @@ -40,27 +45,41 @@ android { packagingOptions { doNotStrip "**/*.so" } + + testOptions.unitTests.all { + maxParallelForks = 4 + } } cargo { module = '../../../../ffi' targetDirectory = '../../../../target' - targetInclude = 'libmentat_ffi.so' + targetIncludes = ['libmentat_ffi.so', 'libmentat_ffi.dylib', 'libmentat_ffi.dll'] targets = [ - 'x86', + 'default', // For unit tests. 'arm', 'arm64', + 'x86', ] + + // This puts the output of `cargo build` (the "default" toolchain) into the correct directory + // for JNA to find it. + defaultToolchainBuildPrefixDir = Platform.RESOURCE_PREFIX } dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'net.java.dev.jna:jna:4.5.2@aar' + + testImplementation 'net.java.dev.jna:jna:4.5.2' + testImplementation 'junit:junit:4.12' + testImplementation 'org.robolectric:robolectric:3.8' + testImplementation 'org.mockito:mockito-core:2.20.0' + androidTestImplementation 'com.android.support:support-annotations:27.1.1' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:rules:1.0.2' - testImplementation 'junit:junit:4.12' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'net.java.dev.jna:jna:4.5.2@aar' } repositories { @@ -68,7 +87,7 @@ repositories { } afterEvaluate { - // The `cargoBuild` tasks isn't available until after evaluation. + // The `cargoBuild` task isn't available until after evaluation. android.libraryVariants.all { variant -> def productFlavor = "" variant.productFlavors.each { @@ -76,6 +95,8 @@ afterEvaluate { } def buildType = "${variant.buildType.name.capitalize()}" tasks["generate${productFlavor}${buildType}Assets"].dependsOn(tasks["cargoBuild"]) + + tasks["process${productFlavor}${buildType}UnitTestJavaRes"].dependsOn(tasks["cargoBuild"]) } } diff --git a/sdks/android/Mentat/library/src/main/java/org/mozilla/mentat/Mentat.java b/sdks/android/Mentat/library/src/main/java/org/mozilla/mentat/Mentat.java index f51ecc7f..90e7c4fc 100644 --- a/sdks/android/Mentat/library/src/main/java/org/mozilla/mentat/Mentat.java +++ b/sdks/android/Mentat/library/src/main/java/org/mozilla/mentat/Mentat.java @@ -21,10 +21,6 @@ import com.sun.jna.Pointer; * The raw pointer it holds is a pointer to a Store. */ public class Mentat extends RustObject { - static { - System.loadLibrary("mentat_ffi"); - } - /** * Create a new Mentat with the provided pointer to a Mentat Store * @param rawPointer A pointer to a Mentat Store. diff --git a/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/FFIIntegrationTest.java b/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/FFIIntegrationTest.java index eec8dd1e..52479781 100644 --- a/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/FFIIntegrationTest.java +++ b/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/FFIIntegrationTest.java @@ -11,15 +11,16 @@ package org.mozilla.mentat; import android.content.Context; -import android.content.res.AssetManager; -import android.util.Log; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.text.DateFormat; import java.text.ParseException; @@ -27,18 +28,20 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.LinkedHashMap; -import java.util.Locale; +import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.CountDownLatch; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** * Instrumentation test, which will execute on an Android device. */ -@RunWith(AndroidJUnit4.class) +@RunWith(RobolectricTestRunner.class) public class FFIIntegrationTest { - class DBSetupResult { TxReport schemaReport; TxReport dataReport; @@ -76,17 +79,19 @@ public class FFIIntegrationTest { @Test public void openStoreInLocationSucceeds() throws Exception { - Context context = InstrumentationRegistry.getTargetContext(); + Context context = RuntimeEnvironment.application.getApplicationContext(); String path = context.getDatabasePath("test.db").getAbsolutePath(); + assertTrue(new File(path).getParentFile().mkdirs()); Mentat mentat = Mentat.open(path); assertNotNull(mentat); } public String readFile(String fileName) { - Context testContext = InstrumentationRegistry.getInstrumentation().getContext(); - AssetManager assetManager = testContext.getAssets(); + final File resource = new File(getClass().getClassLoader().getResource(fileName).getFile()); + assertTrue(resource.exists()); + try { - InputStream inputStream = assetManager.open(fileName); + final FileInputStream inputStream = new FileInputStream(resource); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder out = new StringBuilder(); String line; @@ -261,8 +266,8 @@ public class FFIIntegrationTest { assertNotNull(row); String name = row.asString(0); String category = row.asString(1); - assert(name == "Community Harvest of Southwest Seattle"); - assert(category == "sustainable food"); + assertEquals("Community Harvest of Southwest Seattle", name); + assertEquals("sustainable food", category); expectation.countDown(); } }); @@ -611,10 +616,14 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?v . :in ?e :where [?e :foo/instant ?v]]"; - final CountDownLatch expectation = new CountDownLatch(1); - DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ", Locale.ENGLISH); - format.parse("2017-01-01T11:00:00+00:00"); + + final TimeZone tz = TimeZone.getTimeZone("UTC"); + final DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + format.setTimeZone(tz); + format.parse("2017-01-01T11:00:00.000Z"); final Calendar expectedDate = format.getCalendar(); + + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", aEntid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { @@ -1205,10 +1214,8 @@ public class FFIIntegrationTest { expectation2.await(); long timingDifference = uncachedTimer.duration() - cachedTimer.duration(); - Log.d("testCaching", "Cached query is "+ timingDifference +" nanoseconds faster than the uncached query"); - - assert cachedTimer.duration() < uncachedTimer.duration(); - + assertTrue("Cached query is "+ timingDifference +" nanoseconds faster than the uncached query", + cachedTimer.duration() < uncachedTimer.duration()); } } diff --git a/sdks/android/Mentat/library/src/test/resources/robolectric.properties b/sdks/android/Mentat/library/src/test/resources/robolectric.properties new file mode 100644 index 00000000..ba912df3 --- /dev/null +++ b/sdks/android/Mentat/library/src/test/resources/robolectric.properties @@ -0,0 +1 @@ +manifest=--none