Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.world.walletkit

import java.io.File
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull

class AtomicBlobStoreTests {
@Test
fun writeReadDelete() {
val root = tempDirectory()
val store = FileBlobStore(root)
val path = "account_keys.bin"
val payload = byteArrayOf(1, 2, 3, 4)

store.writeAtomic(path, payload)
val readBack = store.read(path)
assertEquals(payload.toList(), readBack?.toList())

store.delete(path)
assertNull(store.read(path))

root.deleteRecursively()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
package org.world.walletkit

import uniffi.walletkit_core.CredentialStore
import uniffi.walletkit_core.StorageException
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNotEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue

class CredentialStoreTests {
@Test
fun methodsRequireInit() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

assertFailsWith<StorageException.NotInitialized> {
store.listCredentials(issuerSchemaId = null, now = 100UL)
}
assertFailsWith<StorageException.NotInitialized> {
store.merkleCacheGet(validUntil = 100UL)
}

root.deleteRecursively()
}

@Test
fun initRejectsLeafIndexMismatch() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

store.`init`(leafIndex = 42UL, now = 100UL)
val error =
assertFailsWith<StorageException.InvalidLeafIndex> {
store.`init`(leafIndex = 43UL, now = 101UL)
}
assertEquals(42UL, error.`expected`)
assertEquals(43UL, error.`provided`)

root.deleteRecursively()
}

@Test
fun initIsIdempotentForSameLeafIndex() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

store.`init`(leafIndex = 42UL, now = 100UL)
val credentialId =
store.storeCredential(
credential = sampleCredential(),
blindingFactor = sampleBlindingFactor(),
expiresAt = 1_800_000_000UL,
associatedData = null,
now = 100UL,
)

store.`init`(leafIndex = 42UL, now = 101UL)

val records = store.listCredentials(issuerSchemaId = null, now = 102UL)
assertEquals(1, records.size)
assertEquals(credentialId, records.single().credentialId)

root.deleteRecursively()
}

@Test
fun storeAndCacheFlows() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

store.`init`(leafIndex = 42UL, now = 100UL)
assertNull(store.merkleCacheGet(validUntil = 100UL))

val credentialId =
store.storeCredential(
credential = sampleCredential(),
blindingFactor = sampleBlindingFactor(),
expiresAt = 1_800_000_000UL,
associatedData = byteArrayOf(4, 5, 6),
now = 100UL,
)

val records = store.listCredentials(issuerSchemaId = null, now = 101UL)
assertEquals(1, records.size)
val record = records[0]
assertEquals(credentialId, record.credentialId)
assertEquals(7UL, record.issuerSchemaId)
assertEquals(1_800_000_000UL, record.expiresAt)

val proofBytes = byteArrayOf(9, 9, 9)
store.merkleCachePut(
proofBytes = proofBytes,
now = 100UL,
ttlSeconds = 60UL,
)
val cached =
store.merkleCacheGet(
validUntil = 110UL,
)
assertEquals(proofBytes.toList(), cached?.toList())
val expired = store.merkleCacheGet(validUntil = 161UL)
assertNull(expired)

root.deleteRecursively()
}

@Test
fun storeCredentialReturnsStableDistinctIds() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

store.`init`(leafIndex = 42UL, now = 100UL)
val firstCredentialId =
store.storeCredential(
credential = sampleCredential(issuerSchemaId = 7UL, expiresAt = 1_800_000_000UL),
blindingFactor = sampleBlindingFactor(),
expiresAt = 1_800_000_000UL,
associatedData = null,
now = 100UL,
)
val secondCredentialId =
store.storeCredential(
credential = sampleCredential(issuerSchemaId = 8UL, expiresAt = 1_900_000_000UL),
blindingFactor = sampleBlindingFactor(),
expiresAt = 1_900_000_000UL,
associatedData = null,
now = 101UL,
)

assertNotEquals(firstCredentialId, secondCredentialId)

val records = store.listCredentials(issuerSchemaId = null, now = 102UL)
assertEquals(2, records.size)
assertEquals(
setOf(firstCredentialId, secondCredentialId),
records.map { it.credentialId }.toSet(),
)

root.deleteRecursively()
}

@Test
fun listCredentialsFiltersByIssuerSchemaId() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

store.`init`(leafIndex = 42UL, now = 100UL)
store.storeCredential(
credential = sampleCredential(issuerSchemaId = 7UL),
blindingFactor = sampleBlindingFactor(),
expiresAt = 1_800_000_000UL,
associatedData = null,
now = 100UL,
)
store.storeCredential(
credential = sampleCredential(issuerSchemaId = 8UL, expiresAt = 1_900_000_000UL),
blindingFactor = sampleBlindingFactor(),
expiresAt = 1_900_000_000UL,
associatedData = null,
now = 101UL,
)

val filtered = store.listCredentials(issuerSchemaId = 7UL, now = 102UL)
assertEquals(1, filtered.size)
assertEquals(7UL, filtered.single().issuerSchemaId)

root.deleteRecursively()
}

@Test
fun expiredCredentialsAreFilteredOut() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

store.`init`(leafIndex = 42UL, now = 100UL)
store.storeCredential(
credential = sampleCredential(issuerSchemaId = 7UL, expiresAt = 120UL),
blindingFactor = sampleBlindingFactor(),
expiresAt = 120UL,
associatedData = null,
now = 100UL,
)
store.storeCredential(
credential = sampleCredential(issuerSchemaId = 8UL, expiresAt = 1_800_000_000UL),
blindingFactor = sampleBlindingFactor(),
expiresAt = 1_800_000_000UL,
associatedData = null,
now = 101UL,
)

val records = store.listCredentials(issuerSchemaId = null, now = 121UL)
assertEquals(1, records.size)
assertEquals(8UL, records.single().issuerSchemaId)

root.deleteRecursively()
}

@Test
fun storagePathsMatchWorldIdLayout() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

val paths = store.storagePaths()
assertEquals(root.absolutePath, paths.rootPathString())
assertTrue(paths.worldidDirPathString().endsWith("/worldid"))
assertTrue(paths.vaultDbPathString().endsWith("/worldid/account.vault.sqlite"))
assertTrue(paths.cacheDbPathString().endsWith("/worldid/account.cache.sqlite"))
assertTrue(paths.lockPathString().endsWith("/worldid/lock"))

root.deleteRecursively()
}

@Test
fun merkleCachePutRefreshesExistingEntry() {
val root = tempDirectory()
val provider = InMemoryStorageProvider(root)
val store = CredentialStore.fromProviderArc(provider)

store.`init`(leafIndex = 42UL, now = 100UL)
val firstProof = byteArrayOf(1, 2, 3)
val refreshedProof = byteArrayOf(4, 5, 6)
store.merkleCachePut(
proofBytes = firstProof,
now = 100UL,
ttlSeconds = 10UL,
)
store.merkleCachePut(
proofBytes = refreshedProof,
now = 101UL,
ttlSeconds = 60UL,
)

val cached = store.merkleCacheGet(validUntil = 120UL)
assertContentEquals(refreshedProof, cached)

root.deleteRecursively()
}

@Test
fun reopenPersistsVaultAndCache() {
val root = tempDirectory()
val keyBytes = randomKeystoreKeyBytes()
val firstStore =
CredentialStore.fromProviderArc(
InMemoryStorageProvider(root, InMemoryDeviceKeystore(keyBytes)),
)

firstStore.`init`(leafIndex = 42UL, now = 100UL)
val credentialId =
firstStore.storeCredential(
credential = sampleCredential(),
blindingFactor = sampleBlindingFactor(),
expiresAt = 1_800_000_000UL,
associatedData = null,
now = 100UL,
)
val proofBytes = byteArrayOf(9, 9, 9)
firstStore.merkleCachePut(
proofBytes = proofBytes,
now = 100UL,
ttlSeconds = 60UL,
)

val reopenedStore =
CredentialStore.fromProviderArc(
InMemoryStorageProvider(root, InMemoryDeviceKeystore(keyBytes)),
)
reopenedStore.`init`(leafIndex = 42UL, now = 101UL)

val records = reopenedStore.listCredentials(issuerSchemaId = null, now = 102UL)
assertEquals(1, records.size)
assertEquals(credentialId, records.single().credentialId)
assertContentEquals(proofBytes, reopenedStore.merkleCacheGet(validUntil = 120UL))

root.deleteRecursively()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.world.walletkit

import kotlin.test.Test
import kotlin.test.assertFails
import kotlin.test.assertTrue

class DeviceKeystoreTests {
@Test
fun sealAndOpenRoundTrip() {
val keystore = InMemoryDeviceKeystore()
val associatedData = "ad".encodeToByteArray()
val plaintext = "hello".encodeToByteArray()

val ciphertext = keystore.seal(associatedData, plaintext)
val opened = keystore.openSealed(associatedData, ciphertext)

assertTrue(opened.contentEquals(plaintext))
}

@Test
fun associatedDataMismatchFails() {
val keystore = InMemoryDeviceKeystore()
val plaintext = "secret".encodeToByteArray()
val ciphertext = keystore.seal("ad-1".encodeToByteArray(), plaintext)

assertFails {
keystore.openSealed("ad-2".encodeToByteArray(), ciphertext)
}
}

@Test
fun reopenWithSameKeyMaterialCanOpenCiphertext() {
val keyBytes = randomKeystoreKeyBytes()
val firstKeystore = InMemoryDeviceKeystore(keyBytes)
val secondKeystore = InMemoryDeviceKeystore(keyBytes)
val associatedData = "ad".encodeToByteArray()
val plaintext = "hello".encodeToByteArray()

val ciphertext = firstKeystore.seal(associatedData, plaintext)
val opened = secondKeystore.openSealed(associatedData, ciphertext)

assertTrue(opened.contentEquals(plaintext))
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.world.walletkit

import kotlin.test.Test
import kotlin.test.assertTrue
import uniffi.walletkit_core.LogLevel
import uniffi.walletkit_core.Logger
import uniffi.walletkit_core.emitLog
import uniffi.walletkit_core.initLogging
import kotlin.test.Test
import kotlin.test.assertTrue

private class CapturingLogger : Logger {
private val lock = Any()
Expand Down Expand Up @@ -33,8 +33,6 @@ class SimpleTest {
initLogging(logger, LogLevel.INFO)
emitLog(LogLevel.INFO, "bridge test")

// Log delivery happens on a dedicated background thread, so give it
// a moment to flush through the channel.
Thread.sleep(50)

val entries = logger.snapshot()
Expand Down
Loading
Loading