Added repository tests and fixed some bugs
This commit is contained in:
parent
696cd6c0a6
commit
287de9deb5
@ -85,6 +85,11 @@ dependencies {
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'org.mockito:mockito-core:2.8.9'
|
||||
testCompile 'org.hamcrest:hamcrest-library:1.3'
|
||||
testCompile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
testCompile 'com.nhaarman:mockito-kotlin-kt1.1:1.5.0'
|
||||
testCompile 'org.robolectric:robolectric:3.4.2'
|
||||
testCompile "org.robolectric:shadows-multidex:3.4-rc2"
|
||||
}
|
||||
|
||||
idea.module {
|
||||
|
@ -113,7 +113,7 @@ class AndroidInventory(private val sql: SqlHelper) : Inventory {
|
||||
where.append(" AND version = ").append(version)
|
||||
}
|
||||
if (types.isNotEmpty()) {
|
||||
where.append(" AND type IN (").append(join(*types)).append(")")
|
||||
where.append(" AND type IN (").append(types.joinToString(separator = "', '", prefix = "'", postfix = "'", transform = { it.number.toString() })).append(")")
|
||||
}
|
||||
|
||||
val db = sql.readableDatabase
|
||||
|
@ -148,8 +148,9 @@ class AndroidMessageRepository(private val sql: SqlHelper, private val context:
|
||||
}
|
||||
val result = LinkedList<UUID>()
|
||||
sql.readableDatabase.query(
|
||||
TABLE_NAME, projection,
|
||||
where, null, null, null, null
|
||||
true,
|
||||
TABLE_NAME, projection, where,
|
||||
null, null, null, null, null
|
||||
).use { c ->
|
||||
while (c.moveToNext()) {
|
||||
val uuidBytes = c.getBlob(c.getColumnIndex(COLUMN_CONVERSATION))
|
||||
@ -172,8 +173,7 @@ class AndroidMessageRepository(private val sql: SqlHelper, private val context:
|
||||
// save new parents
|
||||
var order = 0
|
||||
for (parentIV in message.parents) {
|
||||
val parent = getMessage(parentIV)
|
||||
if (parent != null) {
|
||||
getMessage(parentIV)?.let { parent ->
|
||||
mergeConversations(db, parent.conversationId, message.conversationId)
|
||||
order++
|
||||
val values = ContentValues()
|
||||
@ -198,9 +198,9 @@ class AndroidMessageRepository(private val sql: SqlHelper, private val context:
|
||||
private fun mergeConversations(db: SQLiteDatabase, source: UUID, target: UUID) {
|
||||
val values = ContentValues()
|
||||
values.put("conversation", UuidUtils.asBytes(target))
|
||||
val whereArgs = arrayOf(hex(UuidUtils.asBytes(source)))
|
||||
db.update(TABLE_NAME, values, "conversation=?", whereArgs)
|
||||
db.update(PARENTS_TABLE_NAME, values, "conversation=?", whereArgs)
|
||||
val where = "conversation=X'${hex(UuidUtils.asBytes(source))}'"
|
||||
db.update(TABLE_NAME, values, where, null)
|
||||
db.update(PARENTS_TABLE_NAME, values, where, null)
|
||||
}
|
||||
|
||||
private fun findIds(where: String): List<Long> {
|
||||
|
@ -99,6 +99,6 @@ class SqlHelper(private val ctx: Context) : SQLiteOpenHelper(ctx, DATABASE_NAME,
|
||||
private val DATABASE_VERSION = 7
|
||||
val DATABASE_NAME = "jabit.db"
|
||||
|
||||
internal fun join(vararg types: Enum<*>): String = types.joinToString(separator = "', '", prefix = "'", postfix = "'", transform = {it.name})
|
||||
internal fun join(vararg types: Enum<*>): String = types.joinToString(separator = "', '", prefix = "'", postfix = "'", transform = { it.name })
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2015 Christian Basler
|
||||
*
|
||||
* 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 ch.dissem.bitmessage.repository
|
||||
|
||||
import android.os.Build
|
||||
import ch.dissem.apps.abit.BuildConfig
|
||||
import ch.dissem.apps.abit.repository.AndroidAddressRepository
|
||||
import ch.dissem.apps.abit.repository.SqlHelper
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature.DOES_ACK
|
||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(constants = BuildConfig::class, sdk = intArrayOf(Build.VERSION_CODES.LOLLIPOP), packageName = "ch.dissem.apps.abit")
|
||||
class AndroidAddressRepositoryTest : TestBase() {
|
||||
private val CONTACT_A = "BM-2cW7cD5cDQJDNkE7ibmyTxfvGAmnPqa9Vt"
|
||||
private val CONTACT_B = "BM-2cTtkBnb4BUYDndTKun6D9PjtueP2h1bQj"
|
||||
private val CONTACT_C = "BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke"
|
||||
|
||||
private lateinit var IDENTITY_A: String
|
||||
private lateinit var IDENTITY_B: String
|
||||
|
||||
private lateinit var repo: AndroidAddressRepository
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
RuntimeEnvironment.application.deleteDatabase(SqlHelper.DATABASE_NAME)
|
||||
val sqlHelper = SqlHelper(RuntimeEnvironment.application)
|
||||
|
||||
repo = AndroidAddressRepository(sqlHelper)
|
||||
|
||||
repo.save(BitmessageAddress(CONTACT_A))
|
||||
repo.save(BitmessageAddress(CONTACT_B))
|
||||
repo.save(BitmessageAddress(CONTACT_C))
|
||||
|
||||
val identityA = BitmessageAddress(PrivateKey(false, 1, 1000, 1000, DOES_ACK))
|
||||
repo.save(identityA)
|
||||
IDENTITY_A = identityA.address
|
||||
val identityB = BitmessageAddress(PrivateKey(false, 1, 1000, 1000))
|
||||
repo.save(identityB)
|
||||
IDENTITY_B = identityB.address
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure contact can be found`() {
|
||||
val address = BitmessageAddress(CONTACT_A)
|
||||
assertEquals(4, address.version)
|
||||
assertEquals(address, repo.findContact(address.tag!!))
|
||||
assertNull(repo.findIdentity(address.tag!!))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure identity can be found`() {
|
||||
val identity = BitmessageAddress(IDENTITY_A)
|
||||
assertEquals(4, identity.version)
|
||||
assertNull(repo.findContact(identity.tag!!))
|
||||
|
||||
val storedIdentity = repo.findIdentity(identity.tag!!)
|
||||
assertEquals(identity, storedIdentity)
|
||||
assertTrue(storedIdentity!!.has(DOES_ACK))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure identities are retrieved`() {
|
||||
val identities = repo.getIdentities()
|
||||
assertEquals(2, identities.size.toLong())
|
||||
for (identity in identities) {
|
||||
assertNotNull(identity.privateKey)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure subscriptions are retrieved`() {
|
||||
addSubscription("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h")
|
||||
addSubscription("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ")
|
||||
addSubscription("BM-2D9QKN4teYRvoq2fyzpiftPh9WP9qggtzh")
|
||||
val subscriptions = repo.getSubscriptions()
|
||||
assertEquals(3, subscriptions.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure subscriptions are retrieved for given version`() {
|
||||
addSubscription("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h")
|
||||
addSubscription("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ")
|
||||
addSubscription("BM-2D9QKN4teYRvoq2fyzpiftPh9WP9qggtzh")
|
||||
|
||||
var subscriptions = repo.getSubscriptions(5)
|
||||
|
||||
assertEquals(1, subscriptions.size.toLong())
|
||||
|
||||
subscriptions = repo.getSubscriptions(4)
|
||||
assertEquals(2, subscriptions.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure contacts are retrieved`() {
|
||||
val contacts = repo.getContacts()
|
||||
assertEquals(3, contacts.size.toLong())
|
||||
for (contact in contacts) {
|
||||
assertNull(contact.privateKey)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure new address is saved`() {
|
||||
repo.save(BitmessageAddress(PrivateKey(false, 1, 1000, 1000)))
|
||||
val identities = repo.getIdentities()
|
||||
assertEquals(3, identities.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure existing address is updated`() {
|
||||
var address = repo.getAddress(CONTACT_A)
|
||||
address!!.alias = "Test-Alias"
|
||||
repo.save(address)
|
||||
address = repo.getAddress(address.address)
|
||||
assertEquals("Test-Alias", address!!.alias)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure existing keys are not deleted`() {
|
||||
val address = BitmessageAddress(IDENTITY_A)
|
||||
address.alias = "Test"
|
||||
repo.save(address)
|
||||
val identityA = repo.getAddress(IDENTITY_A)
|
||||
assertNotNull(identityA!!.pubkey)
|
||||
assertNotNull(identityA.privateKey)
|
||||
assertEquals("Test", identityA.alias)
|
||||
assertFalse(identityA.isChan)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure new chan is saved and updated`() {
|
||||
val chan = BitmessageAddress.chan(1, "test")
|
||||
repo.save(chan)
|
||||
var address = repo.getAddress(chan.address)
|
||||
assertNotNull(address)
|
||||
assertTrue(address!!.isChan)
|
||||
|
||||
address.alias = "Test"
|
||||
repo.save(address)
|
||||
|
||||
address = repo.getAddress(chan.address)
|
||||
assertNotNull(address)
|
||||
assertTrue(address!!.isChan)
|
||||
assertEquals("Test", address.alias)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure address is removed`() {
|
||||
val address = repo.getAddress(IDENTITY_A)
|
||||
repo.remove(address!!)
|
||||
assertNull(repo.getAddress(IDENTITY_A))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure address can be retrieved`() {
|
||||
val address = repo.getAddress(IDENTITY_A)
|
||||
assertNotNull(address)
|
||||
assertNotNull(address!!.privateKey)
|
||||
}
|
||||
|
||||
private fun addSubscription(address: String) {
|
||||
val subscription = BitmessageAddress(address)
|
||||
subscription.isSubscribed = true
|
||||
repo.save(subscription)
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2015 Christian Basler
|
||||
*
|
||||
* 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 ch.dissem.bitmessage.repository
|
||||
|
||||
import android.os.Build
|
||||
import ch.dissem.apps.abit.BuildConfig
|
||||
import ch.dissem.apps.abit.repository.AndroidInventory
|
||||
import ch.dissem.apps.abit.repository.SqlHelper
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||
import ch.dissem.bitmessage.entity.ObjectMessage
|
||||
import ch.dissem.bitmessage.entity.payload.GetPubkey
|
||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload
|
||||
import ch.dissem.bitmessage.entity.payload.ObjectType.GET_PUBKEY
|
||||
import ch.dissem.bitmessage.entity.payload.ObjectType.MSG
|
||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
|
||||
import ch.dissem.bitmessage.ports.Inventory
|
||||
import ch.dissem.bitmessage.utils.UnixTime.DAY
|
||||
import ch.dissem.bitmessage.utils.UnixTime.now
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
import java.util.*
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(constants = BuildConfig::class, sdk = intArrayOf(Build.VERSION_CODES.LOLLIPOP), packageName = "ch.dissem.apps.abit")
|
||||
class AndroidInventoryTest : TestBase() {
|
||||
private lateinit var inventory: Inventory
|
||||
|
||||
private lateinit var inventoryVector1: InventoryVector
|
||||
private lateinit var inventoryVector2: InventoryVector
|
||||
private lateinit var inventoryVectorIgnore: InventoryVector
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
RuntimeEnvironment.application.deleteDatabase(SqlHelper.DATABASE_NAME)
|
||||
val sqlHelper = SqlHelper(RuntimeEnvironment.application)
|
||||
|
||||
inventory = AndroidInventory(sqlHelper)
|
||||
|
||||
val object1 = getObjectMessage(1, 300, getPubkey)
|
||||
inventoryVector1 = object1.inventoryVector
|
||||
inventory.storeObject(object1)
|
||||
|
||||
val object2 = getObjectMessage(2, 300, getPubkey)
|
||||
inventoryVector2 = object2.inventoryVector
|
||||
inventory.storeObject(object2)
|
||||
|
||||
val ignore = getObjectMessage(1, -1 * DAY, getPubkey)
|
||||
inventoryVectorIgnore = ignore.inventoryVector
|
||||
inventory.storeObject(ignore)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure inventory can be retrieved`() {
|
||||
var inventoryVectors = inventory.getInventory(1)
|
||||
assertEquals(1, inventoryVectors.size.toLong())
|
||||
|
||||
inventoryVectors = inventory.getInventory(2)
|
||||
assertEquals(1, inventoryVectors.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure the IVs of missing objects are returned`() {
|
||||
val newIV = getObjectMessage(1, 200, getPubkey).inventoryVector
|
||||
val offer = LinkedList<InventoryVector>()
|
||||
offer.add(newIV)
|
||||
offer.add(inventoryVector1)
|
||||
val missing = inventory.getMissing(offer, 1, 2)
|
||||
assertEquals(1, missing.size.toLong())
|
||||
assertEquals(newIV, missing[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure single object can be retrieved`() {
|
||||
val `object` = inventory.getObject(inventoryVectorIgnore)
|
||||
assertNotNull(`object`)
|
||||
assertEquals(1, `object`!!.stream)
|
||||
assertEquals(inventoryVectorIgnore, `object`.inventoryVector)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure objects can be retrieved`() {
|
||||
var objects = inventory.getObjects(1, 4)
|
||||
assertEquals(2, objects.size.toLong())
|
||||
|
||||
objects = inventory.getObjects(1, 4, GET_PUBKEY)
|
||||
assertEquals(2, objects.size.toLong())
|
||||
|
||||
objects = inventory.getObjects(1, 4, MSG)
|
||||
assertEquals(0, objects.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure object can be stored`() {
|
||||
val `object` = getObjectMessage(5, 0, getPubkey)
|
||||
inventory.storeObject(`object`)
|
||||
|
||||
assertNotNull(inventory.getObject(`object`.inventoryVector))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure contained objects are recognized`() {
|
||||
val `object` = getObjectMessage(5, 0, getPubkey)
|
||||
|
||||
assertFalse(inventory.contains(`object`))
|
||||
|
||||
inventory.storeObject(`object`)
|
||||
|
||||
assertTrue(inventory.contains(`object`))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure inventory is cleaned up`() {
|
||||
assertNotNull(inventory.getObject(inventoryVectorIgnore))
|
||||
inventory.cleanup()
|
||||
assertNull(inventory.getObject(inventoryVectorIgnore))
|
||||
}
|
||||
|
||||
private fun getObjectMessage(stream: Long, TTL: Long, payload: ObjectPayload): ObjectMessage {
|
||||
return ObjectMessage(
|
||||
nonce = ByteArray(8),
|
||||
expiresTime = now + TTL,
|
||||
stream = stream,
|
||||
payload = payload
|
||||
)
|
||||
}
|
||||
|
||||
private val getPubkey: GetPubkey = GetPubkey(BitmessageAddress("BM-2cW7cD5cDQJDNkE7ibmyTxfvGAmnPqa9Vt"))
|
||||
}
|
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright 2015 Christian Basler
|
||||
*
|
||||
* 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 ch.dissem.bitmessage.repository
|
||||
|
||||
import android.os.Build
|
||||
import ch.dissem.apps.abit.BuildConfig
|
||||
import ch.dissem.apps.abit.repository.AndroidAddressRepository
|
||||
import ch.dissem.apps.abit.repository.AndroidMessageRepository
|
||||
import ch.dissem.apps.abit.repository.SqlHelper
|
||||
import ch.dissem.bitmessage.cryptography.sc.SpongyCryptography
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||
import ch.dissem.bitmessage.entity.ObjectMessage
|
||||
import ch.dissem.bitmessage.entity.Plaintext
|
||||
import ch.dissem.bitmessage.entity.Plaintext.Type.MSG
|
||||
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature.DOES_ACK
|
||||
import ch.dissem.bitmessage.entity.valueobject.ExtendedEncoding
|
||||
import ch.dissem.bitmessage.entity.valueobject.Label
|
||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey
|
||||
import ch.dissem.bitmessage.entity.valueobject.extended.Message
|
||||
import ch.dissem.bitmessage.ports.MessageRepository
|
||||
import ch.dissem.bitmessage.utils.UnixTime
|
||||
import org.hamcrest.BaseMatcher
|
||||
import org.hamcrest.CoreMatchers.`is`
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.Matcher
|
||||
import org.hamcrest.Matchers.*
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
import java.util.*
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(constants = BuildConfig::class, sdk = intArrayOf(Build.VERSION_CODES.LOLLIPOP), packageName = "ch.dissem.apps.abit")
|
||||
class AndroidMessageRepositoryTest : TestBase() {
|
||||
private lateinit var contactA: BitmessageAddress
|
||||
private lateinit var contactB: BitmessageAddress
|
||||
private lateinit var identity: BitmessageAddress
|
||||
|
||||
private lateinit var repo: MessageRepository
|
||||
|
||||
private lateinit var inbox: Label
|
||||
private lateinit var sent: Label
|
||||
private lateinit var drafts: Label
|
||||
private lateinit var unread: Label
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
RuntimeEnvironment.application.deleteDatabase(SqlHelper.DATABASE_NAME)
|
||||
val sqlHelper = SqlHelper(RuntimeEnvironment.application)
|
||||
|
||||
val addressRepo = AndroidAddressRepository(sqlHelper)
|
||||
repo = AndroidMessageRepository(sqlHelper, RuntimeEnvironment.application)
|
||||
mockedInternalContext(
|
||||
cryptography = SpongyCryptography(),
|
||||
addressRepository = addressRepo,
|
||||
messageRepository = repo,
|
||||
port = 12345,
|
||||
connectionTTL = 10,
|
||||
connectionLimit = 10
|
||||
)
|
||||
val tmp = BitmessageAddress(PrivateKey(false, 1, 1000, 1000, DOES_ACK))
|
||||
contactA = BitmessageAddress(tmp.address)
|
||||
contactA.pubkey = tmp.pubkey
|
||||
addressRepo.save(contactA)
|
||||
contactB = BitmessageAddress("BM-2cTtkBnb4BUYDndTKun6D9PjtueP2h1bQj")
|
||||
addressRepo.save(contactB)
|
||||
|
||||
identity = BitmessageAddress(PrivateKey(false, 1, 1000, 1000, DOES_ACK))
|
||||
addressRepo.save(identity)
|
||||
|
||||
inbox = repo.getLabels(Label.Type.INBOX)[0]
|
||||
sent = repo.getLabels(Label.Type.SENT)[0]
|
||||
drafts = repo.getLabels(Label.Type.DRAFT)[0]
|
||||
unread = repo.getLabels(Label.Type.UNREAD)[0]
|
||||
|
||||
addMessage(contactA, identity, Plaintext.Status.RECEIVED, inbox, unread)
|
||||
addMessage(identity, contactA, Plaintext.Status.DRAFT, drafts)
|
||||
addMessage(identity, contactB, Plaintext.Status.DRAFT, unread)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure labels are retrieved`() {
|
||||
val labels = repo.getLabels()
|
||||
assertEquals(7, labels.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure labels can be retrieved by type`() {
|
||||
val labels = repo.getLabels(Label.Type.INBOX)
|
||||
assertEquals(1, labels.size.toLong())
|
||||
assertEquals("Inbox", labels[0].toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure messages can be found by label`() {
|
||||
val messages = repo.findMessages(inbox)
|
||||
assertEquals(1, messages.size.toLong())
|
||||
val m = messages[0]
|
||||
assertEquals(contactA, m.from)
|
||||
assertEquals(identity, m.to)
|
||||
assertEquals(Plaintext.Status.RECEIVED, m.status)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure unread messages can be found for all labels`() {
|
||||
val unread = repo.countUnread(null)
|
||||
assertThat(unread, `is`(2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure unread messages can be found by label`() {
|
||||
val unread = repo.countUnread(inbox)
|
||||
assertThat(unread, `is`(1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure message can be retrieved by initial hash`() {
|
||||
val initialHash = ByteArray(64)
|
||||
val message = repo.findMessages(contactA)[0]
|
||||
message.initialHash = initialHash
|
||||
repo.save(message)
|
||||
val other = repo.getMessage(initialHash)
|
||||
assertThat<Plaintext>(other, `is`(message))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure ack message can be updated and retrieved`() {
|
||||
val initialHash = ByteArray(64)
|
||||
val message = repo.findMessages(contactA)[0]
|
||||
message.initialHash = initialHash
|
||||
val ackMessage = message.ackMessage
|
||||
repo.save(message)
|
||||
val other = repo.getMessage(initialHash)!!
|
||||
assertThat<Plaintext>(other, `is`(message))
|
||||
assertThat<ObjectMessage>(other.ackMessage, `is`<ObjectMessage>(ackMessage))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure messages can be found by status`() {
|
||||
val messages = repo.findMessages(Plaintext.Status.RECEIVED)
|
||||
assertEquals(1, messages.size.toLong())
|
||||
val m = messages[0]
|
||||
assertEquals(contactA, m.from)
|
||||
assertEquals(identity, m.to)
|
||||
assertEquals(Plaintext.Status.RECEIVED, m.status)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure messages can be found by status and recipient`() {
|
||||
val messages = repo.findMessages(Plaintext.Status.DRAFT, contactB)
|
||||
assertEquals(1, messages.size.toLong())
|
||||
val m = messages[0]
|
||||
assertEquals(identity, m.from)
|
||||
assertEquals(contactB, m.to)
|
||||
assertEquals(Plaintext.Status.DRAFT, m.status)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure message can be saved`() {
|
||||
val message = Plaintext.Builder(MSG)
|
||||
.IV(randomInventoryVector())
|
||||
.from(identity)
|
||||
.to(contactA)
|
||||
.message("Subject", "Message")
|
||||
.status(Plaintext.Status.DOING_PROOF_OF_WORK)
|
||||
.build()
|
||||
repo.save(message)
|
||||
|
||||
assertNotNull(message.id)
|
||||
|
||||
message.addLabels(inbox)
|
||||
repo.save(message)
|
||||
|
||||
val messages = repo.findMessages(Plaintext.Status.DOING_PROOF_OF_WORK)
|
||||
|
||||
assertEquals(1, messages.size.toLong())
|
||||
assertNotNull(messages[0].inventoryVector)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure message can be updated`() {
|
||||
var messages = repo.findMessages(Plaintext.Status.DRAFT, contactA)
|
||||
val message = messages[0]
|
||||
message.inventoryVector = randomInventoryVector()
|
||||
repo.save(message)
|
||||
|
||||
messages = repo.findMessages(Plaintext.Status.DRAFT, contactA)
|
||||
assertEquals(1, messages.size.toLong())
|
||||
assertNotNull(messages[0].inventoryVector)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure message is removed`() {
|
||||
val toRemove = repo.findMessages(Plaintext.Status.DRAFT, contactB)[0]
|
||||
var messages = repo.findMessages(Plaintext.Status.DRAFT)
|
||||
assertEquals(2, messages.size.toLong())
|
||||
repo.remove(toRemove)
|
||||
messages = repo.findMessages(Plaintext.Status.DRAFT)
|
||||
assertThat(messages, hasSize<Plaintext>(1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure unacknowledged messages are found for resend`() {
|
||||
val message = Plaintext.Builder(MSG)
|
||||
.IV(randomInventoryVector())
|
||||
.from(identity)
|
||||
.to(contactA)
|
||||
.message("Subject", "Message")
|
||||
.sent(UnixTime.now)
|
||||
.status(Plaintext.Status.SENT)
|
||||
.ttl(2)
|
||||
.build()
|
||||
message.updateNextTry()
|
||||
assertThat(message.retries, `is`(1))
|
||||
assertThat<Long>(message.nextTry, greaterThan(UnixTime.now))
|
||||
assertThat<Long>(message.nextTry, lessThanOrEqualTo(UnixTime.now + 2))
|
||||
repo.save(message)
|
||||
Thread.sleep(4100) // somewhat longer than 2*TTL
|
||||
var messagesToResend = repo.findMessagesToResend()
|
||||
assertThat(messagesToResend, hasSize<Plaintext>(1))
|
||||
|
||||
message.updateNextTry()
|
||||
assertThat(message.retries, `is`(2))
|
||||
assertThat<Long>(message.nextTry, greaterThan(UnixTime.now))
|
||||
repo.save(message)
|
||||
messagesToResend = repo.findMessagesToResend()
|
||||
assertThat(messagesToResend, empty<Plaintext>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure parents are saved`() {
|
||||
val parent = storeConversation()
|
||||
|
||||
val responses = repo.findResponses(parent)
|
||||
assertThat(responses, hasSize<Plaintext>(2))
|
||||
assertThat(responses, hasItem(hasMessage("Re: new test", "Nice!")))
|
||||
assertThat(responses, hasItem(hasMessage("Re: new test", "PS: it did work!")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure conversation can be retrieved`() {
|
||||
val root = storeConversation()
|
||||
val conversations = repo.findConversations(inbox)
|
||||
assertThat(conversations, hasSize<UUID>(2))
|
||||
assertThat(conversations, hasItem(root.conversationId))
|
||||
}
|
||||
|
||||
private fun addMessage(from: BitmessageAddress, to: BitmessageAddress, status: Plaintext.Status, vararg labels: Label): Plaintext {
|
||||
val content = Message.Builder()
|
||||
.subject("Subject")
|
||||
.body("Message")
|
||||
.build()
|
||||
return addMessage(from, to, content, status, *labels)
|
||||
}
|
||||
|
||||
private fun addMessage(from: BitmessageAddress, to: BitmessageAddress,
|
||||
content: ExtendedEncoding, status: Plaintext.Status, vararg labels: Label): Plaintext {
|
||||
val message = Plaintext.Builder(MSG)
|
||||
.IV(randomInventoryVector())
|
||||
.from(from)
|
||||
.to(to)
|
||||
.message(content)
|
||||
.status(status)
|
||||
.labels(Arrays.asList(*labels))
|
||||
.build()
|
||||
repo.save(message)
|
||||
return message
|
||||
}
|
||||
|
||||
private fun storeConversation(): Plaintext {
|
||||
val older = addMessage(identity, contactA,
|
||||
Message.Builder()
|
||||
.subject("hey there")
|
||||
.body("does it work?")
|
||||
.build(),
|
||||
Plaintext.Status.SENT, sent)
|
||||
|
||||
val root = addMessage(identity, contactA,
|
||||
Message.Builder()
|
||||
.subject("new test")
|
||||
.body("There's a new test in town!")
|
||||
.build(),
|
||||
Plaintext.Status.SENT, sent)
|
||||
|
||||
addMessage(contactA, identity,
|
||||
Message.Builder()
|
||||
.subject("Re: new test")
|
||||
.body("Nice!")
|
||||
.addParent(root)
|
||||
.build(),
|
||||
Plaintext.Status.RECEIVED, inbox)
|
||||
|
||||
addMessage(contactA, identity,
|
||||
Message.Builder()
|
||||
.subject("Re: new test")
|
||||
.body("PS: it did work!")
|
||||
.addParent(root)
|
||||
.addParent(older)
|
||||
.build(),
|
||||
Plaintext.Status.RECEIVED, inbox)
|
||||
|
||||
return repo.getMessage(root.id!!)
|
||||
}
|
||||
|
||||
private fun hasMessage(subject: String?, body: String?): Matcher<Plaintext> {
|
||||
return object : BaseMatcher<Plaintext>() {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("Subject: ").appendText(subject)
|
||||
description.appendText(", ")
|
||||
description.appendText("Body: ").appendText(body)
|
||||
}
|
||||
|
||||
override fun matches(item: Any): Boolean {
|
||||
if (item is Plaintext) {
|
||||
if (subject != null && subject != item.subject) {
|
||||
return false
|
||||
}
|
||||
if (body != null && body != item.text) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2015 Christian Basler
|
||||
*
|
||||
* 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 ch.dissem.bitmessage.repository
|
||||
|
||||
import android.os.Build
|
||||
import ch.dissem.apps.abit.BuildConfig
|
||||
import ch.dissem.apps.abit.repository.AndroidNodeRegistry
|
||||
import ch.dissem.apps.abit.repository.SqlHelper
|
||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress
|
||||
import ch.dissem.bitmessage.ports.NodeRegistry
|
||||
import ch.dissem.bitmessage.utils.UnixTime.now
|
||||
import org.hamcrest.Matchers.empty
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Please note that some tests fail if there is no internet connection,
|
||||
* as the initial nodes' IP addresses are determined by DNS lookup.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(constants = BuildConfig::class, sdk = intArrayOf(Build.VERSION_CODES.LOLLIPOP), packageName = "ch.dissem.apps.abit")
|
||||
class AndroidNodeRegistryTest : TestBase() {
|
||||
private lateinit var registry: NodeRegistry
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
RuntimeEnvironment.application.deleteDatabase(SqlHelper.DATABASE_NAME)
|
||||
val sqlHelper = SqlHelper(RuntimeEnvironment.application)
|
||||
|
||||
registry = AndroidNodeRegistry(sqlHelper)
|
||||
|
||||
registry.offerAddresses(Arrays.asList(
|
||||
createAddress(1, 8444, 1, now),
|
||||
createAddress(2, 8444, 1, now),
|
||||
createAddress(3, 8444, 1, now),
|
||||
createAddress(4, 8444, 2, now)
|
||||
))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure getKnownNodes() without streams yields empty`() {
|
||||
assertThat(registry.getKnownAddresses(10), empty<NetworkAddress>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure predefined node is returned when database is empty`() {
|
||||
RuntimeEnvironment.application.deleteDatabase(SqlHelper.DATABASE_NAME)
|
||||
|
||||
val sqlHelper = SqlHelper(RuntimeEnvironment.application)
|
||||
registry = AndroidNodeRegistry(sqlHelper)
|
||||
|
||||
val knownAddresses = registry.getKnownAddresses(2, 1)
|
||||
assertEquals(1, knownAddresses.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure known addresses are retrieved`() {
|
||||
var knownAddresses = registry.getKnownAddresses(2, 1)
|
||||
assertEquals(2, knownAddresses.size.toLong())
|
||||
|
||||
knownAddresses = registry.getKnownAddresses(1000, 1)
|
||||
assertEquals(3, knownAddresses.size.toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure offered addresses are added`() {
|
||||
registry.offerAddresses(Arrays.asList(
|
||||
createAddress(1, 8444, 1, now),
|
||||
createAddress(10, 8444, 1, now),
|
||||
createAddress(11, 8444, 1, now)
|
||||
))
|
||||
|
||||
var knownAddresses = registry.getKnownAddresses(1000, 1)
|
||||
assertEquals(5, knownAddresses.size.toLong())
|
||||
|
||||
registry.offerAddresses(listOf(createAddress(1, 8445, 1, now)))
|
||||
|
||||
knownAddresses = registry.getKnownAddresses(1000, 1)
|
||||
assertEquals(6, knownAddresses.size.toLong())
|
||||
}
|
||||
|
||||
private fun createAddress(lastByte: Int, port: Int, stream: Long, time: Long): NetworkAddress {
|
||||
return NetworkAddress.Builder()
|
||||
.ipv6(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, lastByte)
|
||||
.port(port)
|
||||
.stream(stream)
|
||||
.time(time)
|
||||
.build()
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2017 Christian Basler
|
||||
*
|
||||
* 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 ch.dissem.bitmessage.repository
|
||||
|
||||
import android.os.Build.VERSION_CODES.LOLLIPOP
|
||||
import ch.dissem.apps.abit.BuildConfig
|
||||
import ch.dissem.apps.abit.repository.AndroidAddressRepository
|
||||
import ch.dissem.apps.abit.repository.AndroidMessageRepository
|
||||
import ch.dissem.apps.abit.repository.AndroidProofOfWorkRepository
|
||||
import ch.dissem.apps.abit.repository.SqlHelper
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||
import ch.dissem.bitmessage.entity.ObjectMessage
|
||||
import ch.dissem.bitmessage.entity.Plaintext
|
||||
import ch.dissem.bitmessage.entity.payload.GenericPayload
|
||||
import ch.dissem.bitmessage.entity.payload.GetPubkey
|
||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload
|
||||
import ch.dissem.bitmessage.entity.payload.Pubkey
|
||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey
|
||||
import ch.dissem.bitmessage.ports.AddressRepository
|
||||
import ch.dissem.bitmessage.ports.MessageRepository
|
||||
import ch.dissem.bitmessage.ports.ProofOfWorkRepository
|
||||
import ch.dissem.bitmessage.utils.Singleton.cryptography
|
||||
import ch.dissem.bitmessage.utils.UnixTime
|
||||
import org.hamcrest.CoreMatchers.*
|
||||
import org.junit.Assert.assertThat
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* @author Christian Basler
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(constants = BuildConfig::class, sdk = intArrayOf(LOLLIPOP), packageName = "ch.dissem.apps.abit")
|
||||
class AndroidProofOfWorkRepositoryTest : TestBase() {
|
||||
private lateinit var repo: ProofOfWorkRepository
|
||||
private lateinit var addressRepo: AddressRepository
|
||||
private lateinit var messageRepo: MessageRepository
|
||||
|
||||
private var initialHash1: ByteArray by Delegates.notNull<ByteArray>()
|
||||
private var initialHash2: ByteArray by Delegates.notNull<ByteArray>()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
RuntimeEnvironment.application.deleteDatabase(SqlHelper.DATABASE_NAME)
|
||||
val sqlHelper = SqlHelper(RuntimeEnvironment.application)
|
||||
|
||||
addressRepo = AndroidAddressRepository(sqlHelper)
|
||||
messageRepo = AndroidMessageRepository(sqlHelper, RuntimeEnvironment.application)
|
||||
repo = AndroidProofOfWorkRepository(sqlHelper)
|
||||
mockedInternalContext(
|
||||
addressRepository = addressRepo,
|
||||
messageRepository = messageRepo,
|
||||
proofOfWorkRepository = repo,
|
||||
cryptography = cryptography()
|
||||
)
|
||||
|
||||
repo.putObject(ObjectMessage.Builder()
|
||||
.payload(GetPubkey(BitmessageAddress("BM-2DAjcCFrqFrp88FUxExhJ9kPqHdunQmiyn"))).build(),
|
||||
1000, 1000)
|
||||
initialHash1 = repo.getItems()[0]
|
||||
|
||||
val sender = loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")
|
||||
val recipient = loadContact()
|
||||
addressRepo.save(sender)
|
||||
addressRepo.save(recipient)
|
||||
val plaintext = Plaintext.Builder(Plaintext.Type.MSG)
|
||||
.ackData(cryptography().randomBytes(32))
|
||||
.from(sender)
|
||||
.to(recipient)
|
||||
.message("Subject", "Message")
|
||||
.status(Plaintext.Status.DOING_PROOF_OF_WORK)
|
||||
.build()
|
||||
messageRepo.save(plaintext)
|
||||
initialHash2 = cryptography().getInitialHash(plaintext.ackMessage!!)
|
||||
repo.putObject(ProofOfWorkRepository.Item(
|
||||
plaintext.ackMessage!!,
|
||||
1000, 1000,
|
||||
UnixTime.now + 10 * UnixTime.MINUTE,
|
||||
plaintext
|
||||
))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure object is stored`() {
|
||||
val sizeBefore = repo.getItems().size
|
||||
repo.putObject(ObjectMessage.Builder()
|
||||
.payload(GetPubkey(BitmessageAddress("BM-2D9U2hv3YBMHM1zERP32anKfVKohyPN9x2"))).build(),
|
||||
1000, 1000)
|
||||
assertThat(repo.getItems().size, `is`(sizeBefore + 1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure ack objects are stored`() {
|
||||
val sizeBefore = repo.getItems().size
|
||||
val sender = loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")
|
||||
val recipient = loadContact()
|
||||
addressRepo.save(sender)
|
||||
addressRepo.save(recipient)
|
||||
val plaintext = Plaintext.Builder(Plaintext.Type.MSG)
|
||||
.ackData(cryptography().randomBytes(32))
|
||||
.from(sender)
|
||||
.to(recipient)
|
||||
.message("Subject", "Message")
|
||||
.status(Plaintext.Status.DOING_PROOF_OF_WORK)
|
||||
.build()
|
||||
messageRepo.save(plaintext)
|
||||
repo.putObject(ProofOfWorkRepository.Item(
|
||||
plaintext.ackMessage!!,
|
||||
1000, 1000,
|
||||
UnixTime.now + 10 * UnixTime.MINUTE,
|
||||
plaintext
|
||||
))
|
||||
assertThat(repo.getItems().size, `is`(sizeBefore + 1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure item can be retrieved`() {
|
||||
val item = repo.getItem(initialHash1)
|
||||
assertThat(item, notNullValue())
|
||||
assertThat<ObjectPayload>(item.objectMessage.payload, instanceOf<ObjectPayload>(GetPubkey::class.java))
|
||||
assertThat(item.nonceTrialsPerByte, `is`(1000L))
|
||||
assertThat(item.extraBytes, `is`(1000L))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure ack item can be retrieved`() {
|
||||
val item = repo.getItem(initialHash2)
|
||||
assertThat(item, notNullValue())
|
||||
assertThat<ObjectPayload>(item.objectMessage.payload, instanceOf<ObjectPayload>(GenericPayload::class.java))
|
||||
assertThat(item.nonceTrialsPerByte, `is`(1000L))
|
||||
assertThat(item.extraBytes, `is`(1000L))
|
||||
assertThat(item.expirationTime, not<Number>(0))
|
||||
assertThat(item.message, notNullValue())
|
||||
assertThat<PrivateKey>(item.message?.from?.privateKey, notNullValue())
|
||||
assertThat<Pubkey>(item.message?.to?.pubkey, notNullValue())
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun `ensure retrieving nonexisting item causes exception`() {
|
||||
repo.getItem(ByteArray(0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure item can be deleted`() {
|
||||
repo.removeObject(initialHash1)
|
||||
repo.removeObject(initialHash2)
|
||||
assertTrue(repo.getItems().isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure deletion of nonexisting item is handled silently`() {
|
||||
repo.removeObject(ByteArray(0))
|
||||
}
|
||||
}
|
127
app/src/test/java/ch/dissem/bitmessage/repository/TestBase.kt
Normal file
127
app/src/test/java/ch/dissem/bitmessage/repository/TestBase.kt
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2017 Christian Basler
|
||||
*
|
||||
* 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 ch.dissem.bitmessage.repository
|
||||
|
||||
import ch.dissem.bitmessage.BitmessageContext
|
||||
import ch.dissem.bitmessage.InternalContext
|
||||
import ch.dissem.bitmessage.cryptography.sc.SpongyCryptography
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||
import ch.dissem.bitmessage.entity.ObjectMessage
|
||||
import ch.dissem.bitmessage.entity.payload.V4Pubkey
|
||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
|
||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey
|
||||
import ch.dissem.bitmessage.factory.Factory
|
||||
import ch.dissem.bitmessage.ports.*
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import com.nhaarman.mockito_kotlin.spy
|
||||
import org.junit.Assert
|
||||
import org.junit.BeforeClass
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.*
|
||||
|
||||
open class TestBase {
|
||||
companion object {
|
||||
@BeforeClass
|
||||
@JvmStatic
|
||||
fun init() {
|
||||
mockedInternalContext(
|
||||
cryptography = SpongyCryptography(),
|
||||
proofOfWorkEngine = MultiThreadedPOWEngine()
|
||||
)
|
||||
}
|
||||
|
||||
fun mockedInternalContext(
|
||||
cryptography: Cryptography = mock {},
|
||||
inventory: Inventory = mock {},
|
||||
nodeRegistry: NodeRegistry = mock {},
|
||||
networkHandler: NetworkHandler = mock {},
|
||||
addressRepository: AddressRepository = mock {},
|
||||
messageRepository: MessageRepository = mock {},
|
||||
proofOfWorkRepository: ProofOfWorkRepository = mock {},
|
||||
proofOfWorkEngine: ProofOfWorkEngine = mock {},
|
||||
customCommandHandler: CustomCommandHandler = mock {},
|
||||
listener: BitmessageContext.Listener = mock {},
|
||||
labeler: Labeler = mock {},
|
||||
port: Int = 0,
|
||||
connectionTTL: Long = 0,
|
||||
connectionLimit: Int = 0
|
||||
): InternalContext {
|
||||
return spy(InternalContext(
|
||||
cryptography,
|
||||
inventory,
|
||||
nodeRegistry,
|
||||
networkHandler,
|
||||
addressRepository,
|
||||
messageRepository,
|
||||
proofOfWorkRepository,
|
||||
proofOfWorkEngine,
|
||||
customCommandHandler,
|
||||
listener,
|
||||
labeler,
|
||||
"/Jabit:TEST/",
|
||||
port,
|
||||
connectionTTL,
|
||||
connectionLimit
|
||||
))
|
||||
}
|
||||
|
||||
fun randomInventoryVector(): InventoryVector {
|
||||
val bytes = ByteArray(32)
|
||||
RANDOM.nextBytes(bytes)
|
||||
return InventoryVector(bytes)
|
||||
}
|
||||
|
||||
fun getResource(resourceName: String) =
|
||||
TestBase::class.java.classLoader.getResourceAsStream(resourceName)
|
||||
|
||||
fun loadObjectMessage(version: Int, resourceName: String): ObjectMessage {
|
||||
val data = getBytes(resourceName)
|
||||
val `in` = ByteArrayInputStream(data)
|
||||
return Factory.getObjectMessage(version, `in`, data.size) ?: throw NoSuchElementException("error loading object message")
|
||||
}
|
||||
|
||||
fun getBytes(resourceName: String): ByteArray {
|
||||
val `in` = getResource(resourceName)
|
||||
val out = ByteArrayOutputStream()
|
||||
val buffer = ByteArray(1024)
|
||||
var len = `in`.read(buffer)
|
||||
while (len != -1) {
|
||||
out.write(buffer, 0, len)
|
||||
len = `in`.read(buffer)
|
||||
}
|
||||
return out.toByteArray()
|
||||
}
|
||||
|
||||
fun loadIdentity(address: String): BitmessageAddress {
|
||||
val privateKey = PrivateKey.read(getResource(address + ".privkey"))
|
||||
val identity = BitmessageAddress(privateKey)
|
||||
Assert.assertEquals(address, identity.address)
|
||||
return identity
|
||||
}
|
||||
|
||||
fun loadContact(): BitmessageAddress {
|
||||
val address = BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h")
|
||||
val objectMessage = loadObjectMessage(3, "V4Pubkey.payload")
|
||||
objectMessage.decrypt(address.publicDecryptionKey)
|
||||
address.pubkey = objectMessage.payload as V4Pubkey
|
||||
return address
|
||||
}
|
||||
|
||||
private val RANDOM = Random()
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/src/test/resources/V4Pubkey.payload
Normal file
BIN
app/src/test/resources/V4Pubkey.payload
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
mock-maker-inline
|
Loading…
Reference in New Issue
Block a user