From 6856462f1bcd39bf64242472a56b5f920e2af6d2 Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Mon, 23 Jul 2018 12:27:11 -0700 Subject: [PATCH 1/5] [sdks/android] Part 1: Move androidTest to test. --- .../java/org/mozilla/mentat/Expectation.java | 0 .../java/org/mozilla/mentat/FFIIntegrationTest.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename sdks/android/Mentat/library/src/{androidTest => test}/java/org/mozilla/mentat/Expectation.java (100%) rename sdks/android/Mentat/library/src/{androidTest => test}/java/org/mozilla/mentat/FFIIntegrationTest.java (100%) diff --git a/sdks/android/Mentat/library/src/androidTest/java/org/mozilla/mentat/Expectation.java b/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/Expectation.java similarity index 100% rename from sdks/android/Mentat/library/src/androidTest/java/org/mozilla/mentat/Expectation.java rename to sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/Expectation.java diff --git a/sdks/android/Mentat/library/src/androidTest/java/org/mozilla/mentat/FFIIntegrationTest.java b/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/FFIIntegrationTest.java similarity index 100% rename from sdks/android/Mentat/library/src/androidTest/java/org/mozilla/mentat/FFIIntegrationTest.java rename to sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/FFIIntegrationTest.java From 190e05e360e7d116d194a5aa2226cee717f3eaf9 Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Tue, 24 Jul 2018 11:37:30 -0700 Subject: [PATCH 2/5] [sdks/android] Part 2: Replace Expectation/wait/notify with CountDownLatch. Locally, I witnessed very slow tests. Profiling with Visual VM revealed a lot of time spent in `wait`. Digging in, we were trying to be clever, with a `wait(1000)/notify` mechanism. However, there were never multiple threads in play, so the waiter wasn't waiting when `notify` was invoked. That means we always timed out. I think this never worked and using bare `wait()` would have revealed that. Anyway, `CountDownLatch` maintains the one bit of state (was I notified) and generalizes smoothly to when we have threads. --- .../java/org/mozilla/mentat/Expectation.java | 27 -- .../mozilla/mentat/FFIIntegrationTest.java | 327 ++++++------------ 2 files changed, 109 insertions(+), 245 deletions(-) delete mode 100644 sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/Expectation.java diff --git a/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/Expectation.java b/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/Expectation.java deleted file mode 100644 index 3c99d674..00000000 --- a/sdks/android/Mentat/library/src/test/java/org/mozilla/mentat/Expectation.java +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- - * Copyright 2018 Mozilla - * 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 org.mozilla.mentat; - -import java.util.EventListener; - -interface ExpectationEventListener extends EventListener { - public void fulfill(); -} - -public class Expectation implements ExpectationEventListener { - public boolean isFulfilled = false; - public void fulfill() { - this.isFulfilled = true; - synchronized (this) { - notifyAll( ); - } - } -} 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 0b5be28d..eec8dd1e 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 @@ -12,8 +12,6 @@ package org.mozilla.mentat; import android.content.Context; import android.content.res.AssetManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; import android.util.Log; import org.junit.Test; @@ -31,6 +29,7 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.Locale; import java.util.UUID; +import java.util.concurrent.CountDownLatch; import static org.junit.Assert.*; @@ -198,26 +197,23 @@ public class FFIIntegrationTest { public void runScalarSucceeds() throws InterruptedException { Mentat mentat = openAndInitializeCitiesStore(); String query = "[:find ?n . :in ?name :where [(fulltext $ :community/name ?name) [[?e ?n]]]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bind("?name", "Wallingford").run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals("KOMO Communities - Wallingford", value.asString()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test public void runCollSucceeds() throws InterruptedException { Mentat mentat = openAndInitializeCitiesStore(); String query = "[:find [?when ...] :where [_ :db/txInstant ?when] :order (asc ?when)]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).run(new CollResultHandler() { @Override public void handleList(CollResult list) { @@ -225,20 +221,17 @@ public class FFIIntegrationTest { for (int i = 0; i < 3; ++i) { assertNotNull(list.asDate(i)); } - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test public void runCollResultIteratorSucceeds() throws InterruptedException { Mentat mentat = openAndInitializeCitiesStore(); String query = "[:find [?when ...] :where [_ :db/txInstant ?when] :order (asc ?when)]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).run(new CollResultHandler() { @Override public void handleList(CollResult list) { @@ -247,13 +240,10 @@ public class FFIIntegrationTest { for(TypedValue value: list) { assertNotNull(value.asDate()); } - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -264,7 +254,7 @@ public class FFIIntegrationTest { " [?c :community/name ?name]\n" + " [?c :community/type :community.type/website]\n" + " [(fulltext $ :community/category \"food\") [[?c ?cat]]]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -273,13 +263,10 @@ public class FFIIntegrationTest { String category = row.asString(1); assert(name == "Community Harvest of Southwest Seattle"); assert(category == "sustainable food"); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -296,7 +283,7 @@ public class FFIIntegrationTest { expectedResults.put("Seattle Chinatown Guide", "food"); expectedResults.put("Community Harvest of Southwest Seattle", "sustainable food"); expectedResults.put("University District Food Bank", "food bank"); - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).run(new RelResultHandler() { @Override public void handleRows(RelResult rows) { @@ -313,13 +300,10 @@ public class FFIIntegrationTest { ++index; } assertEquals(expectedResults.size(), index); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -336,7 +320,7 @@ public class FFIIntegrationTest { expectedResults.put("Seattle Chinatown Guide", "food"); expectedResults.put("Community Harvest of Southwest Seattle", "sustainable food"); expectedResults.put("University District Food Bank", "food bank"); - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).run(new RelResultHandler() { @Override public void handleRows(RelResult rows) { @@ -352,13 +336,10 @@ public class FFIIntegrationTest { assertNotNull(expectedCategory); assertEquals(expectedCategory, category); } - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -367,19 +348,16 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?e . :in ?long :where [?e :foo/long ?long]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bind("?long", 25).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(aEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -389,19 +367,16 @@ public class FFIIntegrationTest { long stringEntid = mentat.entIdForAttribute(":foo/string"); final Long bEntid = report.getEntidForTempId("b"); String query = "[:find ?e . :in ?ref :where [?e :foo/ref ?ref]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?ref", stringEntid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(bEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -411,19 +386,16 @@ public class FFIIntegrationTest { String refKeyword = ":foo/string"; final Long bEntid = report.getEntidForTempId("b"); String query = "[:find ?e . :in ?ref :where [?e :foo/ref ?ref]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindKeywordReference("?ref", refKeyword).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(bEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -432,19 +404,16 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?e . :in ?kw :where [?e :foo/keyword ?kw]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindKeyword("?kw", ":foo/string").run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(aEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -455,7 +424,7 @@ public class FFIIntegrationTest { Date date = new Date(1523896758000L); String query = "[:find [?e ?d] :in ?now :where [?e :foo/instant ?d] [(< ?d ?now)]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bind("?now", date).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -463,32 +432,26 @@ public class FFIIntegrationTest { TypedValue value = row.get(0); assertNotNull(value); assertEquals(aEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test public void bindingStringValueSucceeds() throws InterruptedException { Mentat mentat = this.openAndInitializeCitiesStore(); String query = "[:find ?n . :in ?name :where [(fulltext $ :community/name ?name) [[?e ?n]]]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bind("?name", "Wallingford").run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals("KOMO Communities - Wallingford", value.asString()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -498,19 +461,16 @@ public class FFIIntegrationTest { final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?e . :in ?uuid :where [?e :foo/uuid ?uuid]]"; UUID uuid = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bind("?uuid", uuid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(aEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -519,20 +479,17 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?e . :in ?bool :where [?e :foo/boolean ?bool]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bind("?bool", true).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(aEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -541,19 +498,16 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?e . :in ?double :where [?e :foo/double ?double]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bind("?double", 11.23).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(aEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -562,20 +516,17 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?v . :in ?e :where [?e :foo/long ?v]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", aEntid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(25, value.asLong().longValue()); assertEquals(25, value.asLong().longValue()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -584,20 +535,17 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?e . :where [?e :foo/long 25]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(aEntid, value.asEntid()); assertEquals(aEntid, value.asEntid()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -606,20 +554,17 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?v . :in ?e :where [?e :foo/keyword ?v]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", aEntid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(":foo/string", value.asKeyword()); assertEquals(":foo/string", value.asKeyword()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -628,20 +573,17 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?v . :in ?e :where [?e :foo/boolean ?v]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", aEntid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(true, value.asBoolean()); assertEquals(true, value.asBoolean()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -650,20 +592,17 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?v . :in ?e :where [?e :foo/double ?v]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", aEntid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(new Double(11.23), value.asDouble()); assertEquals(new Double(11.23), value.asDouble()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -672,7 +611,7 @@ 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 Expectation expectation = new Expectation(); + 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 Calendar expectedDate = format.getCalendar(); @@ -682,13 +621,10 @@ public class FFIIntegrationTest { assertNotNull(value); assertEquals(expectedDate.getTime(), value.asDate()); assertEquals(expectedDate.getTime(), value.asDate()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -697,20 +633,17 @@ public class FFIIntegrationTest { TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?v . :in ?e :where [?e :foo/string ?v]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", aEntid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals("The higher we soar the smaller we appear to those who cannot fly.", value.asString()); assertEquals("The higher we soar the smaller we appear to those who cannot fly.", value.asString()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -720,20 +653,17 @@ public class FFIIntegrationTest { final Long aEntid = report.getEntidForTempId("a"); String query = "[:find ?v . :in ?e :where [?e :foo/uuid ?v]]"; final UUID expectedUUID = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", aEntid).run(new ScalarResultHandler() { @Override public void handleValue(TypedValue value) { assertNotNull(value); assertEquals(expectedUUID, value.asUUID()); assertEquals(expectedUUID, value.asUUID()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -800,7 +730,7 @@ public class FFIIntegrationTest { " [?e :foo/keyword ?k]\n" + " [?e :foo/ref ?r]]"; - final Expectation expectation1 = new Expectation(); + final CountDownLatch expectation1 = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -813,14 +743,11 @@ public class FFIIntegrationTest { assertEquals("Silence is worse; all truths that are kept silent become poisonous.", row.asString(5)); assertEquals(":foo/string", row.asKeyword(6)); assertEquals(stringEntid, row.asEntid(7).longValue()); - expectation1.fulfill(); + expectation1.countDown(); } }); - synchronized (expectation1) { - expectation1.wait(1000); - } - assertTrue(expectation1.isFulfilled); + expectation1.await(); InProgressBuilder builder = mentat.entityBuilder(); builder.add(bEntid, ":foo/boolean", true); @@ -836,7 +763,7 @@ public class FFIIntegrationTest { builder.commit(); - final Expectation expectation2 = new Expectation(); + final CountDownLatch expectation2 = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -850,14 +777,11 @@ public class FFIIntegrationTest { assertEquals("Become who you are!", row.asString(5)); assertEquals(":foo/long", row.asKeyword(6)); assertEquals(longEntid, row.asEntid(7).longValue()); - expectation2.fulfill(); + expectation2.countDown(); } }); - synchronized (expectation2) { - expectation2.wait(1000); - } - assertTrue(expectation2.isFulfilled); + expectation2.await(); } @Test @@ -880,7 +804,7 @@ public class FFIIntegrationTest { " [?e :foo/keyword ?k]\n" + " [?e :foo/ref ?r]]"; - final Expectation expectation1 = new Expectation(); + final CountDownLatch expectation1 = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -893,14 +817,11 @@ public class FFIIntegrationTest { assertEquals("Silence is worse; all truths that are kept silent become poisonous.", row.asString(5)); assertEquals(":foo/string", row.asKeyword(6)); assertEquals(stringEntid, row.asEntid(7).longValue()); - expectation1.fulfill(); + expectation1.countDown(); } }); - synchronized (expectation1) { - expectation1.wait(1000); - } - assertTrue(expectation1.isFulfilled); + expectation1.await(); EntityBuilder builder = mentat.entityBuilder(bEntid); builder.add(":foo/boolean", true); @@ -916,7 +837,7 @@ public class FFIIntegrationTest { builder.commit(); - final Expectation expectation2 = new Expectation(); + final CountDownLatch expectation2 = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -930,14 +851,11 @@ public class FFIIntegrationTest { assertEquals("Become who you are!", row.asString(5)); assertEquals(":foo/long", row.asKeyword(6)); assertEquals(longEntid, row.asEntid(7).longValue()); - expectation2.fulfill(); + expectation2.countDown(); } }); - synchronized (expectation2) { - expectation2.wait(1000); - } - assertTrue(expectation2.isFulfilled); + expectation2.await(); } @Test @@ -972,7 +890,7 @@ public class FFIIntegrationTest { " [?e :foo/keyword ?k]\n" + " [?e :foo/ref ?r]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", cEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -986,14 +904,11 @@ public class FFIIntegrationTest { assertEquals("Become who you are!", row.asString(5)); assertEquals(":foo/long", row.asKeyword(6)); assertEquals(longEntid, row.asEntid(7).longValue()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); } @Test @@ -1034,7 +949,7 @@ public class FFIIntegrationTest { " [?e :foo/keyword ?k]\n" + " [?e :foo/ref ?r]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -1048,14 +963,11 @@ public class FFIIntegrationTest { assertEquals("Become who you are!", row.asString(5)); assertEquals(":foo/long", row.asKeyword(6)); assertEquals(longEntid, row.asEntid(7).longValue()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); TypedValue longValue = mentat.valueForAttributeOfEntity(":foo/long", aEntid); assertEquals(22, longValue.asLong().longValue()); @@ -1100,7 +1012,7 @@ public class FFIIntegrationTest { " [?e :foo/keyword ?k]\n" + " [?e :foo/ref ?r]]"; - final Expectation expectation = new Expectation(); + final CountDownLatch expectation = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { @@ -1114,14 +1026,11 @@ public class FFIIntegrationTest { assertEquals("Become who you are!", row.asString(5)); assertEquals(":foo/long", row.asKeyword(6)); assertEquals(longEntid, row.asEntid(7).longValue()); - expectation.fulfill(); + expectation.countDown(); } }); - synchronized (expectation) { - expectation.wait(1000); - } - assertTrue(expectation.isFulfilled); + expectation.await(); TypedValue longValue = mentat.valueForAttributeOfEntity(":foo/long", aEntid); assertEquals(22, longValue.asLong().longValue()); @@ -1147,7 +1056,7 @@ public class FFIIntegrationTest { " [?e :foo/keyword ?k]\n" + " [?e :foo/ref ?r]]"; - final Expectation expectation1 = new Expectation(); + final CountDownLatch expectation1 = new CountDownLatch(1); final Date previousDate = new Date(1514804400000l); final UUID previousUuid = UUID.fromString("4cb3f828-752d-497a-90c9-b1fd516d5644"); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @@ -1162,14 +1071,11 @@ public class FFIIntegrationTest { assertEquals("Silence is worse; all truths that are kept silent become poisonous.", row.asString(5)); assertEquals(":foo/string", row.asKeyword(6)); assertEquals(stringEntid, row.asEntid(7).longValue()); - expectation1.fulfill(); + expectation1.countDown(); } }); - synchronized (expectation1) { - expectation1.wait(1000); - } - assertTrue(expectation1.isFulfilled); + expectation1.await(); EntityBuilder builder = mentat.entityBuilder(bEntid); builder.retract(":foo/boolean", false); @@ -1182,19 +1088,16 @@ public class FFIIntegrationTest { builder.retractRef(":foo/ref", stringEntid); builder.commit(); - final Expectation expectation2 = new Expectation(); + final CountDownLatch expectation2 = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { assertNull(row); - expectation2.fulfill(); + expectation2.countDown(); } }); - synchronized (expectation2) { - expectation2.wait(1000); - } - assertTrue(expectation2.isFulfilled); + expectation2.await(); } @Test @@ -1217,7 +1120,7 @@ public class FFIIntegrationTest { " [?e :foo/keyword ?k]\n" + " [?e :foo/ref ?r]]"; - final Expectation expectation1 = new Expectation(); + final CountDownLatch expectation1 = new CountDownLatch(1); final Date previousDate = new Date(1514804400000l); final UUID previousUuid = UUID.fromString("4cb3f828-752d-497a-90c9-b1fd516d5644"); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @@ -1232,14 +1135,11 @@ public class FFIIntegrationTest { assertEquals("Silence is worse; all truths that are kept silent become poisonous.", row.asString(5)); assertEquals(":foo/string", row.asKeyword(6)); assertEquals(stringEntid, row.asEntid(7).longValue()); - expectation1.fulfill(); + expectation1.countDown(); } }); - synchronized (expectation1) { - expectation1.wait(1000); - } - assertTrue(expectation1.isFulfilled); + expectation1.await(); InProgressBuilder builder = mentat.entityBuilder(); builder.retract(bEntid, ":foo/boolean", false); @@ -1252,19 +1152,16 @@ public class FFIIntegrationTest { builder.retractRef(bEntid, ":foo/ref", stringEntid); builder.commit(); - final Expectation expectation2 = new Expectation(); + final CountDownLatch expectation2 = new CountDownLatch(1); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override public void handleRow(TupleResult row) { assertNull(row); - expectation2.fulfill(); + expectation2.countDown(); } }); - synchronized (expectation2) { - expectation2.wait(1000); - } - assertTrue(expectation2.isFulfilled); + expectation2.await(); } @Test @@ -1276,7 +1173,7 @@ public class FFIIntegrationTest { Mentat mentat = openAndInitializeCitiesStore(); - final Expectation expectation1 = new Expectation(); + final CountDownLatch expectation1 = new CountDownLatch(1); final QueryTimer uncachedTimer = new QueryTimer(); uncachedTimer.start(); mentat.query(query).run(new RelResultHandler() { @@ -1284,19 +1181,16 @@ public class FFIIntegrationTest { public void handleRows(RelResult rows) { uncachedTimer.end(); assertNotNull(rows); - expectation1.fulfill(); + expectation1.countDown(); } }); - synchronized (expectation1) { - expectation1.wait(1000); - } - assertTrue(expectation1.isFulfilled); + expectation1.await(); mentat.cache(":neighborhood/name", CacheDirection.REVERSE); mentat.cache(":neighborhood/district", CacheDirection.FORWARD); - final Expectation expectation2 = new Expectation(); + final CountDownLatch expectation2 = new CountDownLatch(1); final QueryTimer cachedTimer = new QueryTimer(); cachedTimer.start(); mentat.query(query).run(new RelResultHandler() { @@ -1304,14 +1198,11 @@ public class FFIIntegrationTest { public void handleRows(RelResult rows) { cachedTimer.end(); assertNotNull(rows); - expectation2.fulfill(); + expectation2.countDown(); } }); - synchronized (expectation2) { - expectation2.wait(1000); - } - assertTrue(expectation2.isFulfilled); + expectation2.await(); long timingDifference = uncachedTimer.duration() - cachedTimer.duration(); Log.d("testCaching", "Cached query is "+ timingDifference +" nanoseconds faster than the uncached query"); From 2978ad91c0b0f5bf215fe4fdfc4e70c26f1fec67 Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Thu, 26 Jul 2018 17:22:53 -0700 Subject: [PATCH 3/5] [sdks/android] Part 3: Finish conversion to Robolectric. --- sdks/android/Mentat/build.gradle | 6 ++- sdks/android/Mentat/library/build.gradle | 33 ++++++++++--- .../main/java/org/mozilla/mentat/Mentat.java | 4 -- .../mozilla/mentat/FFIIntegrationTest.java | 47 +++++++++++-------- .../src/test/resources/robolectric.properties | 1 + 5 files changed, 60 insertions(+), 31 deletions(-) create mode 100644 sdks/android/Mentat/library/src/test/resources/robolectric.properties 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 From a7d2057bc694ae3bf2254e1dff1634df14fc1f7f Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Thu, 26 Jul 2018 17:18:48 -0700 Subject: [PATCH 4/5] [sdks/android] Post: Address most Android Studio complaints. The only ones I cared about were unchecked access, but while I'm here, might as well do most of them. --- .../mozilla/mentat/FFIIntegrationTest.java | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) 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 52479781..8f5979c9 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 @@ -46,7 +46,7 @@ public class FFIIntegrationTest { TxReport schemaReport; TxReport dataReport; - public DBSetupResult(TxReport schemaReport, TxReport dataReport) { + DBSetupResult(TxReport schemaReport, TxReport dataReport) { this.schemaReport = schemaReport; this.dataReport = dataReport; } @@ -56,29 +56,29 @@ public class FFIIntegrationTest { private long startTime = 0; private long endTime = 0; - public void start() { + void start() { this.startTime = System.nanoTime(); } - public void end() { + void end() { this.endTime = System.nanoTime(); } - public long duration() { + long duration() { return this.endTime - this.startTime; } } - Mentat mentat = null; + private Mentat mentat = null; @Test - public void openInMemoryStoreSucceeds() throws Exception { + public void openInMemoryStoreSucceeds() { Mentat mentat = Mentat.open(); assertNotNull(mentat); } @Test - public void openStoreInLocationSucceeds() throws Exception { + public void openStoreInLocationSucceeds() { Context context = RuntimeEnvironment.application.getApplicationContext(); String path = context.getDatabasePath("test.db").getAbsolutePath(); assertTrue(new File(path).getParentFile().mkdirs()); @@ -96,7 +96,7 @@ public class FFIIntegrationTest { StringBuilder out = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { - out.append(line + "\n"); + out.append(line).append("\n"); } return out.toString(); } catch (IOException e) { @@ -283,7 +283,7 @@ public class FFIIntegrationTest { " [?c :community/type :community.type/website]\n" + " [(fulltext $ :community/category \"food\") [[?c ?cat]]]]"; - final LinkedHashMap expectedResults = new LinkedHashMap(); + final LinkedHashMap expectedResults = new LinkedHashMap<>(); expectedResults.put("InBallard", "food"); expectedResults.put("Seattle Chinatown Guide", "food"); expectedResults.put("Community Harvest of Southwest Seattle", "sustainable food"); @@ -299,7 +299,7 @@ public class FFIIntegrationTest { assertNotNull(name); String category = row.asString(1); assertNotNull(category); - String expectedCategory = expectedResults.get(name).toString(); + String expectedCategory = expectedResults.get(name); assertNotNull(expectedCategory); assertEquals(expectedCategory, category); ++index; @@ -320,7 +320,7 @@ public class FFIIntegrationTest { " [?c :community/type :community.type/website]\n" + " [(fulltext $ :community/category \"food\") [[?c ?cat]]]]"; - final LinkedHashMap expectedResults = new LinkedHashMap(); + final LinkedHashMap expectedResults = new LinkedHashMap<>(); expectedResults.put("InBallard", "food"); expectedResults.put("Seattle Chinatown Guide", "food"); expectedResults.put("Community Harvest of Southwest Seattle", "sustainable food"); @@ -337,7 +337,7 @@ public class FFIIntegrationTest { assertNotNull(name); String category = row.asString(1); assertNotNull(category); - String expectedCategory = expectedResults.get(name).toString(); + String expectedCategory = expectedResults.get(name); assertNotNull(expectedCategory); assertEquals(expectedCategory, category); } @@ -422,7 +422,7 @@ public class FFIIntegrationTest { } @Test - public void bindingDateValueSucceeds() throws InterruptedException, ParseException { + public void bindingDateValueSucceeds() throws InterruptedException { Mentat mentat = Mentat.open(); TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); @@ -676,7 +676,7 @@ public class FFIIntegrationTest { } @Test - public void valueForAttributeOfEntitySucceeds() throws InterruptedException { + public void valueForAttributeOfEntitySucceeds() { Mentat mentat = Mentat.open(); TxReport report = this.populateWithTypesSchema(mentat).dataReport; final Long aEntid = report.getEntidForTempId("a"); @@ -745,7 +745,7 @@ public class FFIIntegrationTest { public void handleRow(TupleResult row) { assertNotNull(row); assertEquals(false, row.asBool(0)); - assertEquals(new Date(1514804400000l), row.asDate(1)); + assertEquals(new Date(1514804400000L), row.asDate(1)); assertEquals(UUID.fromString("4cb3f828-752d-497a-90c9-b1fd516d5644"), row.asUUID(2)); assertEquals(50, row.asLong(3).longValue()); assertEquals(new Double(22.46), row.asDouble(4)); @@ -760,7 +760,7 @@ public class FFIIntegrationTest { InProgressBuilder builder = mentat.entityBuilder(); builder.add(bEntid, ":foo/boolean", true); - final Date newDate = new Date(1524743301000l); + final Date newDate = new Date(1524743301000L); builder.add(bEntid, ":foo/instant", newDate); final UUID newUUID = UUID.randomUUID(); builder.add(bEntid, ":foo/uuid", newUUID); @@ -819,7 +819,7 @@ public class FFIIntegrationTest { public void handleRow(TupleResult row) { assertNotNull(row); assertEquals(false, row.asBool(0)); - assertEquals(new Date(1514804400000l), row.asDate(1)); + assertEquals(new Date(1514804400000L), row.asDate(1)); assertEquals(UUID.fromString("4cb3f828-752d-497a-90c9-b1fd516d5644"), row.asUUID(2)); assertEquals(50, row.asLong(3).longValue()); assertEquals(new Double(22.46), row.asDouble(4)); @@ -834,7 +834,7 @@ public class FFIIntegrationTest { EntityBuilder builder = mentat.entityBuilder(bEntid); builder.add(":foo/boolean", true); - final Date newDate = new Date(1524743301000l); + final Date newDate = new Date(1524743301000L); builder.add(":foo/instant", newDate); final UUID newUUID = UUID.randomUUID(); builder.add(":foo/uuid", newUUID); @@ -875,7 +875,7 @@ public class FFIIntegrationTest { EntityBuilder builder = mentat.entityBuilder("c"); builder.add(":foo/boolean", true); - final Date newDate = new Date(1524743301000l); + final Date newDate = new Date(1524743301000L); builder.add(":foo/instant", newDate); final UUID newUUID = UUID.randomUUID(); builder.add(":foo/uuid", newUUID); @@ -929,7 +929,7 @@ public class FFIIntegrationTest { final long longEntid = reports.schemaReport.getEntidForTempId("l"); InProgressBuilder builder = mentat.entityBuilder(); builder.add(bEntid, ":foo/boolean", true); - final Date newDate = new Date(1524743301000l); + final Date newDate = new Date(1524743301000L); builder.add(bEntid, ":foo/instant", newDate); final UUID newUUID = UUID.randomUUID(); builder.add(bEntid, ":foo/uuid", newUUID); @@ -992,7 +992,7 @@ public class FFIIntegrationTest { EntityBuilder builder = mentat.entityBuilder(bEntid); builder.add(":foo/boolean", true); - final Date newDate = new Date(1524743301000l); + final Date newDate = new Date(1524743301000L); builder.add(":foo/instant", newDate); final UUID newUUID = UUID.randomUUID(); builder.add(":foo/uuid", newUUID); @@ -1066,7 +1066,7 @@ public class FFIIntegrationTest { " [?e :foo/ref ?r]]"; final CountDownLatch expectation1 = new CountDownLatch(1); - final Date previousDate = new Date(1514804400000l); + final Date previousDate = new Date(1514804400000L); final UUID previousUuid = UUID.fromString("4cb3f828-752d-497a-90c9-b1fd516d5644"); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override @@ -1130,7 +1130,7 @@ public class FFIIntegrationTest { " [?e :foo/ref ?r]]"; final CountDownLatch expectation1 = new CountDownLatch(1); - final Date previousDate = new Date(1514804400000l); + final Date previousDate = new Date(1514804400000L); final UUID previousUuid = UUID.fromString("4cb3f828-752d-497a-90c9-b1fd516d5644"); mentat.query(query).bindEntidReference("?e", bEntid).run(new TupleResultHandler() { @Override From e06bfd1b7ded029b8f66ad710d298c3d92fe7f6e Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Fri, 27 Jul 2018 10:20:12 -0700 Subject: [PATCH 5/5] [sdks/android] Workaround Android Studio JUnit test runner runtime classpath issue. --- sdks/android/Mentat/library/build.gradle | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sdks/android/Mentat/library/build.gradle b/sdks/android/Mentat/library/build.gradle index 680ec094..cf33a652 100644 --- a/sdks/android/Mentat/library/build.gradle +++ b/sdks/android/Mentat/library/build.gradle @@ -68,11 +68,30 @@ cargo { defaultToolchainBuildPrefixDir = Platform.RESOURCE_PREFIX } +configurations { + // There's an interaction between Gradle's resolution of dependencies with different types + // (@jar, @aar) for `implementation` and `testImplementation` and with Android Studio's built-in + // JUnit test runner. The runtime classpath in the built-in JUnit test runner gets the + // dependency from the `implementation`, which is type @aar, and therefore the JNA dependency + // doesn't provide the JNI dispatch libraries in the correct Java resource directories. I think + // what's happening is that @aar type in `implementation` resolves to the @jar type in + // `testImplementation`, and that it wins the dependency resolution battle. + // + // A workaround is to add a new configuration which depends on the @jar type and to reference + // the underlying JAR file directly in `testImplementation`. This JAR file doesn't resolve to + // the @aar type in `implementation`. This works when invoked via `gradle`, but also sets the + // correct runtime classpath when invoked with Android Studio's built-in JUnit test runner. + // Success! + jnaForTest +} + dependencies { + jnaForTest 'net.java.dev.jna:jna:4.5.2@jar' + 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 files(configurations.jnaForTest.files) testImplementation 'junit:junit:4.12' testImplementation 'org.robolectric:robolectric:3.8' testImplementation 'org.mockito:mockito-core:2.20.0'