From 303f013239dc43bba430c86297418cda13d228dd Mon Sep 17 00:00:00 2001 From: "arnaubennassar5@gmail.com" Date: Tue, 7 Apr 2020 15:35:51 +0200 Subject: [PATCH] Integration test for the generated Go code in Android --- .gitignore | 1 + android/iden3coreapi/build.gradle | 8 +- .../iden3coreapi/GomobileIntegrationTest.kt | 225 +++++++++++++++++- .../iden3coreapi/src/main/AndroidManifest.xml | 4 +- .../com/iden3/iden3coreapi/ExampleUnitTest.kt | 4 +- 5 files changed, 229 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index e773a22..33fe3e7 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ unlinked_spec.ds **/android/**/GeneratedPluginRegistrant.java **/android/key.properties **/android/iden3coreapi/github.properties +**/android/iden3coreapi/infura.properties *.jks # iOS/XCode related diff --git a/android/iden3coreapi/build.gradle b/android/iden3coreapi/build.gradle index 538bcd8..33b89ce 100644 --- a/android/iden3coreapi/build.gradle +++ b/android/iden3coreapi/build.gradle @@ -13,6 +13,12 @@ android { versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' + // Infura config + Properties infuraProperties = new Properties() + InputStream ins = new FileInputStream("iden3coreapi/infura.properties") + infuraProperties.load(ins) + ins.close() + buildConfigField("String", "INFURA_URL", infuraProperties['url']) } testOptions { @@ -46,7 +52,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.2.0' - implementation 'com.iden3:iden3mobile:v0.0.1-beta4' + implementation 'com.iden3:iden3mobile:v0.0.1-beta8' // Required -- JUnit 4 framework testImplementation 'junit:junit:4.13' // Optional -- Robolectric environment diff --git a/android/iden3coreapi/src/androidTest/java/com/iden3/iden3coreapi/GomobileIntegrationTest.kt b/android/iden3coreapi/src/androidTest/java/com/iden3/iden3coreapi/GomobileIntegrationTest.kt index e34c096..0b49dfd 100644 --- a/android/iden3coreapi/src/androidTest/java/com/iden3/iden3coreapi/GomobileIntegrationTest.kt +++ b/android/iden3coreapi/src/androidTest/java/com/iden3/iden3coreapi/GomobileIntegrationTest.kt @@ -1,12 +1,16 @@ package com.iden3.iden3coreapi -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 - +import android.util.Log +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import iden3mobile.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals import org.junit.Test import org.junit.runner.RunWith - -import org.junit.Assert.* +import java.io.File +import java.lang.Exception +import java.time.Instant /** * Instrumented test, which will execute on an Android device. @@ -14,11 +18,214 @@ import org.junit.Assert.* * See [testing documentation](http://d.android.com/tools/testing). */ @RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { +class GomobileIntegrationTest { @Test - fun useAppContext() { - // Context of the app under test. + fun fullFlow() { + // Test config + val nIdentities = 2 + val nClaimsPerId = 5 + val web3Url = BuildConfig.INFURA_URL + val issuerUrl = "http://167.172.104.160:6100/api/unstable" + val verifierUrl = "http://167.172.104.160:6200/api/unstable" + + // Create a new directory for each identity val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.iden3.iden3coreapi.test", appContext.packageName) + val storePath = appContext.filesDir.absolutePath + for (i in 0 until nIdentities){ + // Remove directory in case last test did't finish + File("$storePath/$i").deleteRecursively() + // Create directory + File("$storePath/$i/").mkdirs() + } + + // 1. Create nIdentities + var eventCounter = 0 + Log.i("fullFlow","CREATING $nIdentities IDENTITIES") + var ids = List(nIdentities) { i -> + try { + Iden3mobile.newIdentity( + "$storePath/$i", + "password", + web3Url, + 1000, + null, + object : Sender { + override fun send(event: Event) { + eventCounter++ + Log.i("fullFlow","EVENT RECEIVED: ${event.ticketId}. $eventCounter EVENTS RECEIVED SO FAR") + assertEquals(null, event.err) + } + } + ) + } catch (e: Exception) { + assertEquals(null, e) + null + } + } + + // 2. Request claims + Log.i("fullFlow", "REQUESTING $nClaimsPerId CLAIMS FOR EACH IDENTITY") + var ticketCounter = 0 + for (i in 0 until nClaimsPerId){ + var idCount = 0 + for (id in ids){ + id?.requestClaimWithCb(issuerUrl, "$idCount/$i/${Instant.now()}", object: CallbackRequestClaim{ + override fun fn(ticket: Ticket?, e: Exception?) { + assertNotEquals(null, ticket) + assertEquals(null, e) + ticketCounter++ + Log.i("fullFlow","REQUEST CLAIM TICKET RECEIVED: ${ticket?.id}. $ticketCounter TICKETS RECEIVED SO FAR}") + } + }) + idCount++ + } + } + // Wait for callbacks + while (ticketCounter < nIdentities*nClaimsPerId){ + Log.i("fullFlow","WAITING FOR REQUEST CLAIM TICKETS") + Thread.sleep(100) + } + + // Restart identities + ids = restartIdentities(ids, storePath, web3Url, fun (event: Event) { + eventCounter++ + Log.i("fullFlow","EVENT RECEIVED: ${event.ticketId}. $eventCounter EVENTS RECEIVED SO FAR") + assertEquals(null, event.err) + }) + + // Wait to receive claims + Log.i("fullFlow","WAITING TO RECEIVE CLAIMS") + while (eventCounter < nIdentities*nClaimsPerId){ + Log.i("fullFlow","WAITING FOR REQUEST CLAIM EVENTS.") + Thread.sleep(1000) + } + // Check claims on DB + assertEquals(nIdentities*nClaimsPerId, countClaims(ids)) + + // 3. Prove claims + // Since the claims have been issued instants ago, they may not be on chain yet + // so it's normal to receive error in the upcoming seconds + var provedClaims = 0 + var attempts = 10 + while (provedClaims < nIdentities*nClaimsPerId && attempts >= 0){ + provedClaims = 0 + for (id in ids){ + id?.getClaimDB()?.iterateClaimsJSON(object: ClaimDBIterFner{ + override fun fn(key: String, claim: String): Boolean{ + id.proveClaimWithCb(verifierUrl, key, object: CallbackProveClaim { + override fun fn(success: Boolean, e: Exception?) { + Log.i("fullFlow", "Verify claim: $key. Success? $success. Error? $e") + if(e == null){ + assertEquals(true, success) + provedClaims++ + } + } + }) + return true + } + }) + } + attempts-- + Log.i("fullFlow","WAITING FOR CLAIMS TO BE PROVED.") + Thread.sleep(2_000) + } + assertEquals(nClaimsPerId*nIdentities, provedClaims) + + // Restart identities + ids = restartIdentities(ids, storePath, web3Url, fun (event: Event) { + eventCounter++ + Log.i("fullFlow","UNEXPECTED EVENT RECEIVED: ${event.ticketId}.") + assertEquals(null, event) + }) + + // Check claims on DB + assertEquals(nIdentities*nClaimsPerId, countClaims(ids)) + + // Test cancel ticket + // Request a claim to generate a ticket + ticketCounter = 0 + for (id in ids){ + id?.requestClaimWithCb(issuerUrl, "${Instant.now()}", object: CallbackRequestClaim{ + override fun fn(ticket: Ticket?, e: Exception?) { + assertNotEquals(null, ticket) + assertEquals(null, e) + Log.i("fullFlow","REQUEST CLAIM TICKET RECEIVED.") + // Cancel ticket + id?.tickets.cancelTicket(ticket?.id) + ticketCounter++ + } + }) + } + while (ticketCounter < nIdentities){ + Log.i("fullFlow","WAITING FOR TICKETS TO BE GENERATED.") + Thread.sleep(1000) + } + // Check tickets + Log.i("fullFlow","CHECK TICKETS AFTER RESTART") + // Give time for cancellation to take effect + Thread.sleep(1000) + ticketCounter = 0 + var cancelledTicketCounter = 0 + for (id in ids){ + id?.tickets?.iterate(object: TicketOperator{ + override fun iterate(ticket: Ticket?): Boolean { + ticketCounter++ + if(ticket?.status == Iden3mobile.TicketStatusCancel){ + cancelledTicketCounter++ + } + return true + } + }) + } + assertEquals(nIdentities*nClaimsPerId + nIdentities, ticketCounter) + assertEquals(nIdentities, cancelledTicketCounter) + + // Stop identities + for(id in ids){ + id?.stop() + } + + // Remove identity directories + for (i in 0 until nIdentities){ + File("$storePath/$i").deleteRecursively() + } + } + + fun restartIdentities(ids: List, storePath: String, web3Url: String, fn: (e:Event)->Unit): List{ + Log.i("fullFlow","RESTARTING IDENTITIES") + for (id in ids){ + id?.stop() + } + return List(ids.size) { i -> + try { + Iden3mobile.newIdentityLoad( + "$storePath/$i", + "password", + web3Url, + 1000, + object : Sender { + override fun send(event: Event) { + fn(event) + } + } + ) + } catch (e: Exception) { + assertEquals(null, e) + null + } + } + } + + fun countClaims(ids: List): Int { + var claimCounter = 0 + for (id in ids){ + id?.getClaimDB()?.iterateClaimsJSON(object: ClaimDBIterFner{ + override fun fn(claim: String, key: String): Boolean{ + claimCounter++ + return true + } + }) + } + return claimCounter } } diff --git a/android/iden3coreapi/src/main/AndroidManifest.xml b/android/iden3coreapi/src/main/AndroidManifest.xml index ec07dc3..0431ce4 100644 --- a/android/iden3coreapi/src/main/AndroidManifest.xml +++ b/android/iden3coreapi/src/main/AndroidManifest.xml @@ -1,2 +1,4 @@ + package="com.iden3.iden3coreapi" > + + diff --git a/android/iden3coreapi/src/test/java/com/iden3/iden3coreapi/ExampleUnitTest.kt b/android/iden3coreapi/src/test/java/com/iden3/iden3coreapi/ExampleUnitTest.kt index e8c19fa..1b09994 100644 --- a/android/iden3coreapi/src/test/java/com/iden3/iden3coreapi/ExampleUnitTest.kt +++ b/android/iden3coreapi/src/test/java/com/iden3/iden3coreapi/ExampleUnitTest.kt @@ -11,7 +11,7 @@ import androidx.test.core.app.ApplicationProvider * See [testing documentation](http://d.android.com/tools/testing). */ class ExampleUnitTest { - val context = ApplicationProvider.getApplicationContext() + //val context = ApplicationProvider.getApplicationContext() @Test fun addition_isCorrect() { @@ -20,7 +20,7 @@ class ExampleUnitTest { @Test fun testIden3CoreAPI() { - val iden3CoreAPI = Iden3CoreAPI.instance + val iden3CoreAPI = Iden3CoreAPI() assertTrue(iden3CoreAPI != null) } }