From aa011cfb4c9f8c599d7128a66d8dac77a02d9717 Mon Sep 17 00:00:00 2001 From: Bohdan Vanieiev Date: Thu, 16 Dec 2021 16:25:02 +0200 Subject: [PATCH 01/12] Fix --- README.md | 16 ++ build.gradle.kts | 16 +- src/main/kotlin/nodecore/api/FaucetApi.kt | 20 --- src/main/kotlin/nodecore/api/NodeCoreApi.kt | 157 ------------------ .../kotlin/nodecore/api/SyncNodeCoreApi.kt | 35 ---- .../wrapper/nodecore/Entities.kt | 83 --------- .../testframework/BaseIntegrationTest.kt | 155 ++++++++--------- .../testframework/BaseJsonRpcApi.kt | 13 +- .../testframework/BtcPluginInterface.kt | 2 +- .../{nodecore => }/testframework/Exec.kt | 2 +- .../testframework/ProcessManager.kt | 2 +- .../testframework/StdStreamLogger.kt | 2 +- .../{nodecore => }/testframework/Util.kt | 12 +- .../api => testframework/util}/HttpClient.kt | 19 ++- .../api => testframework/util}/Rpc.kt | 3 +- .../testframework/wrapper/apm/ApmHttpApi.kt | 2 +- .../testframework/wrapper/apm/Entities.kt | 2 +- .../testframework/wrapper/apm/TestAPM.kt | 12 +- .../wrapper/btcsq/BtcsqApi.kt} | 6 +- .../wrapper/btcsq/BtcsqSettings.kt} | 4 +- .../wrapper/btcsq}/Entities.kt | 2 +- .../wrapper/btcsq/TestBtcsq.kt} | 23 +-- .../wrapper/nodecore/Entities.kt} | 90 ++++++---- .../wrapper/nodecore/MiniNode.kt | 6 +- .../wrapper/nodecore/NodeHttpApi.kt | 12 +- .../wrapper/nodecore/TestNodecore.kt | 21 ++- src/test/kotlin/functional/ExampleApmTest.kt | 6 +- src/test/kotlin/functional/ExampleTest.kt | 8 +- src/test/kotlin/functional/LedgerProofTest.kt | 4 +- src/test/kotlin/functional/PopMiningTest.kt | 20 +-- src/test/kotlin/functional/TxLimitTest.kt | 16 +- .../nodecore/NodeCoreMempoolSyncTest.kt | 8 +- 32 files changed, 277 insertions(+), 502 deletions(-) create mode 100644 README.md delete mode 100644 src/main/kotlin/nodecore/api/FaucetApi.kt delete mode 100644 src/main/kotlin/nodecore/api/NodeCoreApi.kt delete mode 100644 src/main/kotlin/nodecore/api/SyncNodeCoreApi.kt delete mode 100644 src/main/kotlin/nodecore/testframework/wrapper/nodecore/Entities.kt rename src/main/kotlin/{nodecore => }/testframework/BaseIntegrationTest.kt (54%) rename src/main/kotlin/{nodecore => }/testframework/BaseJsonRpcApi.kt (75%) rename src/main/kotlin/{nodecore => }/testframework/BtcPluginInterface.kt (88%) rename src/main/kotlin/{nodecore => }/testframework/Exec.kt (97%) rename src/main/kotlin/{nodecore => }/testframework/ProcessManager.kt (98%) rename src/main/kotlin/{nodecore => }/testframework/StdStreamLogger.kt (97%) rename src/main/kotlin/{nodecore => }/testframework/Util.kt (92%) rename src/main/kotlin/{nodecore/api => testframework/util}/HttpClient.kt (71%) rename src/main/kotlin/{nodecore/api => testframework/util}/Rpc.kt (95%) rename src/main/kotlin/{nodecore => }/testframework/wrapper/apm/ApmHttpApi.kt (97%) rename src/main/kotlin/{nodecore => }/testframework/wrapper/apm/Entities.kt (97%) rename src/main/kotlin/{nodecore => }/testframework/wrapper/apm/TestAPM.kt (92%) rename src/main/kotlin/{nodecore/testframework/wrapper/vbtc/VBTCApi.kt => testframework/wrapper/btcsq/BtcsqApi.kt} (89%) rename src/main/kotlin/{nodecore/testframework/wrapper/vbtc/VBtcSettings.kt => testframework/wrapper/btcsq/BtcsqSettings.kt} (84%) rename src/main/kotlin/{nodecore/testframework/wrapper/vbtc => testframework/wrapper/btcsq}/Entities.kt (96%) rename src/main/kotlin/{nodecore/testframework/wrapper/vbtc/TestVBTC.kt => testframework/wrapper/btcsq/TestBtcsq.kt} (87%) rename src/main/kotlin/{nodecore/api/Proto.kt => testframework/wrapper/nodecore/Entities.kt} (88%) rename src/main/kotlin/{nodecore => }/testframework/wrapper/nodecore/MiniNode.kt (98%) rename src/main/kotlin/{nodecore => }/testframework/wrapper/nodecore/NodeHttpApi.kt (82%) rename src/main/kotlin/{nodecore => }/testframework/wrapper/nodecore/TestNodecore.kt (89%) diff --git a/README.md b/README.md new file mode 100644 index 0000000..58e7c84 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# pop-integration-int + +This repository contains e2e test framework for POP protocol. + +To run all tests: `./gradlew build test` + +Each test uses testcontainers to start docker images of NodeCore, APM, BTCSQ (and other stuff) to test everything end-to-end. + +## Development guide + +Each service (APM/NC/BTCSQ) is organized into "wrapper" - [./src/main/kotlin/testframework/wrapper](./src/main/kotlin/testframework/wrapper). +Each wrapper is expected to provide all necessary tools to start / stop and control wrapped tool via API (HTTP/GRPC...). + +Every test defines a "topology" - a set of "wrappers" to run, their relations (for example, APM should be added after NC and BTCSQ). + +[ExampleTest.kt](./src/test/kotlin/functional/ExampleTest.kt) \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index d411479..25f5e29 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,32 +14,32 @@ repositories { maven("https://jitpack.io") } -val kotestVersion = "4.6.3" +val kotestVersion = "5.0.1" val coroutinesVersion = "1.5.2-native-mt" -val log4jVersion= "2.14.1" -val ktorVersion = "1.6.4" +val log4jVersion= "2.16.0" +val ktorVersion = "1.6.6" dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion") - implementation("io.github.microutils:kotlin-logging:2.0.11") + implementation("io.github.microutils:kotlin-logging:2.1.16") implementation("org.apache.logging.log4j:log4j-api:$log4jVersion") implementation("org.apache.logging.log4j:log4j-core:$log4jVersion") implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion") implementation("com.fasterxml.jackson.core:jackson-databind:2.13.0") - implementation("com.google.code.gson:gson:2.8.8") + implementation("com.google.code.gson:gson:2.8.9") implementation("io.ktor:ktor-client:$ktorVersion") implementation("io.ktor:ktor-client-core-jvm:$ktorVersion") implementation("io.ktor:ktor-client-cio:$ktorVersion") implementation("io.ktor:ktor-client-auth:$ktorVersion") implementation("io.ktor:ktor-client-gson:$ktorVersion") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.3.0") - implementation("org.testcontainers:testcontainers:1.16.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.3.1") + implementation("org.testcontainers:testcontainers:1.16.2") implementation("com.google.guava:guava:31.0.1-jre") implementation("com.github.veriblock.nodecore:nodecore-grpc:v0.4.13-rc.2") implementation("com.github.veriblock.nodecore:veriblock-extensions:v0.4.13-rc.2") implementation("com.github.veriblock.nodecore:vpm-mock:v0.4.13-rc.2") - implementation("io.github.microutils:kotlin-logging:2.0.11") + implementation("io.github.microutils:kotlin-logging:2.1.16") testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion") testImplementation("io.kotest:kotest-assertions-core:$kotestVersion") testImplementation(kotlin("test")) diff --git a/src/main/kotlin/nodecore/api/FaucetApi.kt b/src/main/kotlin/nodecore/api/FaucetApi.kt deleted file mode 100644 index 618add8..0000000 --- a/src/main/kotlin/nodecore/api/FaucetApi.kt +++ /dev/null @@ -1,20 +0,0 @@ -package nodecore.api - -import io.ktor.client.request.get -import io.ktor.client.request.parameter - -//private val apiConfig = config.extract("faucetApi") -// ?: HttpApiConfig("http://95.217.67.120/alt-integration/api/v1.0/faucet") - -private val httpClient = createHttpClient() - -object FaucetApi { - suspend fun getCoins(address: String): FaucetResponse = httpClient.get("http://95.217.67.120/alt-integration/api/v1.0/faucet") { // TODO: config URL - parameter("address", address) - }.handle() -} - -data class FaucetResponse( - val success: Boolean, - val txIds: List -) diff --git a/src/main/kotlin/nodecore/api/NodeCoreApi.kt b/src/main/kotlin/nodecore/api/NodeCoreApi.kt deleted file mode 100644 index 07e3475..0000000 --- a/src/main/kotlin/nodecore/api/NodeCoreApi.kt +++ /dev/null @@ -1,157 +0,0 @@ -package nodecore.api - -import io.ktor.client.request.post -import kotlinx.coroutines.delay -import org.slf4j.LoggerFactory -import java.util.Collections.EMPTY_MAP -import kotlin.math.absoluteValue -import kotlin.math.roundToInt - -//private val apiConfig = config.extract("nodeCoreApi") -// ?: HttpApiConfig("http://localhost:10600/api") - -private val httpClient = createHttpClient() - -private val logger = LoggerFactory.getLogger("NodeCoreApi") - -object NodeCoreApi { - suspend fun getInfo(): VbkInfo = performRequest( - method = "getinfo" - ) - - suspend fun getStateInfo(): StateInfo = performRequest( - method = "getstateinfo" - ) - - suspend fun getLastBlock(): BlockHeaderContainer = performRequest( - method = "getlastblock" - ) - - suspend fun getLastBitcoinBlockAtVeriBlockBlock(vbkHash: String): BtcBlockData = performRequest( - method = "getlastbitcoinblockatveriblockblock", - params = mapOf( - "vbkBlockHash" to vbkHash - ) - ) - - suspend fun getNewAddress(count: Int = 1): GetNewAddressReply = performRequest( - method = "getnewaddress", - params = mapOf( - "count" to count - ) - ) - - suspend fun getBlocksByHeight(searchLength: Int, heights: List): GetBlocksReply = performRequest( - method = "getblocks", - params = mapOf( - "searchLength" to searchLength, - "filters" to heights.map { - mapOf("index" to it) - } - ) - ) - - suspend fun getBlocksByHash(searchLength: Int, hashes: List): GetBlocksReply = performRequest( - method = "getblocks", - params = mapOf( - "searchLength" to searchLength, - "filters" to listOf(hashes.map { - mapOf("hash" to it) - }) - ) - ) - - suspend fun getTransaction(txId: String): GetTransactionsReply = performRequest( - method = "gettransactions", - params = mapOf( - "searchLength" to 0, - "ids" to listOf(txId) - ) - ) - - suspend fun sendCoins(sourceAddress: String, amounts: List): SendCoinsReply = performRequest( - method = "sendcoins", - params = mapOf( - "sourceAddress" to sourceAddress, - "amounts" to amounts - ) - ) - - suspend fun getPendingTransactions(): GetPendingTransactionsReply = performRequest( - method = "getpendingtransactions" - ) - - suspend fun checkConnection() { - while (true) { - try { - getInfo() - break - } catch (e: Exception) { - logger.warn("NodeCore not available yet, trying again in 10s...") - delay(10_000L) - } - } - } - - suspend fun checkSyncStatus() { - var previousState = 0 - var previousSpeed = 0.0 - while (true) { - try { - val stateInfo = getStateInfo() - val syncState = stateInfo.networkHeight - stateInfo.localBlockchainHeight - if (syncState.absoluteValue >= 5) { - val syncSummary = if (previousState > 0) { - val increment = previousState - syncState - val speed = increment / 5.0 - val fixedSpeed = if (previousSpeed > 0) { - (speed + previousSpeed) / 2.0 - } else { - speed - } - previousSpeed = fixedSpeed - val remainingTimeSeconds = (syncState / fixedSpeed).roundToInt() - val remainingTime = if (remainingTimeSeconds >= 60) { - "${remainingTimeSeconds / 60}m ${remainingTimeSeconds % 60}s" - } else { - "${remainingTimeSeconds}s" - } - " Download Speed=${String.format("%.2f", fixedSpeed)}Bk/s Remaining Time=$remainingTime" - } else { - "" - } - logger.warn("Waiting for NodeCore to synchronize. $syncState blocks left (LocalHeight=${stateInfo.localBlockchainHeight} NetworkHeight=${stateInfo.networkHeight}$syncSummary)") - previousState = syncState - - delay(5_000L) - continue - } - - logger.info("NodeCore is synchronized.. continuing.") - break - } catch (e: Exception) { - logger.warn("NodeCore not available, trying again in 5s...") - delay(5_000L) - } - } - } - - suspend fun waitUntilBlock(blockHeight: Int) { - while (true) { - val info = getInfo() - val tip = info.lastBlock.number - logger.info("Current Tip: $tip") - if (tip >= blockHeight) { - return - } - delay(30_0000) - } - } -} - -private suspend inline fun performRequest( - method: String, - params: Any? = EMPTY_MAP -): T = httpClient.post("http://localhost:10600/api") { // TODO: config URL - body = JsonRpcRequestBody(method, params).toJson() -}.handle() diff --git a/src/main/kotlin/nodecore/api/SyncNodeCoreApi.kt b/src/main/kotlin/nodecore/api/SyncNodeCoreApi.kt deleted file mode 100644 index 943b9dc..0000000 --- a/src/main/kotlin/nodecore/api/SyncNodeCoreApi.kt +++ /dev/null @@ -1,35 +0,0 @@ -package nodecore.api - -import io.ktor.client.request.post -import kotlinx.coroutines.runBlocking -//import nodecore.config - -//private val apiConfig = config.extract("nodeCoreApi") -// ?: HttpApiConfig("http://localhost:10600/api") - -private val httpClient = createHttpClient() - -object SyncNodeCoreApi { - fun getInfo(): VbkInfo = runBlocking { - httpClient.post("http://localhost:10600/api") { // TODO: config URL - body = JsonRpcRequestBody("getinfo").toJson() - }.handle() - } - - fun getLastBlock(): BlockHeaderContainer = runBlocking { - httpClient.post("http://localhost:10600/api") { // TODO: config URL - body = JsonRpcRequestBody("getlastblock").toJson() - }.handle() - } - - fun getLastBitcoinBlockAtVeriBlockBlock(vbkHash: String): BtcBlockData = runBlocking { - httpClient.post("http://localhost:10600/api") { // TODO: config URL - body = JsonRpcRequestBody( - "getlastbitcoinblockatveriblockblock", - mapOf( - "vbkBlockHash" to vbkHash - ) - ).toJson() - }.handle() - } -} diff --git a/src/main/kotlin/nodecore/testframework/wrapper/nodecore/Entities.kt b/src/main/kotlin/nodecore/testframework/wrapper/nodecore/Entities.kt deleted file mode 100644 index 320854b..0000000 --- a/src/main/kotlin/nodecore/testframework/wrapper/nodecore/Entities.kt +++ /dev/null @@ -1,83 +0,0 @@ -package nodecore.testframework.wrapper.nodecore - -import kotlinx.serialization.Serializable -import nodecore.api.VbkBlockData - -@Serializable -data class Result( - val error: Boolean, - val code: String, - val message: String, - val details: String -) { - override fun toString(): String { - return "[$code] $message: $details" - } -} - -@Serializable -data class ProtocolReply( - val success: Boolean, - val results: List -) - -@Serializable -data class VbkInfoAddress ( - val address: String -) - -@Serializable -data class VbkInfo( - val lastBlock: VbkBlockData, - val defaultAddress: VbkInfoAddress -) - -@Serializable -data class NodeRequest( - val endpoint: List -) - -@Serializable -data class Endpoint( - val address: String, - val port: Int -) - -@Serializable -data class GenerateBlocksReply( - val result: Result?, - val hash: List -) - -@Serializable -data class BlockHeader( - val header: String, - val hash: String -) - -@Serializable -data class GetLastBlockReply( - val header: BlockHeader -) - -@Serializable -data class GetLastBitcoinBlockReply( - val header: String, - val height: Int, - val hash: String -) - -@Serializable -data class BitcoinBlockHeader( - val header: String -) - -@Serializable -data class SubmitPopRequest( - val endorsedBlockHeader: String, - val bitcoinTransaction: String, - val bitcoinMerklePathToRoot: String, - val bitcoinBlockHeaderOfProof: BitcoinBlockHeader, - val contextBitcoinBlockHeaders: List, - val address: String -) diff --git a/src/main/kotlin/nodecore/testframework/BaseIntegrationTest.kt b/src/main/kotlin/testframework/BaseIntegrationTest.kt similarity index 54% rename from src/main/kotlin/nodecore/testframework/BaseIntegrationTest.kt rename to src/main/kotlin/testframework/BaseIntegrationTest.kt index 3989c87..ea0121a 100644 --- a/src/main/kotlin/nodecore/testframework/BaseIntegrationTest.kt +++ b/src/main/kotlin/testframework/BaseIntegrationTest.kt @@ -1,15 +1,18 @@ -package nodecore.testframework +package testframework +import java.io.File import kotlinx.coroutines.* -import nodecore.testframework.wrapper.apm.ApmSettings -import nodecore.testframework.wrapper.apm.TestAPM -import nodecore.testframework.wrapper.nodecore.NodecoreSettings -import nodecore.testframework.wrapper.nodecore.TestNodecore -import nodecore.testframework.wrapper.vbtc.TestVBTC -import nodecore.testframework.wrapper.vbtc.VBtcSettings -import org.junit.ComparisonFailure +import testframework.wrapper.apm.ApmSettings +import testframework.wrapper.apm.TestAPM +import testframework.wrapper.btcsq.BtcsqSettings +import testframework.wrapper.nodecore.NodecoreSettings +import testframework.wrapper.nodecore.TestNodecore import org.slf4j.LoggerFactory -import java.io.File +import testframework.wrapper.btcsq.TestBtcsq + +val nodecoreVersion = System.getenv("INT_NODECORE_VERSION") ?: "0.4.13-rc.11" +val apmVersion = System.getenv("INT_APM_VERSION") ?: "0.4.13-rc.11" +val btcsqVersion = System.getenv("INT_BTCSQ_VERSION") ?: "master-47363b0" enum class TestStatus(val state: String) { PASSED("PASSED"), @@ -24,7 +27,7 @@ abstract class BaseIntegrationTest { // all instances of Altchain POP miners val apms = ArrayList() /* empty by default */ val nodecores = ArrayList() /* empty by default */ - val vbtcs = ArrayList() /* empty by default */ + val btcsqs = ArrayList() /* empty by default */ val logger = LoggerFactory.getLogger("BaseIntegrationTest") var baseNodecoreRpcPort = (23300) var baseNodecoreP2pPort = (23200) @@ -35,8 +38,8 @@ abstract class BaseIntegrationTest { var baseBtcRpcPort = (25200) var baseBtcZmqPort = (25300) val baseDir: File = createTempDir( - prefix = "veriblock_${System.currentTimeMillis()}_", - ) + prefix = "veriblock_${System.currentTimeMillis()}_", + ) var status: TestStatus = TestStatus.FAILED @@ -50,52 +53,60 @@ abstract class BaseIntegrationTest { // override this function to define network services abstract suspend fun setup() - fun addNodecore(version: String = "0.4.13-rc.12"): TestNodecore { - val ncSettings = NodecoreSettings( - peerPort = baseNodecoreP2pPort++, - rpcPort = baseNodecoreRpcPort++, - httpPort = baseNodecoreHttpPort++, - baseDir = baseDir, - index = nodecores.size, - progpowTime = progpowStartupTime, - network = "regtest" - ) + fun addNodecore(version: String = nodecoreVersion): TestNodecore { + val ncSettings = + NodecoreSettings( + peerPort = baseNodecoreP2pPort++, + rpcPort = baseNodecoreRpcPort++, + httpPort = baseNodecoreHttpPort++, + baseDir = baseDir, + index = nodecores.size, + progpowTime = progpowStartupTime, + network = "regtest" + ) val nc = TestNodecore(ncSettings, version) nodecores.add(nc) - logger.info("Setting up ${nc.name} with network=${ncSettings.network}") + logger.info("Setting up ${nc.name}:${nodecoreVersion} with network=${ncSettings.network}") return nc } - fun addAPM(node: TestNodecore, btcaltchains: List = emptyList(), version: String = "0.4.13-rc.11"): TestAPM { - val apmSettings = ApmSettings( - index = apms.size, - p2pPort = baseApmP2pPort++, - httpPort = baseApmHttpPort++, - nodecore = node, - baseDir = baseDir, - btcaltchains = btcaltchains - ) + fun addAPM( + node: TestNodecore, + btcaltchains: List = emptyList(), + version: String = apmVersion + ): TestAPM { + val apmSettings = + ApmSettings( + index = apms.size, + p2pPort = baseApmP2pPort++, + httpPort = baseApmHttpPort++, + nodecore = node, + baseDir = baseDir, + btcaltchains = btcaltchains + ) val apm = TestAPM(apmSettings, version) apms.add(apm) - logger.info("Setting up ${apm.name} connected to ${node.name} and BTC plugins: ${btcaltchains.joinToString { it.name() }}") + logger.info( + "Setting up ${apm.name}:${apmVersion} connected to ${node.name} and BTC plugins: ${btcaltchains.joinToString { it.name() }}" + ) return apm } - fun addVBTC(version: String = "master-734a3a0"): TestVBTC { - val settings = VBtcSettings( + fun addBtcsq(version: String = btcsqVersion): TestBtcsq { + val settings = BtcsqSettings( p2pPort = baseBtcP2pPort++, rpcPort = baseBtcRpcPort++, zmqPort = baseBtcZmqPort++, - index = vbtcs.size, + index = btcsqs.size, baseDir = baseDir ) - val vbtc = TestVBTC(settings, version) - vbtcs.add(vbtc) - logger.info("Setting up ${vbtc.name}") - return vbtc + val node = TestBtcsq(settings, version) + btcsqs.add(node) + logger.info("Setting up ${node.name}:${btcsqVersion}") + return node } // entry point for every test @@ -103,20 +114,16 @@ abstract class BaseIntegrationTest { try { logger.info("Setting base dir ${baseDir.absolutePath}") - Runtime.getRuntime().addShutdownHook(Thread { - shutdown() - }) - setup() runTest() status = TestStatus.PASSED willCleanup = shouldCleanup exitCode = 0 - } catch (e: ComparisonFailure) { - logger.error("ASSERTION FAILED") - e.printStackTrace() - status = TestStatus.FAILED - exitCode = 1 +// } catch (e: ComparisonFailure) { +// logger.error("ASSERTION FAILED") +// e.printStackTrace() +// status = TestStatus.FAILED +// exitCode = 1 } catch (e: Exception) { logger.error("UNHANDLED EXCEPTION") e.printStackTrace() @@ -141,14 +148,17 @@ abstract class BaseIntegrationTest { runBlocking { apms.map { async { it.close() } } + - nodecores.map { async { it.close() } } + - vbtcs.map { async { it.close() } } - .awaitAll() + nodecores.map { async { it.close() } } + + btcsqs.map { async { it.close() } }.awaitAll() } nodecores.clear() apms.clear() - vbtcs.clear() + btcsqs.clear() + + if (exitCode != 0) { + throw RuntimeException("Test failed with exit code $exitCode") + } return exitCode } @@ -158,59 +168,56 @@ abstract class BaseIntegrationTest { try { waitUntil(timeout = timeout) { - statuses = apms - .map { it.http.getMinerInfo().status.isReady } + statuses = apms.map { it.http.getMinerInfo().status.isReady } // if all getInfo returned same block, // then we consider syncAll succeeded return@waitUntil statuses.all { it } } } catch (e: TimeoutCancellationException) { - logger.error("syncBlocks failed: ${statuses.joinToString { "\n" }}") + logger.error("syncNodecoreBlocks failed: ${statuses.joinToString { "\n" }}") throw e } } suspend fun syncAllNodecores(nodecores: List, timeout: Long = 60_000 /*ms*/) { - syncBlocks(nodecores, timeout) - syncMempools(nodecores, timeout) + syncNodecoreBlocks(nodecores, timeout) + syncNodecoreMempools(nodecores, timeout) } - - suspend fun syncBlocks(nodecores: List, timeout: Long = 60_000 /*ms*/) { + + suspend fun syncNodecoreBlocks(nodecores: List, timeout: Long = 60_000 /*ms*/) { var hashes: List = emptyList() - + try { waitUntil(timeout = timeout) { - hashes = nodecores - .map { it.http.getInfo().lastBlock.hash } - + hashes = nodecores.map { it.http.getInfo().lastBlock.hash } + // if all getInfo returned same block, // then we consider syncAll succeeded return@waitUntil hashes.toSet().size == 1 } } catch (e: TimeoutCancellationException) { - logger.error("syncBlocks failed: ${hashes.joinToString { "\n" }}") + logger.error("syncNodecoreBlocks failed: ${hashes.joinToString { "\n" }}") throw e } } - - suspend fun syncMempools(nodecores: List, timeout: Long = 60_000 /*ms*/) { + + suspend fun syncNodecoreMempools(nodecores: List, timeout: Long = 60_000 /*ms*/) { var transactions: List> = emptyList() - + try { waitUntil(timeout = timeout) { - transactions = nodecores - .map { - it.http.getPendingTransactions() - .transactions.map { it.txId }.sorted() + transactions = + nodecores.map { + it.http.getPendingTransactions().transactions.map { it.txId }.sorted() } - + // if all getInfo returned same block, // then we consider syncAll succeeded return@waitUntil transactions.toSet().size == 1 } } catch (e: TimeoutCancellationException) { - logger.error("syncMempools failed: ${transactions.joinToString { "\n" }}") + logger.error("syncNodecoreMempools failed: ${transactions.joinToString { "\n" }}") throw e } } diff --git a/src/main/kotlin/nodecore/testframework/BaseJsonRpcApi.kt b/src/main/kotlin/testframework/BaseJsonRpcApi.kt similarity index 75% rename from src/main/kotlin/nodecore/testframework/BaseJsonRpcApi.kt rename to src/main/kotlin/testframework/BaseJsonRpcApi.kt index e8a8324..715bbc4 100644 --- a/src/main/kotlin/nodecore/testframework/BaseJsonRpcApi.kt +++ b/src/main/kotlin/testframework/BaseJsonRpcApi.kt @@ -1,10 +1,19 @@ -package nodecore.testframework +package testframework +import testframework.util.JsonRpcRequestBody +import testframework.util.RpcResponse +import testframework.util.handle +import testframework.util.toJson import io.ktor.client.request.* -import nodecore.api.* import org.slf4j.LoggerFactory +import testframework.util.HttpApiConfig +import testframework.util.HttpAuthConfig +import testframework.util.createHttpClient import java.util.* +/** + * All JSONRPC Apis should extend from this class. + */ open class BaseJsonRpcApi( val name: String, host: String, diff --git a/src/main/kotlin/nodecore/testframework/BtcPluginInterface.kt b/src/main/kotlin/testframework/BtcPluginInterface.kt similarity index 88% rename from src/main/kotlin/nodecore/testframework/BtcPluginInterface.kt rename to src/main/kotlin/testframework/BtcPluginInterface.kt index ef40497..d9313a0 100644 --- a/src/main/kotlin/nodecore/testframework/BtcPluginInterface.kt +++ b/src/main/kotlin/testframework/BtcPluginInterface.kt @@ -1,4 +1,4 @@ -package nodecore.testframework +package testframework interface BtcPluginInterface { fun name(): String diff --git a/src/main/kotlin/nodecore/testframework/Exec.kt b/src/main/kotlin/testframework/Exec.kt similarity index 97% rename from src/main/kotlin/nodecore/testframework/Exec.kt rename to src/main/kotlin/testframework/Exec.kt index faa8de4..50761e3 100644 --- a/src/main/kotlin/nodecore/testframework/Exec.kt +++ b/src/main/kotlin/testframework/Exec.kt @@ -1,4 +1,4 @@ -package nodecore.testframework +package testframework import java.io.File import java.io.IOException diff --git a/src/main/kotlin/nodecore/testframework/ProcessManager.kt b/src/main/kotlin/testframework/ProcessManager.kt similarity index 98% rename from src/main/kotlin/nodecore/testframework/ProcessManager.kt rename to src/main/kotlin/testframework/ProcessManager.kt index 03611ca..d2010c2 100644 --- a/src/main/kotlin/nodecore/testframework/ProcessManager.kt +++ b/src/main/kotlin/testframework/ProcessManager.kt @@ -1,4 +1,4 @@ -package nodecore.testframework +package testframework import kotlinx.coroutines.runBlocking import org.slf4j.LoggerFactory diff --git a/src/main/kotlin/nodecore/testframework/StdStreamLogger.kt b/src/main/kotlin/testframework/StdStreamLogger.kt similarity index 97% rename from src/main/kotlin/nodecore/testframework/StdStreamLogger.kt rename to src/main/kotlin/testframework/StdStreamLogger.kt index 8a9d0ce..9c2d71e 100644 --- a/src/main/kotlin/nodecore/testframework/StdStreamLogger.kt +++ b/src/main/kotlin/testframework/StdStreamLogger.kt @@ -1,4 +1,4 @@ -package nodecore.testframework +package testframework import org.testcontainers.containers.output.OutputFrame import java.io.File diff --git a/src/main/kotlin/nodecore/testframework/Util.kt b/src/main/kotlin/testframework/Util.kt similarity index 92% rename from src/main/kotlin/nodecore/testframework/Util.kt rename to src/main/kotlin/testframework/Util.kt index 3537894..0c60cef 100644 --- a/src/main/kotlin/nodecore/testframework/Util.kt +++ b/src/main/kotlin/testframework/Util.kt @@ -1,19 +1,19 @@ -package nodecore.testframework +package testframework import com.google.protobuf.ByteString import kotlinx.coroutines.delay import nodecore.api.grpc.RpcEvent import nodecore.api.grpc.utilities.ByteStringUtility -import nodecore.testframework.wrapper.apm.TestAPM -import nodecore.testframework.wrapper.nodecore.BitcoinBlockHeader -import nodecore.testframework.wrapper.nodecore.Endpoint -import nodecore.testframework.wrapper.nodecore.SubmitPopRequest -import nodecore.testframework.wrapper.nodecore.TestNodecore import org.testcontainers.containers.GenericContainer import org.testcontainers.utility.DockerImageName import org.veriblock.core.wallet.AddressKeyGenerator import org.veriblock.sdk.models.Address import org.veriblock.sdk.models.VeriBlockPopTransaction +import testframework.wrapper.apm.TestAPM +import testframework.wrapper.nodecore.BitcoinBlockHeader +import testframework.wrapper.nodecore.Endpoint +import testframework.wrapper.nodecore.SubmitPopRequest +import testframework.wrapper.nodecore.TestNodecore import java.net.ServerSocket import java.security.KeyPair import java.util.concurrent.TimeoutException diff --git a/src/main/kotlin/nodecore/api/HttpClient.kt b/src/main/kotlin/testframework/util/HttpClient.kt similarity index 71% rename from src/main/kotlin/nodecore/api/HttpClient.kt rename to src/main/kotlin/testframework/util/HttpClient.kt index 6428e80..74fa565 100644 --- a/src/main/kotlin/nodecore/api/HttpClient.kt +++ b/src/main/kotlin/testframework/util/HttpClient.kt @@ -1,10 +1,11 @@ -package nodecore.api// VeriBlock Blockchain Project +// VeriBlock Blockchain Project // Copyright 2017-2018 VeriBlock, Inc // Copyright 2018-2019 Xenios SEZC // All rights reserved. // https://www.veriblock.org // Distributed under the MIT software license, see the accompanying // file LICENSE or http://www.opensource.org/licenses/mit-license.php. +package testframework.util import com.google.gson.Gson import com.google.gson.JsonElement @@ -12,7 +13,7 @@ import io.ktor.client.HttpClient import io.ktor.client.engine.cio.CIO import io.ktor.client.features.* import io.ktor.client.features.auth.Auth -import io.ktor.client.features.auth.providers.basic +import io.ktor.client.features.auth.providers.* import io.ktor.client.features.json.JsonFeature import io.ktor.http.ContentType import java.lang.reflect.Type @@ -31,7 +32,11 @@ class HttpAuthConfig( val password: String ) -fun createHttpClient(authConfig: HttpAuthConfig? = null, contentTypes: List? = null, timeoutMillis: Long = 0) = HttpClient(CIO) { +fun createHttpClient( + authConfig: HttpAuthConfig? = null, + contentTypes: List? = null, + timeoutMillis: Long = 0 +) = HttpClient(CIO) { install(JsonFeature) { if (contentTypes != null) { acceptContentTypes = contentTypes @@ -40,8 +45,12 @@ fun createHttpClient(authConfig: HttpAuthConfig? = null, contentTypes: List ) +@Serializable +data class VbkInfoAddress ( + val address: String +) + @Serializable data class VbkInfo( - val lastBlock: VbkBlockData + val lastBlock: VbkBlockData, + val defaultAddress: VbkInfoAddress ) @Serializable @@ -43,16 +49,65 @@ data class GenerateBlocksReply( ) @Serializable -data class BlockHeaderContainer( +data class BlockHeader( + val header: String, + val hash: String +) + +@Serializable +data class GetLastBlockReply( val header: BlockHeader ) @Serializable -data class BlockHeader( - val hash: String, +data class GetLastBitcoinBlockReply( + val header: String, + val height: Int, + val hash: String +) + +@Serializable +data class BitcoinBlockHeader( val header: String ) +@Serializable +data class SubmitPopRequest( + val endorsedBlockHeader: String, + val bitcoinTransaction: String, + val bitcoinMerklePathToRoot: String, + val bitcoinBlockHeaderOfProof: BitcoinBlockHeader, + val contextBitcoinBlockHeaders: List, + val address: String +) + +@Serializable +data class SendCoinsRequest( + val amounts: List, + val sourceAddress: String? = null, + val takeFeeFromOutputs: Boolean = false +) + +@Serializable +data class SendCoinsReply( + val success: Boolean, + val results: List, + val txIds: List +) + +@Serializable +data class GetPendingTransactionsReply( + val success: Boolean, + val results: List, + val transactions: List +) + + +@Serializable +data class BlockHeaderContainer( + val header: BlockHeader +) + @Serializable data class VbkBlockData( val hash: String, @@ -192,11 +247,6 @@ data class Output( val amount: Long ) -@Serializable -data class BitcoinBlockHeader( - val header: String -) - @Serializable data class SignedTransaction( val signature: String, @@ -271,23 +321,3 @@ data class TransactionInfo( val bitcoinConfirmations: Int ) -@Serializable -data class SendCoinsRequest( - val amounts: List, - val sourceAddress: String? = null, - val takeFeeFromOutputs: Boolean = false -) - -@Serializable -data class SendCoinsReply( - val success: Boolean, - val results: List, - val txIds: List -) - -@Serializable -data class GetPendingTransactionsReply( - val success: Boolean, - val results: List, - val transactions: List -) diff --git a/src/main/kotlin/nodecore/testframework/wrapper/nodecore/MiniNode.kt b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt similarity index 98% rename from src/main/kotlin/nodecore/testframework/wrapper/nodecore/MiniNode.kt rename to src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt index b6dc270..55b409f 100644 --- a/src/main/kotlin/nodecore/testframework/wrapper/nodecore/MiniNode.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt @@ -1,4 +1,4 @@ -package nodecore.testframework.wrapper.nodecore +package testframework.wrapper.nodecore import com.google.common.util.concurrent.ThreadFactoryBuilder import io.ktor.network.selector.* @@ -10,7 +10,7 @@ import kotlinx.coroutines.channels.ClosedReceiveChannelException import nodecore.api.grpc.RpcAnnounce import nodecore.api.grpc.RpcEvent import nodecore.api.grpc.RpcNodeInfo -import nodecore.testframework.buildMessage +import testframework.buildMessage import org.slf4j.LoggerFactory import java.io.Closeable import java.io.EOFException @@ -57,7 +57,7 @@ private class PeerSocket( fun write(message: RpcEvent) { logger.debug("$peerName <--p2p-- ${message.resultsCase.name}") try { - if (!writeQueue.offer(message)) { + if (!writeQueue.trySend(message).isSuccess) { logger.warn( "Not writing event ${message.resultsCase.name} to peer $peerName because write queue is full." ) diff --git a/src/main/kotlin/nodecore/testframework/wrapper/nodecore/NodeHttpApi.kt b/src/main/kotlin/testframework/wrapper/nodecore/NodeHttpApi.kt similarity index 82% rename from src/main/kotlin/nodecore/testframework/wrapper/nodecore/NodeHttpApi.kt rename to src/main/kotlin/testframework/wrapper/nodecore/NodeHttpApi.kt index 53480b6..51bbad3 100644 --- a/src/main/kotlin/nodecore/testframework/wrapper/nodecore/NodeHttpApi.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/NodeHttpApi.kt @@ -1,13 +1,7 @@ -package nodecore.testframework.wrapper.nodecore +package testframework.wrapper.nodecore -import nodecore.api.GetPendingTransactionsReply -import nodecore.api.SendCoinsReply -import nodecore.api.SendCoinsRequest -import nodecore.api.grpc.RpcGetPendingTransactionsReply -import nodecore.api.grpc.RpcSendCoinsReply -import nodecore.api.grpc.RpcSendCoinsRequest -import nodecore.testframework.BaseJsonRpcApi -import nodecore.testframework.toRequest +import testframework.BaseJsonRpcApi +import testframework.toRequest import org.veriblock.sdk.models.Address import org.veriblock.sdk.models.VeriBlockPopTransaction diff --git a/src/main/kotlin/nodecore/testframework/wrapper/nodecore/TestNodecore.kt b/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt similarity index 89% rename from src/main/kotlin/nodecore/testframework/wrapper/nodecore/TestNodecore.kt rename to src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt index fef64a5..0b14962 100644 --- a/src/main/kotlin/nodecore/testframework/wrapper/nodecore/TestNodecore.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt @@ -1,14 +1,14 @@ -package nodecore.testframework.wrapper.nodecore +package testframework.wrapper.nodecore import io.grpc.Deadline import io.grpc.ManagedChannelBuilder import kotlinx.coroutines.delay import kotlinx.coroutines.withTimeout import nodecore.api.grpc.AdminGrpc -import nodecore.testframework.StdStreamLogger -import nodecore.testframework.KGenericContainer import org.slf4j.LoggerFactory import org.testcontainers.containers.BindMode +import testframework.KGenericContainer +import testframework.StdStreamLogger import java.io.Closeable import java.io.File import java.util.concurrent.TimeUnit @@ -46,6 +46,10 @@ class TestNodecore( // Accessor for Admin HTTP API val http = NodeHttpApi(name, "127.0.0.1", settings.httpPort) val rpc: AdminGrpc.AdminBlockingStub + private val channel = ManagedChannelBuilder + .forAddress("127.0.0.1", settings.rpcPort) + .usePlaintext() + .build() init { datadir.mkdirs() @@ -57,12 +61,7 @@ class TestNodecore( // setup RPC channel rpc = AdminGrpc - .newBlockingStub( - ManagedChannelBuilder - .forAddress("127.0.0.1", settings.rpcPort) - .usePlaintext() - .build() - ) + .newBlockingStub(channel) .withMaxInboundMessageSize(20 * 1024 * 1024) .withMaxOutboundMessageSize(20 * 1024 * 1024) .withDeadline(Deadline.after(rpcTimeout, TimeUnit.MILLISECONDS)) @@ -100,6 +99,10 @@ class TestNodecore( } fun stop() { + // don't forget to shutdown channel + if(!channel.isShutdown) { + channel.shutdownNow() + } container.stop() } diff --git a/src/test/kotlin/functional/ExampleApmTest.kt b/src/test/kotlin/functional/ExampleApmTest.kt index a833143..4232fa2 100644 --- a/src/test/kotlin/functional/ExampleApmTest.kt +++ b/src/test/kotlin/functional/ExampleApmTest.kt @@ -2,8 +2,8 @@ package functional import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking -import nodecore.testframework.BaseIntegrationTest -import nodecore.testframework.BtcPluginInterface +import testframework.BaseIntegrationTest +import testframework.BtcPluginInterface import kotlin.test.Test internal class ExampleApmTest : BaseIntegrationTest() { @@ -18,7 +18,7 @@ internal class ExampleApmTest : BaseIntegrationTest() { val nodecore = addNodecore() nodecore.start() - val vbtc = addVBTC() + val vbtc = addBtcsq() vbtc.start() val apm = addAPM(nodecore, List(1){vbtc}) diff --git a/src/test/kotlin/functional/ExampleTest.kt b/src/test/kotlin/functional/ExampleTest.kt index bee5e37..826ac69 100644 --- a/src/test/kotlin/functional/ExampleTest.kt +++ b/src/test/kotlin/functional/ExampleTest.kt @@ -7,10 +7,10 @@ import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking import nodecore.api.grpc.RpcEvent -import nodecore.testframework.BaseIntegrationTest -import nodecore.testframework.wrapper.nodecore.MiniNode -import nodecore.testframework.connectNodes -import nodecore.testframework.randomAddress +import testframework.BaseIntegrationTest +import testframework.wrapper.nodecore.MiniNode +import testframework.connectNodes +import testframework.randomAddress import kotlin.test.Test import org.veriblock.core.utilities.createLogger diff --git a/src/test/kotlin/functional/LedgerProofTest.kt b/src/test/kotlin/functional/LedgerProofTest.kt index b0a8b71..e36f6a2 100644 --- a/src/test/kotlin/functional/LedgerProofTest.kt +++ b/src/test/kotlin/functional/LedgerProofTest.kt @@ -8,8 +8,8 @@ import nodecore.api.grpc.RpcLedgerProofReply import nodecore.api.grpc.RpcLedgerProofReply.* import nodecore.api.grpc.RpcLedgerProofRequest import nodecore.api.grpc.utilities.ByteStringAddressUtility -import nodecore.testframework.* -import nodecore.testframework.wrapper.nodecore.MiniNode +import testframework.* +import testframework.wrapper.nodecore.MiniNode import kotlin.test.Test import org.veriblock.extensions.ledger.LedgerProofWithContext import org.veriblock.sdk.models.Address diff --git a/src/test/kotlin/functional/PopMiningTest.kt b/src/test/kotlin/functional/PopMiningTest.kt index 21c0e78..1261756 100644 --- a/src/test/kotlin/functional/PopMiningTest.kt +++ b/src/test/kotlin/functional/PopMiningTest.kt @@ -2,9 +2,9 @@ package functional import io.kotest.matchers.shouldBe import kotlinx.coroutines.* -import nodecore.testframework.* -import nodecore.testframework.wrapper.apm.MineRequest -import nodecore.testframework.wrapper.nodecore.TestNodecore +import testframework.* +import testframework.wrapper.apm.MineRequest +import testframework.wrapper.nodecore.TestNodecore import org.bouncycastle.jce.provider.BouncyCastleProvider import kotlin.test.Test import org.nodecore.vpmmock.mockmining.VeriBlockPopMinerMock @@ -63,7 +63,7 @@ class PopMiningTest : BaseIntegrationTest() { connectNodes(nodecores[i + 1], nodecores[i]) } - val vbtc = addVBTC() + val vbtc = addBtcsq() vbtc.start() vbtc.mineUntilPopEnabled() @@ -75,8 +75,8 @@ class PopMiningTest : BaseIntegrationTest() { logger.info("Running PopMiningTest test!") logger.info("Generating 10 vBTC blocks") - val vbtcAddr = vbtcs[0].rpc.getNewAddress() - vbtcs[0].rpc.generateToAddress(10, vbtcAddr) + val vbtcAddr = btcsqs[0].rpc.getNewAddress() + btcsqs[0].rpc.generateToAddress(10, vbtcAddr) logger.info("Sending VBK to APM address ${apms[0].vbkAddress}") topUpApmWallet(apms[0], blocks = 10) @@ -92,7 +92,7 @@ class PopMiningTest : BaseIntegrationTest() { } syncAllApms(apms) - val operation = apms[0].http.mine(MineRequest(chainSymbol = vbtcs[0].name, 210)) // TODO: height = popActvationHeight + mined vbtc blocks + val operation = apms[0].http.mine(MineRequest(chainSymbol = btcsqs[0].name, 210)) // TODO: height = popActvationHeight + mined vbtc blocks logger.info("waiting until APM submits endorsement TX") waitUntil(delay = 5000L) { @@ -118,15 +118,15 @@ class PopMiningTest : BaseIntegrationTest() { logger.info("waiting until APM sends all lacking VBK context blocks, $TOTAL_VTBS VTBs and 1 ATV") waitUntil(timeout = 120_000L, delay = 5000L) { - val popmp = vbtcs[0].rpc.getRawPopMempool() + val popmp = btcsqs[0].rpc.getRawPopMempool() // total number of VBK blocks in mempool must be `lastBlockHeight - 1` popmp.vbkblocks.size != lastBlockHeight - 1 /* genesis */ && popmp.vtbs.size >= TOTAL_VTBS && popmp.atvs.isNotEmpty() } - vbtcs[0].rpc.generateToAddress(1, address = vbtcAddr)[0] + btcsqs[0].rpc.generateToAddress(1, address = vbtcAddr)[0] // all pop-payloads mined, mempool is empty - val popmp = vbtcs[0].rpc.getRawPopMempool() + val popmp = btcsqs[0].rpc.getRawPopMempool() popmp.atvs.size shouldBe 0 popmp.vtbs.size shouldBe 0 popmp.vbkblocks.size shouldBe 0 diff --git a/src/test/kotlin/functional/TxLimitTest.kt b/src/test/kotlin/functional/TxLimitTest.kt index b63e049..975701a 100644 --- a/src/test/kotlin/functional/TxLimitTest.kt +++ b/src/test/kotlin/functional/TxLimitTest.kt @@ -5,11 +5,11 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking -import nodecore.testframework.BaseIntegrationTest -import nodecore.testframework.connectNodes -import nodecore.testframework.topUpApmWallet -import nodecore.testframework.waitUntil -import nodecore.testframework.wrapper.apm.MineRequest +import testframework.BaseIntegrationTest +import testframework.connectNodes +import testframework.topUpApmWallet +import testframework.waitUntil +import testframework.wrapper.apm.MineRequest import kotlin.test.Test class TxLimitTest : BaseIntegrationTest() { @@ -29,7 +29,7 @@ class TxLimitTest : BaseIntegrationTest() { connectNodes(nodecores[i + 1], nodecores[i]) } - val vbtc = addVBTC() + val vbtc = addBtcsq() vbtc.start() vbtc.mineUntilPopEnabled() @@ -46,7 +46,7 @@ class TxLimitTest : BaseIntegrationTest() { val TX_LIMIT = 900 logger.info("Create ${TX_LIMIT} transactions") for (i in 1..TX_LIMIT) { - apms[0].http.mine(MineRequest(chainSymbol = vbtcs[0].name, 200)) + apms[0].http.mine(MineRequest(chainSymbol = btcsqs[0].name, 200)) } waitUntil { @@ -57,7 +57,7 @@ class TxLimitTest : BaseIntegrationTest() { logger.info("Create 901 transaction") try { - apms[0].http.mine(MineRequest(chainSymbol = vbtcs[0].name, 200)) + apms[0].http.mine(MineRequest(chainSymbol = btcsqs[0].name, 200)) throw NoErrorException("Error was not returned") } catch(e: NoErrorException) { logger.error(e.message) diff --git a/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt b/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt index d7768c3..c659528 100644 --- a/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt +++ b/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt @@ -7,11 +7,11 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking -import nodecore.testframework.BaseIntegrationTest -import nodecore.testframework.connectNodes +import testframework.BaseIntegrationTest +import testframework.connectNodes +import testframework.wrapper.nodecore.Output +import testframework.wrapper.nodecore.SendCoinsRequest import kotlin.test.Test -import nodecore.api.Output -import nodecore.api.SendCoinsRequest class NodeCoreMempoolSyncTest : BaseIntegrationTest() { override suspend fun setup() = coroutineScope { From 9182e607aa7759cb3d249c18324cc36e0debcf37 Mon Sep 17 00:00:00 2001 From: Bohdan Vanieiev Date: Thu, 16 Dec 2021 18:42:06 +0200 Subject: [PATCH 02/12] Fix tests --- .github/workflows/main.yml | 15 +++------ build.gradle.kts | 31 +++++++++++++++--- .../testframework/BaseIntegrationTest.kt | 32 +++++++++---------- src/main/resources/log4j2.xml | 2 +- src/test/kotlin/functional/ExampleApmTest.kt | 2 +- src/test/kotlin/functional/LedgerProofTest.kt | 2 ++ src/test/kotlin/functional/PopMiningTest.kt | 8 ++--- .../nodecore/NodeCoreMempoolSyncTest.kt | 2 +- 8 files changed, 56 insertions(+), 38 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a353ebf..c1d6e61 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,28 +1,23 @@ -# This is a basic workflow to help you get started with Actions - name: CI -# Controls when the workflow will run on: - # Triggers the workflow on push or pull request events but only for the master branch push: branches: [ master ] pull_request: branches: [ master ] - # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - # This workflow contains a single job called "build" build: - # The type of runner that the job will run on runs-on: ubuntu-latest + env: + # specify versions to test + INT_NODECORE_VERSION: "0.4.13-rc.11" + INT_APM_VERSION: "0.4.13-rc.11" + INT_BTCSQ_VERSION: "master-47363b0" - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - uses: actions/setup-java@v2 with: diff --git a/build.gradle.kts b/build.gradle.kts index 25f5e29..4deba88 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,11 @@ -import org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL -import org.gradle.api.tasks.testing.logging.TestExceptionFormat.SHORT import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import com.adarshr.gradle.testlogger.TestLoggerExtension +import com.adarshr.gradle.testlogger.TestLoggerPlugin +import com.adarshr.gradle.testlogger.theme.ThemeType plugins { kotlin("jvm") version "1.5.31" + id("com.adarshr.test-logger") version "3.1.0" } group = "org.veriblock" @@ -17,7 +19,7 @@ repositories { val kotestVersion = "5.0.1" val coroutinesVersion = "1.5.2-native-mt" val log4jVersion= "2.16.0" -val ktorVersion = "1.6.6" +val ktorVersion = "1.6.0" dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") @@ -48,8 +50,6 @@ dependencies { tasks.test { useJUnitPlatform() maxParallelForks = 1 - testLogging.showStandardStreams = true - testLogging.exceptionFormat = SHORT } tasks.withType { @@ -63,3 +63,24 @@ tasks.withType { tasks.withType { useJUnitPlatform() } + +plugins.withType { + configure { + theme = ThemeType.MOCHA + showExceptions = true + showStackTraces = true + showFullStackTraces = false + showCauses = true + slowThreshold = 20000 + showSummary = true + showSimpleNames = false + showPassed = true + showSkipped = true + showFailed = true + showStandardStreams = true + showPassedStandardStreams = false + showSkippedStandardStreams = false + showFailedStandardStreams = true + logLevel = LogLevel.LIFECYCLE + } +} diff --git a/src/main/kotlin/testframework/BaseIntegrationTest.kt b/src/main/kotlin/testframework/BaseIntegrationTest.kt index ea0121a..178c9ef 100644 --- a/src/main/kotlin/testframework/BaseIntegrationTest.kt +++ b/src/main/kotlin/testframework/BaseIntegrationTest.kt @@ -119,22 +119,28 @@ abstract class BaseIntegrationTest { status = TestStatus.PASSED willCleanup = shouldCleanup exitCode = 0 -// } catch (e: ComparisonFailure) { -// logger.error("ASSERTION FAILED") -// e.printStackTrace() -// status = TestStatus.FAILED -// exitCode = 1 + } catch (e: AssertionError) { + logger.error("ASSERTION FAILED") + e.printStackTrace() + fail(e) } catch (e: Exception) { logger.error("UNHANDLED EXCEPTION") - e.printStackTrace() - status = TestStatus.FAILED - exitCode = 1 + fail(e) } finally { - return shutdown() + shutdown() } + + return 0 } - private fun shutdown(): Int { + private fun fail(reason: Exception) { + throw RuntimeException("Test failed: \n${reason}") + } + private fun fail(reason: Error) { + throw RuntimeException("Test failed: \n${reason}") + } + + private fun shutdown() { logger.info("Test ${status.state}!") logger.info("Logs are available in ${baseDir.absolutePath}") logger.info("Shutting down environment...") @@ -155,12 +161,6 @@ abstract class BaseIntegrationTest { nodecores.clear() apms.clear() btcsqs.clear() - - if (exitCode != 0) { - throw RuntimeException("Test failed with exit code $exitCode") - } - - return exitCode } suspend fun syncAllApms(apms: List, timeout: Long = 60_000 /*ms*/) { diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index af739ea..1fa7e9e 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -1,7 +1,7 @@ - + diff --git a/src/test/kotlin/functional/ExampleApmTest.kt b/src/test/kotlin/functional/ExampleApmTest.kt index 4232fa2..d19519b 100644 --- a/src/test/kotlin/functional/ExampleApmTest.kt +++ b/src/test/kotlin/functional/ExampleApmTest.kt @@ -21,7 +21,7 @@ internal class ExampleApmTest : BaseIntegrationTest() { val vbtc = addBtcsq() vbtc.start() - val apm = addAPM(nodecore, List(1){vbtc}) + val apm = addAPM(nodecore, listOf(vbtc)) apm.start() } diff --git a/src/test/kotlin/functional/LedgerProofTest.kt b/src/test/kotlin/functional/LedgerProofTest.kt index e36f6a2..b6f7aac 100644 --- a/src/test/kotlin/functional/LedgerProofTest.kt +++ b/src/test/kotlin/functional/LedgerProofTest.kt @@ -46,6 +46,8 @@ internal class LedgerProofTest : BaseIntegrationTest() { val n = LedgerProofVerifier() n.connect(nodecores[0]) + val info = nodecores[0].http.getInfo() + // TODO: check that nodecore0 is connected to mininodes nodecores[0].http.generateBlocks(100, addr1.toString()) diff --git a/src/test/kotlin/functional/PopMiningTest.kt b/src/test/kotlin/functional/PopMiningTest.kt index 1261756..6e88b56 100644 --- a/src/test/kotlin/functional/PopMiningTest.kt +++ b/src/test/kotlin/functional/PopMiningTest.kt @@ -85,8 +85,8 @@ class PopMiningTest : BaseIntegrationTest() { val ncAddress = Address(nodecores[0].http.getInfo().defaultAddress.address) logger.info("Generating VTBs...") - val TOTAL_VTBS = 10 - for (i in 1..TOTAL_VTBS) { + val totalVtbs = 10 + for (i in 1..totalVtbs) { nodecores[0].http.generateBlocks(1, ncAddress.toString()) endorseVbkTip(nodecores[0], address = ncAddress) } @@ -116,11 +116,11 @@ class PopMiningTest : BaseIntegrationTest() { val lastBlockHeight = nodecores[0].http.getInfo().lastBlock.number; - logger.info("waiting until APM sends all lacking VBK context blocks, $TOTAL_VTBS VTBs and 1 ATV") + logger.info("waiting until APM sends all lacking VBK context blocks, $totalVtbs VTBs and 1 ATV") waitUntil(timeout = 120_000L, delay = 5000L) { val popmp = btcsqs[0].rpc.getRawPopMempool() // total number of VBK blocks in mempool must be `lastBlockHeight - 1` - popmp.vbkblocks.size != lastBlockHeight - 1 /* genesis */ && popmp.vtbs.size >= TOTAL_VTBS && popmp.atvs.isNotEmpty() + popmp.vbkblocks.size != lastBlockHeight - 1 /* genesis */ && popmp.vtbs.size >= totalVtbs && popmp.atvs.isNotEmpty() } btcsqs[0].rpc.generateToAddress(1, address = vbtcAddr)[0] diff --git a/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt b/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt index c659528..db59a81 100644 --- a/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt +++ b/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt @@ -1,4 +1,4 @@ -package functional +package functional.nodecore import io.kotest.matchers.collections.shouldNotBeEmpty import io.kotest.matchers.shouldBe From 036a62b6c3385dc38a87a8f73efb0e52f97ca0f1 Mon Sep 17 00:00:00 2001 From: Bohdan Vanieiev Date: Thu, 16 Dec 2021 22:49:09 +0200 Subject: [PATCH 03/12] Use deprecated offer --- src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt index 55b409f..6c4494c 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt @@ -54,13 +54,16 @@ private class PeerSocket( start() } - fun write(message: RpcEvent) { + fun write(message: RpcEvent, failOnError: Boolean = true) { logger.debug("$peerName <--p2p-- ${message.resultsCase.name}") try { - if (!writeQueue.trySend(message).isSuccess) { + if (!writeQueue.offer(message)) { logger.warn( "Not writing event ${message.resultsCase.name} to peer $peerName because write queue is full." ) + if (failOnError) { + throw RuntimeException("$peerName: Write queue is full") + } } } catch (e: InterruptedException) { logger.warn("Output stream thread shutting down for peer $peerName") From 7daa6dc4921d8f52929544e3055934721058f92d Mon Sep 17 00:00:00 2001 From: Bohdan Vanieiev Date: Thu, 16 Dec 2021 23:44:18 +0200 Subject: [PATCH 04/12] Use PerClass lifecycle --- gradle.properties | 1 + .../wrapper/nodecore/Entities.kt | 49 ++++++++++++++++++- .../wrapper/nodecore/MiniNode.kt | 31 ++---------- .../wrapper/nodecore/NodeHttpApi.kt | 5 +- src/main/resources/junit-platform.properties | 1 + src/test/kotlin/functional/ExampleApmTest.kt | 2 + src/test/kotlin/functional/ExampleTest.kt | 2 + src/test/kotlin/functional/LedgerProofTest.kt | 16 +++--- src/test/kotlin/functional/PopMiningTest.kt | 2 + src/test/kotlin/functional/TxLimitTest.kt | 2 + .../nodecore/NodeCoreMempoolSyncTest.kt | 2 + 11 files changed, 76 insertions(+), 37 deletions(-) create mode 100644 src/main/resources/junit-platform.properties diff --git a/gradle.properties b/gradle.properties index 7fc6f1f..a3293d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ kotlin.code.style=official + diff --git a/src/main/kotlin/testframework/wrapper/nodecore/Entities.kt b/src/main/kotlin/testframework/wrapper/nodecore/Entities.kt index 82f2877..7e50cdf 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/Entities.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/Entities.kt @@ -1,6 +1,7 @@ package testframework.wrapper.nodecore import kotlinx.serialization.Serializable +import nodecore.api.grpc.RpcNodeInfo @Serializable data class Result( @@ -21,7 +22,53 @@ data class ProtocolReply( ) @Serializable -data class VbkInfoAddress ( +data class NodeInfo( + val address: String = "", + val application: String = "MiniNode", + val platform: String = "e2eTest", + val startTimestamp: Int = 1552064237, + val id: String = "Test", + val port: Int = 12345, + // mainnet, regtest, alphanet == 3 + // testnet, testnet_progpow == 2 + val protocolVersion: Int = 3, + val share: Boolean = false, + val capabilities: Long = 0 +) { + fun toProto(): RpcNodeInfo { + return RpcNodeInfo.newBuilder() + .setApplication(application) + .setPlatform(platform) + .setAddress(address) + .setStartTimestamp(startTimestamp) + .setId(id) + .setPort(port) + .setShare(share) + .setProtocolVersion(protocolVersion) + .setCapabilities(capabilities) + .build() + } +} + +@Serializable +data class NodeHeight( + val peer: String, + val height: Int +) + +@Serializable +data class GetPeerInfoReply( + val success: Boolean, + val results: List, + val endpoints: List, + val connectedNodes: List, + val disconnectedNodes: List, + val candidateNodes: List, + val nodeHeights: List +) + +@Serializable +data class VbkInfoAddress( val address: String ) diff --git a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt index 6c4494c..f71da30 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt @@ -150,28 +150,7 @@ private class PeerSocket( } -data class NodeMetadata( - var application: String = "", - var platform: String = "", - var startTimestamp: Int = 1552064237, - var id: String = "Test", - var port: Int = 12345, - // mainnet, regtest, alphanet == 3 - // testnet, testnet_progpow == 2 - var protocolVersion: Int = 3 -) { - fun toProto(): RpcNodeInfo { - return RpcNodeInfo.newBuilder() - .setApplication(application) - .setPlatform(platform) - .setStartTimestamp(startTimestamp) - .setId(id) - .setPort(port) - .setShare(false) - .setProtocolVersion(protocolVersion) - .build() - } -} + open class MiniNode : Closeable, AutoCloseable { @@ -179,7 +158,7 @@ open class MiniNode : Closeable, AutoCloseable { private var socket: PeerSocket? = null val stats: HashMap = HashMap() val identity = AtomicLong(0) - val metadata: NodeMetadata = NodeMetadata() + val metadata: NodeInfo = NodeInfo() fun nextMessageId(): String { return identity.incrementAndGet().toString() @@ -191,11 +170,11 @@ open class MiniNode : Closeable, AutoCloseable { suspend fun connect(p: TestNodecore, shouldAnnounce: Boolean = true) { if (socket != null) { - logger.warn("Already connected to ${peerName()}, disconnect first") + logger.warn("Already connected to ${p.name}, disconnect first") return } val address = NetworkAddress("127.0.0.1", p.settings.peerPort) - logger.debug("Connecting to node${p.settings.index}") + logger.debug("Connecting to ${p.name}") try { val socket = PeerSocket( @@ -219,7 +198,7 @@ open class MiniNode : Closeable, AutoCloseable { } this.socket = socket } catch (e: Exception) { - logger.error("Unable to connect to ${peerName()}") + logger.error("Unable to connect to ${p.name}") throw e } } diff --git a/src/main/kotlin/testframework/wrapper/nodecore/NodeHttpApi.kt b/src/main/kotlin/testframework/wrapper/nodecore/NodeHttpApi.kt index 51bbad3..221a05a 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/NodeHttpApi.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/NodeHttpApi.kt @@ -1,5 +1,6 @@ package testframework.wrapper.nodecore +import nodecore.api.grpc.RpcGetPeerInfoReply import testframework.BaseJsonRpcApi import testframework.toRequest import org.veriblock.sdk.models.Address @@ -20,8 +21,8 @@ class NodeHttpApi( method = "getinfo" ) - suspend fun getStateInfo(): VbkInfo = performRequest( - method = "getstateinfo" + suspend fun getPeerInfo(): GetPeerInfoReply = performRequest( + method = "getpeerinfo" ) suspend fun addNode(e: List): ProtocolReply = performRequest( diff --git a/src/main/resources/junit-platform.properties b/src/main/resources/junit-platform.properties new file mode 100644 index 0000000..e6d55f8 --- /dev/null +++ b/src/main/resources/junit-platform.properties @@ -0,0 +1 @@ +junit.jupiter.testinstance.lifecycle.default = per_class \ No newline at end of file diff --git a/src/test/kotlin/functional/ExampleApmTest.kt b/src/test/kotlin/functional/ExampleApmTest.kt index d19519b..dafa470 100644 --- a/src/test/kotlin/functional/ExampleApmTest.kt +++ b/src/test/kotlin/functional/ExampleApmTest.kt @@ -2,10 +2,12 @@ package functional import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.TestInstance import testframework.BaseIntegrationTest import testframework.BtcPluginInterface import kotlin.test.Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class ExampleApmTest : BaseIntegrationTest() { override suspend fun runTest() { logger.info("Running ExampleApmTest test!") diff --git a/src/test/kotlin/functional/ExampleTest.kt b/src/test/kotlin/functional/ExampleTest.kt index 826ac69..92d39d7 100644 --- a/src/test/kotlin/functional/ExampleTest.kt +++ b/src/test/kotlin/functional/ExampleTest.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking import nodecore.api.grpc.RpcEvent +import org.junit.jupiter.api.TestInstance import testframework.BaseIntegrationTest import testframework.wrapper.nodecore.MiniNode import testframework.connectNodes @@ -21,6 +22,7 @@ private class ExampleMiniNode : MiniNode() { } } +@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class ExampleTest : BaseIntegrationTest() { override suspend fun setup() = coroutineScope { addNodecore() diff --git a/src/test/kotlin/functional/LedgerProofTest.kt b/src/test/kotlin/functional/LedgerProofTest.kt index b6f7aac..a36980e 100644 --- a/src/test/kotlin/functional/LedgerProofTest.kt +++ b/src/test/kotlin/functional/LedgerProofTest.kt @@ -1,6 +1,7 @@ package functional import com.google.protobuf.ByteString +import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe import kotlinx.coroutines.* import nodecore.api.grpc.RpcEvent @@ -8,6 +9,7 @@ import nodecore.api.grpc.RpcLedgerProofReply import nodecore.api.grpc.RpcLedgerProofReply.* import nodecore.api.grpc.RpcLedgerProofRequest import nodecore.api.grpc.utilities.ByteStringAddressUtility +import org.junit.jupiter.api.TestInstance import testframework.* import testframework.wrapper.nodecore.MiniNode import kotlin.test.Test @@ -24,6 +26,7 @@ private class LedgerProofVerifier : MiniNode() { } } +@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class LedgerProofTest : BaseIntegrationTest() { // exists, has VBK val addr1 = randomAddress() @@ -44,10 +47,12 @@ internal class LedgerProofTest : BaseIntegrationTest() { override suspend fun runTest() { logger.info("Running LedgerProof test!") + nodecores[0].stdlog.useConsole = true + val n = LedgerProofVerifier() n.connect(nodecores[0]) - val info = nodecores[0].http.getInfo() - // TODO: check that nodecore0 is connected to mininodes + val peerinfo = nodecores[0].http.getPeerInfo() + peerinfo.connectedNodes shouldHaveSize 1 nodecores[0].http.generateBlocks(100, addr1.toString()) @@ -79,7 +84,7 @@ internal class LedgerProofTest : BaseIntegrationTest() { fun checkProofOfExistence(e: LedgerProofResult) { e.result shouldBe Status.ADDRESS_EXISTS - // throws is proof is invalid + // throws if proof is invalid val proof = LedgerProofWithContext.parseFrom( e.ledgerProofWithContext ) @@ -98,11 +103,6 @@ internal class LedgerProofTest : BaseIntegrationTest() { proof.ledgerAddress shouldBe addr2.toString() } - fun checkInvalidAddr(e: LedgerProofResult) { - e.address.toString("UTF-8") shouldBe badAddr - e.result shouldBe Status.ADDRESS_IS_INVALID - } - @Test fun run(): Unit = runBlocking { LedgerProofTest().main() diff --git a/src/test/kotlin/functional/PopMiningTest.kt b/src/test/kotlin/functional/PopMiningTest.kt index 6e88b56..b04641b 100644 --- a/src/test/kotlin/functional/PopMiningTest.kt +++ b/src/test/kotlin/functional/PopMiningTest.kt @@ -6,6 +6,7 @@ import testframework.* import testframework.wrapper.apm.MineRequest import testframework.wrapper.nodecore.TestNodecore import org.bouncycastle.jce.provider.BouncyCastleProvider +import org.junit.jupiter.api.TestInstance import kotlin.test.Test import org.nodecore.vpmmock.mockmining.VeriBlockPopMinerMock import org.veriblock.core.Context @@ -16,6 +17,7 @@ import org.veriblock.sdk.models.Address import org.veriblock.sdk.services.SerializeDeserializeService import java.security.Security +@TestInstance(TestInstance.Lifecycle.PER_CLASS) class PopMiningTest : BaseIntegrationTest() { init { // for VPM diff --git a/src/test/kotlin/functional/TxLimitTest.kt b/src/test/kotlin/functional/TxLimitTest.kt index 975701a..a031fd1 100644 --- a/src/test/kotlin/functional/TxLimitTest.kt +++ b/src/test/kotlin/functional/TxLimitTest.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.TestInstance import testframework.BaseIntegrationTest import testframework.connectNodes import testframework.topUpApmWallet @@ -12,6 +13,7 @@ import testframework.waitUntil import testframework.wrapper.apm.MineRequest import kotlin.test.Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) class TxLimitTest : BaseIntegrationTest() { class NoErrorException(message: String): Exception(message) diff --git a/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt b/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt index db59a81..94fcd49 100644 --- a/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt +++ b/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt @@ -7,12 +7,14 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.TestInstance import testframework.BaseIntegrationTest import testframework.connectNodes import testframework.wrapper.nodecore.Output import testframework.wrapper.nodecore.SendCoinsRequest import kotlin.test.Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) class NodeCoreMempoolSyncTest : BaseIntegrationTest() { override suspend fun setup() = coroutineScope { addNodecore() From 61059d7762a8e12296ecafa6e7565261130f2eca Mon Sep 17 00:00:00 2001 From: Bohdan Vanieiev Date: Mon, 20 Dec 2021 18:19:35 +0200 Subject: [PATCH 05/12] Fix --- .gitignore | 4 +- build.gradle.kts | 22 ++++++- .../testframework/BaseIntegrationTest.kt | 7 +-- .../kotlin/testframework/StdStreamLogger.kt | 13 ++-- .../testframework/wrapper/apm/TestAPM.kt | 2 +- .../testframework/wrapper/btcsq/TestBtcsq.kt | 2 +- .../wrapper/nodecore/Entities.kt | 1 - .../wrapper/nodecore/MiniNode.kt | 61 ++++++++++++------- .../wrapper/nodecore/TestNodecore.kt | 3 +- src/main/resources/log4j2.xml | 2 +- src/test/kotlin/functional/LedgerProofTest.kt | 17 +++--- src/test/kotlin/functional/PopMiningTest.kt | 2 + 12 files changed, 86 insertions(+), 50 deletions(-) diff --git a/.gitignore b/.gitignore index 72c3cef..e061937 100644 --- a/.gitignore +++ b/.gitignore @@ -77,4 +77,6 @@ scripts/certs/ certs/ *.iml -*.prefs \ No newline at end of file +*.prefs + +reports diff --git a/build.gradle.kts b/build.gradle.kts index 4deba88..b23fc41 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,6 +4,7 @@ import com.adarshr.gradle.testlogger.TestLoggerPlugin import com.adarshr.gradle.testlogger.theme.ThemeType plugins { + idea kotlin("jvm") version "1.5.31" id("com.adarshr.test-logger") version "3.1.0" } @@ -18,7 +19,7 @@ repositories { val kotestVersion = "5.0.1" val coroutinesVersion = "1.5.2-native-mt" -val log4jVersion= "2.16.0" +val log4jVersion = "2.16.0" val ktorVersion = "1.6.0" dependencies { @@ -62,6 +63,15 @@ tasks.withType { tasks.withType { useJUnitPlatform() + + reports { + html.required.set(true) + junitXml.required.set(true) + junitXml.apply { + isOutputPerTestCase = true // defaults to false + mergeReruns.set(true) // defaults to false + } + } } plugins.withType { @@ -84,3 +94,13 @@ plugins.withType { logLevel = LogLevel.LIFECYCLE } } + +reporting.baseDir = file("$buildDir/reports") +project.setProperty("testResultsDirName", "$buildDir/test-results") + +tasks.register("showDirs") { + doLast { + logger.quiet(rootDir.toPath().relativize((project.properties["reportsDir"] as File).toPath()).toString()) + logger.quiet(rootDir.toPath().relativize((project.properties["testResultsDir"] as File).toPath()).toString()) + } +} diff --git a/src/main/kotlin/testframework/BaseIntegrationTest.kt b/src/main/kotlin/testframework/BaseIntegrationTest.kt index 178c9ef..8bbdfea 100644 --- a/src/main/kotlin/testframework/BaseIntegrationTest.kt +++ b/src/main/kotlin/testframework/BaseIntegrationTest.kt @@ -28,7 +28,7 @@ abstract class BaseIntegrationTest { val apms = ArrayList() /* empty by default */ val nodecores = ArrayList() /* empty by default */ val btcsqs = ArrayList() /* empty by default */ - val logger = LoggerFactory.getLogger("BaseIntegrationTest") + val logger = LoggerFactory.getLogger("Test") var baseNodecoreRpcPort = (23300) var baseNodecoreP2pPort = (23200) var baseNodecoreHttpPort = (23100) @@ -169,13 +169,10 @@ abstract class BaseIntegrationTest { try { waitUntil(timeout = timeout) { statuses = apms.map { it.http.getMinerInfo().status.isReady } - - // if all getInfo returned same block, - // then we consider syncAll succeeded return@waitUntil statuses.all { it } } } catch (e: TimeoutCancellationException) { - logger.error("syncNodecoreBlocks failed: ${statuses.joinToString { "\n" }}") + logger.error("syncAllApms failed: ${statuses.joinToString { "\n" }}") throw e } } diff --git a/src/main/kotlin/testframework/StdStreamLogger.kt b/src/main/kotlin/testframework/StdStreamLogger.kt index 9c2d71e..7eb89b4 100644 --- a/src/main/kotlin/testframework/StdStreamLogger.kt +++ b/src/main/kotlin/testframework/StdStreamLogger.kt @@ -3,6 +3,7 @@ package testframework import org.testcontainers.containers.output.OutputFrame import java.io.File import java.io.PrintWriter +import java.util.logging.Logger class StdStreamLogger( datadir: File @@ -11,7 +12,6 @@ class StdStreamLogger( private val stderr = File(datadir, "stderr") private val stdoutwriter: PrintWriter private val stderrwriter: PrintWriter - var useConsole = false init { if (!datadir.exists()) { @@ -27,17 +27,16 @@ class StdStreamLogger( stderrwriter = stderr.printWriter() } - fun forward(): (OutputFrame) -> Unit = { + fun forward(logger: org.slf4j.Logger): (OutputFrame) -> Unit = { when (it.type) { OutputFrame.OutputType.STDOUT -> { - if(useConsole) print(it.utf8String) - stdoutwriter.print(it.utf8String) - stdoutwriter.print('\n') + logger.debug(it.utf8String.dropLast(1)) + stdoutwriter.println(it.utf8String) stdoutwriter.flush() } OutputFrame.OutputType.STDERR -> { - if(useConsole) System.err.print(it.utf8String) - stderrwriter.print(it.utf8String) + logger.error(it.utf8String.dropLast(1)) + stderrwriter.println(it.utf8String) stderrwriter.flush() } else -> Unit diff --git a/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt b/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt index a1957e9..64eaa79 100644 --- a/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt +++ b/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt @@ -95,7 +95,7 @@ class TestAPM( suspend fun start() { container.start() - container.followOutput(stdlog.forward()) + container.followOutput(stdlog.forward(logger)) waitForHttpApiAvailability() } diff --git a/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt b/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt index 6003252..e8af043 100644 --- a/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt +++ b/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt @@ -82,7 +82,7 @@ class TestBtcsq( suspend fun start() { container.start() - container.followOutput(stdlog.forward()) + container.followOutput(stdlog.forward(logger)) waitForRpcAvailability() } diff --git a/src/main/kotlin/testframework/wrapper/nodecore/Entities.kt b/src/main/kotlin/testframework/wrapper/nodecore/Entities.kt index 7e50cdf..68b8693 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/Entities.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/Entities.kt @@ -39,7 +39,6 @@ data class NodeInfo( return RpcNodeInfo.newBuilder() .setApplication(application) .setPlatform(platform) - .setAddress(address) .setStartTimestamp(startTimestamp) .setId(id) .setPort(port) diff --git a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt index f71da30..e34985c 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt @@ -12,6 +12,7 @@ import nodecore.api.grpc.RpcEvent import nodecore.api.grpc.RpcNodeInfo import testframework.buildMessage import org.slf4j.LoggerFactory +import testframework.waitUntil import java.io.Closeable import java.io.EOFException import java.io.IOException @@ -150,9 +151,6 @@ private class PeerSocket( } - - - open class MiniNode : Closeable, AutoCloseable { // connected to this node private var socket: PeerSocket? = null @@ -160,6 +158,8 @@ open class MiniNode : Closeable, AutoCloseable { val identity = AtomicLong(0) val metadata: NodeInfo = NodeInfo() + private var nodeAnnouncedBack = AtomicBoolean(false) + fun nextMessageId(): String { return identity.incrementAndGet().toString() } @@ -168,38 +168,49 @@ open class MiniNode : Closeable, AutoCloseable { return socket?.peerName } - suspend fun connect(p: TestNodecore, shouldAnnounce: Boolean = true) { + suspend fun connect(p: TestNodecore) { if (socket != null) { logger.warn("Already connected to ${p.name}, disconnect first") return } - val address = NetworkAddress("127.0.0.1", p.settings.peerPort) - logger.debug("Connecting to ${p.name}") + waitUntil(attempts = 5, delay = 2_000L) { + connectOnce(p) + } + } + + private suspend fun connectOnce(p: TestNodecore): Boolean { try { - val socket = PeerSocket( + val address = NetworkAddress("127.0.0.1", p.settings.peerPort) + logger.debug("Connecting to ${p.name}") + + val socket = aSocket(selectorManager) + .tcp() + .connect(address) + + val peer = PeerSocket( p, - aSocket(selectorManager) - .tcp() - .connect(address) + socket ) { handleMessage(it) } - if (shouldAnnounce) { - val announceMsg = buildMessage(nextMessageId()) { - announce = RpcAnnounce.newBuilder() - .setReply(false) - .setNodeInfo(metadata.toProto()) - .build() - } - - socket.write(announceMsg) + val announceMsg = buildMessage(nextMessageId()) { + announce = RpcAnnounce.newBuilder() + .setReply(false) + .setNodeInfo(metadata.toProto()) + .build() } - this.socket = socket + + peer.write(announceMsg) + + // wait for ANNOUNCE from a node + waitUntil(timeout = 10_000L) { nodeAnnouncedBack.get() } + this.socket = peer + return true } catch (e: Exception) { - logger.error("Unable to connect to ${p.name}") - throw e + logger.error("Unable to connect to ${p.name}: $e") + return false } } @@ -231,6 +242,12 @@ open class MiniNode : Closeable, AutoCloseable { // store stats about received msgs val count = stats.getOrDefault(event.resultsCase.name, 0L) stats[event.resultsCase.name] = count + 1 + + // if this is announce back, then release "connect" + if (event.hasAnnounce()) { + this.nodeAnnouncedBack.set(true) + } + // let user handle msg onEvent(event) } catch (e: Exception) { diff --git a/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt b/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt index 0b14962..a9fb175 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt @@ -70,6 +70,7 @@ class TestNodecore( nodecoreProperties .writeText( """ + bfi.enabled=false network=${settings.network} peer.bootstrap.enabled=false peer.bind.address=127.0.0.1 @@ -88,7 +89,7 @@ class TestNodecore( suspend fun start() { container.start() - container.followOutput(stdlog.forward()) + container.followOutput(stdlog.forward(logger)) waitForRpcConnection() } diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 1fa7e9e..39defda 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -7,7 +7,7 @@ - + diff --git a/src/test/kotlin/functional/LedgerProofTest.kt b/src/test/kotlin/functional/LedgerProofTest.kt index a36980e..3371158 100644 --- a/src/test/kotlin/functional/LedgerProofTest.kt +++ b/src/test/kotlin/functional/LedgerProofTest.kt @@ -27,15 +27,15 @@ private class LedgerProofVerifier : MiniNode() { } @TestInstance(TestInstance.Lifecycle.PER_CLASS) -internal class LedgerProofTest : BaseIntegrationTest() { +class LedgerProofTest : BaseIntegrationTest() { // exists, has VBK - val addr1 = randomAddress() + private val addr1 = randomAddress() // does not exist, has no VBK - val addr2 = randomAddress() - val badAddr = "Not An Address" + private val addr2 = randomAddress() + private val badAddr = "Not An Address" - fun addr2bytes(addr: Address): ByteString { + private fun addr2bytes(addr: Address): ByteString { return ByteStringAddressUtility.createProperByteStringAutomatically(addr.toString()) } @@ -47,8 +47,7 @@ internal class LedgerProofTest : BaseIntegrationTest() { override suspend fun runTest() { logger.info("Running LedgerProof test!") - nodecores[0].stdlog.useConsole = true - + delay(5_000L) val n = LedgerProofVerifier() n.connect(nodecores[0]) val peerinfo = nodecores[0].http.getPeerInfo() @@ -81,7 +80,7 @@ internal class LedgerProofTest : BaseIntegrationTest() { checkProofOfNonExistence(list[1]) } - fun checkProofOfExistence(e: LedgerProofResult) { + private fun checkProofOfExistence(e: LedgerProofResult) { e.result shouldBe Status.ADDRESS_EXISTS // throws if proof is invalid @@ -92,7 +91,7 @@ internal class LedgerProofTest : BaseIntegrationTest() { proof.ledgerAddress shouldBe addr1.toString() } - fun checkProofOfNonExistence(e: LedgerProofResult) { + private fun checkProofOfNonExistence(e: LedgerProofResult) { e.result shouldBe Status.ADDRESS_DOES_NOT_EXIST // throws if proof is invalid diff --git a/src/test/kotlin/functional/PopMiningTest.kt b/src/test/kotlin/functional/PopMiningTest.kt index b04641b..c2295c6 100644 --- a/src/test/kotlin/functional/PopMiningTest.kt +++ b/src/test/kotlin/functional/PopMiningTest.kt @@ -69,6 +69,8 @@ class PopMiningTest : BaseIntegrationTest() { vbtc.start() vbtc.mineUntilPopEnabled() + logger.info("BTCSQ is at height when POP is enabled") + val apm = addAPM(nodecores[0], listOf(vbtc)) apm.start() } From 0b070abdfed7f3ef2e6546e2d952255232afb556 Mon Sep 17 00:00:00 2001 From: Bohdan Vanieiev Date: Mon, 20 Dec 2021 21:33:39 +0200 Subject: [PATCH 06/12] Use bridge networking --- .github/workflows/main.yml | 1 + .../kotlin/testframework/BaseJsonRpcApi.kt | 2 +- .../testframework/BtcPluginInterface.kt | 1 + .../kotlin/testframework/StdStreamLogger.kt | 24 ++++++-- src/main/kotlin/testframework/Util.kt | 19 +++++- .../testframework/wrapper/apm/TestAPM.kt | 30 +++++++--- .../testframework/wrapper/btcsq/TestBtcsq.kt | 35 ++++++++--- .../wrapper/nodecore/MiniNode.kt | 9 +-- .../wrapper/nodecore/TestNodecore.kt | 60 ++++++++++++------- src/main/resources/log4j2.xml | 2 +- src/test/kotlin/functional/ExampleApmTest.kt | 2 +- src/test/kotlin/functional/LedgerProofTest.kt | 1 - 12 files changed, 131 insertions(+), 55 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1d6e61..f36327c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,6 +16,7 @@ jobs: INT_NODECORE_VERSION: "0.4.13-rc.11" INT_APM_VERSION: "0.4.13-rc.11" INT_BTCSQ_VERSION: "master-47363b0" + INT_LOG_LEVEL: "DEBUG" steps: - uses: actions/checkout@v2 diff --git a/src/main/kotlin/testframework/BaseJsonRpcApi.kt b/src/main/kotlin/testframework/BaseJsonRpcApi.kt index 715bbc4..78a3425 100644 --- a/src/main/kotlin/testframework/BaseJsonRpcApi.kt +++ b/src/main/kotlin/testframework/BaseJsonRpcApi.kt @@ -21,7 +21,7 @@ open class BaseJsonRpcApi( suffix: String = "", username: String = "", password: String = "", - timeoutMillis: Long = 0 + timeoutMillis: Long = 10_000L ) { protected val apiConfig = HttpApiConfig("http://${host}:${port}/${suffix}") protected val httpClient = createHttpClient(HttpAuthConfig(username, password), timeoutMillis = timeoutMillis) diff --git a/src/main/kotlin/testframework/BtcPluginInterface.kt b/src/main/kotlin/testframework/BtcPluginInterface.kt index d9313a0..7617127 100644 --- a/src/main/kotlin/testframework/BtcPluginInterface.kt +++ b/src/main/kotlin/testframework/BtcPluginInterface.kt @@ -6,6 +6,7 @@ interface BtcPluginInterface { fun username(): String fun password(): String fun id(): Long + fun host(): String fun port(): Int fun network(): String fun payoutDelay(): Int diff --git a/src/main/kotlin/testframework/StdStreamLogger.kt b/src/main/kotlin/testframework/StdStreamLogger.kt index 7eb89b4..0ae9b88 100644 --- a/src/main/kotlin/testframework/StdStreamLogger.kt +++ b/src/main/kotlin/testframework/StdStreamLogger.kt @@ -1,9 +1,9 @@ package testframework +import org.slf4j.Logger import org.testcontainers.containers.output.OutputFrame import java.io.File import java.io.PrintWriter -import java.util.logging.Logger class StdStreamLogger( datadir: File @@ -27,16 +27,28 @@ class StdStreamLogger( stderrwriter = stderr.printWriter() } - fun forward(logger: org.slf4j.Logger): (OutputFrame) -> Unit = { + fun forward(logger: Logger, addEndl: Boolean = false): (OutputFrame) -> Unit = { when (it.type) { OutputFrame.OutputType.STDOUT -> { - logger.debug(it.utf8String.dropLast(1)) - stdoutwriter.println(it.utf8String) + if (addEndl) { + logger.debug(it.utf8String) + stdoutwriter.println(it.utf8String) + } else { + logger.debug(it.utf8String.dropLast(1)) + stdoutwriter.print(it.utf8String) + } + stdoutwriter.flush() } OutputFrame.OutputType.STDERR -> { - logger.error(it.utf8String.dropLast(1)) - stderrwriter.println(it.utf8String) + if (addEndl) { + logger.error(it.utf8String) + stdoutwriter.println(it.utf8String) + } else { + logger.error(it.utf8String.dropLast(1)) + stdoutwriter.print(it.utf8String) + } + stderrwriter.flush() } else -> Unit diff --git a/src/main/kotlin/testframework/Util.kt b/src/main/kotlin/testframework/Util.kt index 0c60cef..0ff5e42 100644 --- a/src/main/kotlin/testframework/Util.kt +++ b/src/main/kotlin/testframework/Util.kt @@ -16,8 +16,9 @@ import testframework.wrapper.nodecore.SubmitPopRequest import testframework.wrapper.nodecore.TestNodecore import java.net.ServerSocket import java.security.KeyPair +import java.security.SecureRandom import java.util.concurrent.TimeoutException - +import kotlin.random.Random fun isPortAvailable(port: Int): Boolean { try { @@ -31,11 +32,18 @@ fun isPortAvailable(port: Int): Boolean { return false } +fun getNextAvailablePort(basePort: Int): Int { + var port = basePort + while (!isPortAvailable(port++)) { + } + return port +} + suspend fun connectNodes(a: TestNodecore, b: TestNodecore) { a.http.addNode( listOf( Endpoint( - address = "127.0.0.1", + address = b.getAddress(), port = b.settings.peerPort ) ) @@ -62,7 +70,12 @@ fun buildMessage( .build() // sleep until the predicate resolves to be True -suspend fun waitUntil(attempts: Long = Long.MAX_VALUE, timeout: Long = 60_000L, delay: Long = 1_000L, predicate: suspend () -> Boolean) { +suspend fun waitUntil( + attempts: Long = Long.MAX_VALUE, + timeout: Long = 60_000L, + delay: Long = 1_000L, + predicate: suspend () -> Boolean +) { var attempt = 0 val timeEnd = System.currentTimeMillis() + timeout while (attempt++ < attempts && System.currentTimeMillis() < timeEnd) { diff --git a/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt b/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt index 64eaa79..2234c64 100644 --- a/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt +++ b/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt @@ -31,16 +31,28 @@ class TestAPM( val datadir = File(settings.baseDir, name) val stdlog = StdStreamLogger(datadir) val container = KGenericContainer("veriblock/altchain-pop-miner:$version") - .withNetworkMode("host") .withNetworkAliases(name) .withFileSystemBind(datadir.absolutePath, "/data", BindMode.READ_WRITE) .withCreateContainerCmdModifier { it.withTty(true) } .withEnv("APM_LOG_LEVEL", "DEBUG") - .withEnv("APM_CONSOLE_LOG_LEVEL", "DEBUG") + .withEnv("APM_CONSOLE_LOG_LEVEL", "INFO") + fun getAddress(): String { + // we can take IP only on running containers + assert(container.isRunning) + return container + .containerInfo + .networkSettings + .networks + .entries + .first() + .value + .ipAddress!! + } + val applicationConf = File(datadir, "application.conf") - val http = ApmHttpApi(name, container.host, settings.httpPort) + lateinit var http: ApmHttpApi val vbkAddress by lazy { runBlocking { http.getMinerInfo().vbkAddress @@ -55,7 +67,7 @@ class TestAPM( pluginKey: btc id: ${it.id()} name: "${it.name()}" - host: "http://127.0.0.1:${it.port()}" + host: "http://${it.host()}:${it.port()}" auth: { username: "${it.username()}" password: "${it.password()}" @@ -78,9 +90,10 @@ class TestAPM( feePerByte: 1000 maxFee: 10000000 api { + host: 0.0.0.0 port: ${settings.httpPort} } - connectDirectlyTo: ["127.0.0.1:${settings.nodecore.settings.peerPort}"] + connectDirectlyTo: ["${settings.nodecore.getAddress()}:${settings.nodecore.settings.peerPort}"] network: ${settings.nodecore.settings.network} dataDir: /data progPowGenesis: true @@ -95,7 +108,10 @@ class TestAPM( suspend fun start() { container.start() - container.followOutput(stdlog.forward(logger)) + container.followOutput(stdlog.forward(logger, true)) + logger.info("IP: ${getAddress()}") + http = ApmHttpApi(name, getAddress(), settings.httpPort) + waitForHttpApiAvailability() } @@ -109,7 +125,7 @@ class TestAPM( } private suspend fun waitForHttpApiAvailability() { - waitUntil(timeout = 30_000L, delay = 2_000L) { + waitUntil(timeout = 60_000L, delay = 5_000L) { try { http.getMinerInfo() return@waitUntil true diff --git a/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt b/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt index e8af043..4e1ff49 100644 --- a/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt +++ b/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt @@ -21,20 +21,25 @@ class TestBtcsq( val stdlog = StdStreamLogger(datadir) val container = KGenericContainer("veriblock/btcsq:$version") .withNetworkAliases(name) - .withNetworkMode("host") .withFileSystemBind(datadir.absolutePath, "/home/btcsq/.btcsq", BindMode.READ_WRITE) .withCommand("btcsqd") + fun getAddress(): String { + // we can take IP only on running containers + assert(container.isRunning) + return container + .containerInfo + .networkSettings + .networks + .entries + .first() + .value + .ipAddress!! + } + val conf = File(datadir, "btcsq.conf") - val rpc = BtcsqApi( - name, - container.host, - settings.rpcPort, - settings.username, - settings.password, - 60000 - ) + lateinit var rpc: BtcsqApi init { @@ -83,6 +88,17 @@ class TestBtcsq( suspend fun start() { container.start() container.followOutput(stdlog.forward(logger)) + logger.info("IP: ${getAddress()}") + + rpc = BtcsqApi( + name, + getAddress(), + settings.rpcPort, + settings.username, + settings.password, + 60000 + ) + waitForRpcAvailability() } @@ -122,6 +138,7 @@ class TestBtcsq( override fun username(): String = settings.username override fun password(): String = settings.password override fun id(): Long = 0x3ae6ca26ff + override fun host(): String = getAddress() override fun port(): Int = settings.rpcPort override fun network(): String = settings.bitcoinNetwork override fun payoutDelay(): Int = 150 diff --git a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt index e34985c..a7af1cb 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt @@ -181,17 +181,14 @@ open class MiniNode : Closeable, AutoCloseable { private suspend fun connectOnce(p: TestNodecore): Boolean { try { - val address = NetworkAddress("127.0.0.1", p.settings.peerPort) + val address = NetworkAddress(p.getAddress(), p.settings.peerPort) logger.debug("Connecting to ${p.name}") val socket = aSocket(selectorManager) .tcp() .connect(address) - val peer = PeerSocket( - p, - socket - ) { + val peer = PeerSocket(p, socket) { handleMessage(it) } @@ -205,7 +202,7 @@ open class MiniNode : Closeable, AutoCloseable { peer.write(announceMsg) // wait for ANNOUNCE from a node - waitUntil(timeout = 10_000L) { nodeAnnouncedBack.get() } + waitUntil(timeout = 5_000L) { nodeAnnouncedBack.get() } this.socket = peer return true } catch (e: Exception) { diff --git a/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt b/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt index a9fb175..0cef608 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/TestNodecore.kt @@ -1,12 +1,15 @@ package testframework.wrapper.nodecore import io.grpc.Deadline +import io.grpc.ManagedChannel import io.grpc.ManagedChannelBuilder import kotlinx.coroutines.delay import kotlinx.coroutines.withTimeout import nodecore.api.grpc.AdminGrpc import org.slf4j.LoggerFactory import org.testcontainers.containers.BindMode +import org.testcontainers.containers.wait.strategy.Wait +import org.testcontainers.containers.wait.strategy.WaitStrategy import testframework.KGenericContainer import testframework.StdStreamLogger import java.io.Closeable @@ -27,8 +30,7 @@ class NodecoreSettings( class TestNodecore( val settings: NodecoreSettings, version: String, -) : Closeable, AutoCloseable -{ +) : Closeable, AutoCloseable { val name = "nodecore${settings.index}" private val logger = LoggerFactory.getLogger(name) val datadir = File(settings.baseDir, name) @@ -38,18 +40,28 @@ class TestNodecore( val container = KGenericContainer("veriblock/nodecore:$version") .withNetworkAliases(name) - .withNetworkMode("host") .withFileSystemBind(datadir.absolutePath, "/data", BindMode.READ_WRITE) .withEnv("NODECORE_LOG_LEVEL", "DEBUG") .withEnv("NODECORE_CONSOLE_LOG_LEVEL", "DEBUG") + .waitingFor(Wait.forLogMessage(".*NodeCore operating state is now: Running.*", 1)) + + fun getAddress(): String { + // we can take IP only on running containers + assert(container.isRunning) + return container + .containerInfo + .networkSettings + .networks + .entries + .first() + .value + .ipAddress!! + } // Accessor for Admin HTTP API - val http = NodeHttpApi(name, "127.0.0.1", settings.httpPort) - val rpc: AdminGrpc.AdminBlockingStub - private val channel = ManagedChannelBuilder - .forAddress("127.0.0.1", settings.rpcPort) - .usePlaintext() - .build() + lateinit var http: NodeHttpApi + lateinit var rpc: AdminGrpc.AdminBlockingStub + private lateinit var channel: ManagedChannel init { datadir.mkdirs() @@ -59,13 +71,6 @@ class TestNodecore( nodecoreProperties.setReadable(true, false) nodecoreProperties.setWritable(true, false) - // setup RPC channel - rpc = AdminGrpc - .newBlockingStub(channel) - .withMaxInboundMessageSize(20 * 1024 * 1024) - .withMaxOutboundMessageSize(20 * 1024 * 1024) - .withDeadline(Deadline.after(rpcTimeout, TimeUnit.MILLISECONDS)) - // write nodecode.properties nodecoreProperties .writeText( @@ -73,13 +78,13 @@ class TestNodecore( bfi.enabled=false network=${settings.network} peer.bootstrap.enabled=false - peer.bind.address=127.0.0.1 + peer.bind.address=0.0.0.0 peer.bind.port=${settings.peerPort} peer.share.platform=true peer.share.myAddress=true - rpc.bind.address=127.0.0.1 + rpc.bind.address=0.0.0.0 rpc.bind.port=${settings.rpcPort} - http.api.bind.address=127.0.0.1 + http.api.bind.address=0.0.0.0 http.api.bind.port=${settings.httpPort} regtest.progpow.height=${settings.progpowHeight} regtest.progpow.start.time=${settings.progpowTime} @@ -90,6 +95,21 @@ class TestNodecore( suspend fun start() { container.start() container.followOutput(stdlog.forward(logger)) + logger.info("IP: ${getAddress()}") + + channel = ManagedChannelBuilder + .forAddress(getAddress(), settings.rpcPort) + .usePlaintext() + .build() + + // setup RPC channel + rpc = AdminGrpc + .newBlockingStub(channel) + .withMaxInboundMessageSize(20 * 1024 * 1024) + .withMaxOutboundMessageSize(20 * 1024 * 1024) + .withDeadline(Deadline.after(rpcTimeout, TimeUnit.MILLISECONDS)) + + http = NodeHttpApi(name, getAddress(), settings.httpPort) waitForRpcConnection() } @@ -101,7 +121,7 @@ class TestNodecore( fun stop() { // don't forget to shutdown channel - if(!channel.isShutdown) { + if (!channel.isShutdown) { channel.shutdownNow() } container.stop() diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 39defda..dd626a4 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -1,7 +1,7 @@ - + diff --git a/src/test/kotlin/functional/ExampleApmTest.kt b/src/test/kotlin/functional/ExampleApmTest.kt index dafa470..4c70d80 100644 --- a/src/test/kotlin/functional/ExampleApmTest.kt +++ b/src/test/kotlin/functional/ExampleApmTest.kt @@ -8,7 +8,7 @@ import testframework.BtcPluginInterface import kotlin.test.Test @TestInstance(TestInstance.Lifecycle.PER_CLASS) -internal class ExampleApmTest : BaseIntegrationTest() { +class ExampleApmTest : BaseIntegrationTest() { override suspend fun runTest() { logger.info("Running ExampleApmTest test!") diff --git a/src/test/kotlin/functional/LedgerProofTest.kt b/src/test/kotlin/functional/LedgerProofTest.kt index 3371158..db9ba00 100644 --- a/src/test/kotlin/functional/LedgerProofTest.kt +++ b/src/test/kotlin/functional/LedgerProofTest.kt @@ -47,7 +47,6 @@ class LedgerProofTest : BaseIntegrationTest() { override suspend fun runTest() { logger.info("Running LedgerProof test!") - delay(5_000L) val n = LedgerProofVerifier() n.connect(nodecores[0]) val peerinfo = nodecores[0].http.getPeerInfo() From 21422a27164ea7410d68fec3c26181556f7a6c55 Mon Sep 17 00:00:00 2001 From: Bohdan Vanieiev Date: Tue, 21 Dec 2021 17:51:54 +0200 Subject: [PATCH 07/12] Update --- README.md | 11 +++++++++++ .../kotlin/testframework/wrapper/nodecore/MiniNode.kt | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 58e7c84..1656efe 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,17 @@ To run all tests: `./gradlew build test` Each test uses testcontainers to start docker images of NodeCore, APM, BTCSQ (and other stuff) to test everything end-to-end. +## Environment variables + +Tests will use either default versions (see [BaseIntegrationTest.kt](./src/main/kotlin/testframework/BaseIntegrationTest.kt)) or specified in following environment variables: + +- INT_NODECORE_VERSION - veriblock version (https://hub.docker.com/r/veriblock/nodecore) +- INT_APM_VERSION - APM version (https://hub.docker.com/r/veriblock/altchain-pop-miner) +- INT_BTCSQ_VERSION - BTCSQ version (https://hub.docker.com/r/veriblock/btcsq) +- INT_LOG_LEVEL: "DEBUG" + +Example: [ci.yml](./.github/workflows/main.yml) + ## Development guide Each service (APM/NC/BTCSQ) is organized into "wrapper" - [./src/main/kotlin/testframework/wrapper](./src/main/kotlin/testframework/wrapper). diff --git a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt index a7af1cb..1213fbd 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt @@ -189,7 +189,7 @@ open class MiniNode : Closeable, AutoCloseable { .connect(address) val peer = PeerSocket(p, socket) { - handleMessage(it) + handleMessage(it, p.name) } val announceMsg = buildMessage(nextMessageId()) { @@ -232,10 +232,10 @@ open class MiniNode : Closeable, AutoCloseable { socket.write(e) } - private suspend fun handleMessage(buf: ByteArray) { + private suspend fun handleMessage(buf: ByteArray, name: String) { try { val event = RpcEvent.parseFrom(buf) - logger.debug("${peerName()} --p2p--> ${event.resultsCase.name}") + logger.debug("$name --p2p--> ${event.resultsCase.name}") // store stats about received msgs val count = stats.getOrDefault(event.resultsCase.name, 0L) stats[event.resultsCase.name] = count + 1 @@ -248,7 +248,7 @@ open class MiniNode : Closeable, AutoCloseable { // let user handle msg onEvent(event) } catch (e: Exception) { - logger.error("${peerName()} misbehaved! Can't parse Event of size ${buf.size}.") + logger.error("$name misbehaved! Can't parse Event of size ${buf.size}.") close() return } From 5056fa385ae180df46102412294ba75630ef7c3b Mon Sep 17 00:00:00 2001 From: Bohdan Vanieiev Date: Wed, 22 Dec 2021 12:50:08 +0200 Subject: [PATCH 08/12] Bump version --- .github/workflows/main.yml | 4 ++-- .../testframework/BaseIntegrationTest.kt | 8 +++++-- .../kotlin/testframework/BaseJsonRpcApi.kt | 5 +---- src/main/kotlin/testframework/Util.kt | 5 ++++- .../testframework/wrapper/apm/ApmHttpApi.kt | 7 ++----- .../testframework/wrapper/apm/TestAPM.kt | 2 ++ .../testframework/wrapper/btcsq/TestBtcsq.kt | 2 ++ .../wrapper/nodecore/MiniNode.kt | 14 ++++++++++--- src/main/resources/junit-platform.properties | 2 +- src/test/kotlin/functional/ExampleApmTest.kt | 1 - src/test/kotlin/functional/ExampleTest.kt | 3 +-- src/test/kotlin/functional/LedgerProofTest.kt | 21 +++++++++++++++---- src/test/kotlin/functional/PopMiningTest.kt | 1 - src/test/kotlin/functional/TxLimitTest.kt | 1 - .../nodecore/NodeCoreMempoolSyncTest.kt | 6 +++--- 15 files changed, 52 insertions(+), 30 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f36327c..729d1c8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,8 +13,8 @@ jobs: runs-on: ubuntu-latest env: # specify versions to test - INT_NODECORE_VERSION: "0.4.13-rc.11" - INT_APM_VERSION: "0.4.13-rc.11" + INT_NODECORE_VERSION: "0.4.13-rc.12.dev.1" + INT_APM_VERSION: "0.4.13-rc.12.dev.1" INT_BTCSQ_VERSION: "master-47363b0" INT_LOG_LEVEL: "DEBUG" diff --git a/src/main/kotlin/testframework/BaseIntegrationTest.kt b/src/main/kotlin/testframework/BaseIntegrationTest.kt index 8bbdfea..9ac1b4b 100644 --- a/src/main/kotlin/testframework/BaseIntegrationTest.kt +++ b/src/main/kotlin/testframework/BaseIntegrationTest.kt @@ -10,8 +10,8 @@ import testframework.wrapper.nodecore.TestNodecore import org.slf4j.LoggerFactory import testframework.wrapper.btcsq.TestBtcsq -val nodecoreVersion = System.getenv("INT_NODECORE_VERSION") ?: "0.4.13-rc.11" -val apmVersion = System.getenv("INT_APM_VERSION") ?: "0.4.13-rc.11" +val nodecoreVersion = System.getenv("INT_NODECORE_VERSION") ?: "0.4.13-rc.12.dev.1" +val apmVersion = System.getenv("INT_APM_VERSION") ?: "0.4.13-rc.12.dev.1" val btcsqVersion = System.getenv("INT_BTCSQ_VERSION") ?: "master-47363b0" enum class TestStatus(val state: String) { @@ -114,6 +114,10 @@ abstract class BaseIntegrationTest { try { logger.info("Setting base dir ${baseDir.absolutePath}") + Runtime.getRuntime().addShutdownHook(Thread { + shutdown() + }) + setup() runTest() status = TestStatus.PASSED diff --git a/src/main/kotlin/testframework/BaseJsonRpcApi.kt b/src/main/kotlin/testframework/BaseJsonRpcApi.kt index 78a3425..d31c5ba 100644 --- a/src/main/kotlin/testframework/BaseJsonRpcApi.kt +++ b/src/main/kotlin/testframework/BaseJsonRpcApi.kt @@ -23,6 +23,7 @@ open class BaseJsonRpcApi( password: String = "", timeoutMillis: Long = 10_000L ) { + val logger = LoggerFactory.getLogger(name) protected val apiConfig = HttpApiConfig("http://${host}:${port}/${suffix}") protected val httpClient = createHttpClient(HttpAuthConfig(username, password), timeoutMillis = timeoutMillis) @@ -38,8 +39,4 @@ open class BaseJsonRpcApi( logger.debug("$name --jsonrpc--> $response") return response.handle() }.handle() - - companion object { - val logger = LoggerFactory.getLogger("BaseJsonRpcApi") - } } diff --git a/src/main/kotlin/testframework/Util.kt b/src/main/kotlin/testframework/Util.kt index 0ff5e42..c2e4e5d 100644 --- a/src/main/kotlin/testframework/Util.kt +++ b/src/main/kotlin/testframework/Util.kt @@ -74,6 +74,7 @@ suspend fun waitUntil( attempts: Long = Long.MAX_VALUE, timeout: Long = 60_000L, delay: Long = 1_000L, + message: String = "", predicate: suspend () -> Boolean ) { var attempt = 0 @@ -87,7 +88,9 @@ suspend fun waitUntil( } // print the cause of failure - val s: StringBuilder = StringBuilder().append("waitUntil failed! ") + val s: StringBuilder = StringBuilder().append("waitUntil failed!\n") + s.append(message) + s.append("\n") if (attempt >= attempts) { s.append("Predicate not true after $attempt attempts") } else if (System.currentTimeMillis() >= timeEnd) { diff --git a/src/main/kotlin/testframework/wrapper/apm/ApmHttpApi.kt b/src/main/kotlin/testframework/wrapper/apm/ApmHttpApi.kt index 7a52f2c..21d1a37 100644 --- a/src/main/kotlin/testframework/wrapper/apm/ApmHttpApi.kt +++ b/src/main/kotlin/testframework/wrapper/apm/ApmHttpApi.kt @@ -8,6 +8,8 @@ import io.ktor.http.* import org.slf4j.LoggerFactory class ApmHttpApi(val name: String, _host: String, _port: Int) { + val logger = LoggerFactory.getLogger(name) + data class MinerInfoResponse( val vbkAddress: String, val vbkBalance: Long, @@ -67,9 +69,4 @@ class ApmHttpApi(val name: String, _host: String, _port: Int) { logger.debug("$name --http--> $ret") return ret } - - - companion object { - val logger = LoggerFactory.getLogger("ApmHttpApi") - } } diff --git a/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt b/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt index 2234c64..a188545 100644 --- a/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt +++ b/src/main/kotlin/testframework/wrapper/apm/TestAPM.kt @@ -8,6 +8,7 @@ import testframework.waitUntil import testframework.wrapper.nodecore.TestNodecore import org.slf4j.LoggerFactory import org.testcontainers.containers.BindMode +import org.testcontainers.containers.wait.strategy.Wait import java.io.Closeable import java.io.File @@ -36,6 +37,7 @@ class TestAPM( .withCreateContainerCmdModifier { it.withTty(true) } .withEnv("APM_LOG_LEVEL", "DEBUG") .withEnv("APM_CONSOLE_LOG_LEVEL", "INFO") + .waitingFor(Wait.forLogMessage(".*Starting miner.*", 1)) fun getAddress(): String { diff --git a/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt b/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt index 4e1ff49..ec8a714 100644 --- a/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt +++ b/src/main/kotlin/testframework/wrapper/btcsq/TestBtcsq.kt @@ -7,6 +7,7 @@ import testframework.KGenericContainer import testframework.waitUntil import org.slf4j.LoggerFactory import org.testcontainers.containers.BindMode +import org.testcontainers.containers.wait.strategy.Wait import java.io.Closeable import java.io.File @@ -23,6 +24,7 @@ class TestBtcsq( .withNetworkAliases(name) .withFileSystemBind(datadir.absolutePath, "/home/btcsq/.btcsq", BindMode.READ_WRITE) .withCommand("btcsqd") + .waitingFor(Wait.forLogMessage(".*tree best height =.*", 3)) fun getAddress(): String { // we can take IP only on running containers diff --git a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt index 1213fbd..46e2792 100644 --- a/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt +++ b/src/main/kotlin/testframework/wrapper/nodecore/MiniNode.kt @@ -174,11 +174,17 @@ open class MiniNode : Closeable, AutoCloseable { return } - waitUntil(attempts = 5, delay = 2_000L) { + waitUntil(attempts = 5, delay = 2_000L, message = "Can not connect to ${p.name}") { connectOnce(p) } } + suspend fun disconnect() { + if(this.socket?.isRunning() == true) { + this.socket?.socket?.close() + } + } + private suspend fun connectOnce(p: TestNodecore): Boolean { try { val address = NetworkAddress(p.getAddress(), p.settings.peerPort) @@ -192,7 +198,7 @@ open class MiniNode : Closeable, AutoCloseable { handleMessage(it, p.name) } - val announceMsg = buildMessage(nextMessageId()) { + val announceMsg = buildMessage("0") { announce = RpcAnnounce.newBuilder() .setReply(false) .setNodeInfo(metadata.toProto()) @@ -202,7 +208,9 @@ open class MiniNode : Closeable, AutoCloseable { peer.write(announceMsg) // wait for ANNOUNCE from a node - waitUntil(timeout = 5_000L) { nodeAnnouncedBack.get() } + waitUntil(timeout = 5_000L, message = "${p.name} did not ANNOUNCE back") { + nodeAnnouncedBack.get() + } this.socket = peer return true } catch (e: Exception) { diff --git a/src/main/resources/junit-platform.properties b/src/main/resources/junit-platform.properties index e6d55f8..2dd4834 100644 --- a/src/main/resources/junit-platform.properties +++ b/src/main/resources/junit-platform.properties @@ -1 +1 @@ -junit.jupiter.testinstance.lifecycle.default = per_class \ No newline at end of file +#junit.jupiter.testinstance.lifecycle.default = per_class \ No newline at end of file diff --git a/src/test/kotlin/functional/ExampleApmTest.kt b/src/test/kotlin/functional/ExampleApmTest.kt index 4c70d80..369a376 100644 --- a/src/test/kotlin/functional/ExampleApmTest.kt +++ b/src/test/kotlin/functional/ExampleApmTest.kt @@ -7,7 +7,6 @@ import testframework.BaseIntegrationTest import testframework.BtcPluginInterface import kotlin.test.Test -@TestInstance(TestInstance.Lifecycle.PER_CLASS) class ExampleApmTest : BaseIntegrationTest() { override suspend fun runTest() { logger.info("Running ExampleApmTest test!") diff --git a/src/test/kotlin/functional/ExampleTest.kt b/src/test/kotlin/functional/ExampleTest.kt index 92d39d7..45cf283 100644 --- a/src/test/kotlin/functional/ExampleTest.kt +++ b/src/test/kotlin/functional/ExampleTest.kt @@ -22,8 +22,7 @@ private class ExampleMiniNode : MiniNode() { } } -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -internal class ExampleTest : BaseIntegrationTest() { +class ExampleTest : BaseIntegrationTest() { override suspend fun setup() = coroutineScope { addNodecore() addNodecore() diff --git a/src/test/kotlin/functional/LedgerProofTest.kt b/src/test/kotlin/functional/LedgerProofTest.kt index db9ba00..acfd744 100644 --- a/src/test/kotlin/functional/LedgerProofTest.kt +++ b/src/test/kotlin/functional/LedgerProofTest.kt @@ -15,6 +15,7 @@ import testframework.wrapper.nodecore.MiniNode import kotlin.test.Test import org.veriblock.extensions.ledger.LedgerProofWithContext import org.veriblock.sdk.models.Address +import kotlin.test.fail private class LedgerProofVerifier : MiniNode() { var reply: RpcLedgerProofReply? = null @@ -26,7 +27,6 @@ private class LedgerProofVerifier : MiniNode() { } } -@TestInstance(TestInstance.Lifecycle.PER_CLASS) class LedgerProofTest : BaseIntegrationTest() { // exists, has VBK private val addr1 = randomAddress() @@ -44,16 +44,26 @@ class LedgerProofTest : BaseIntegrationTest() { nc.start() } + private suspend fun ensureMiniNodeIsConnected() { + val info = nodecores[0].http.getPeerInfo() + if (info.connectedNodes.size != 1) { + logger.error(info.toString()) + fail() + } + } + override suspend fun runTest() { logger.info("Running LedgerProof test!") + delay(5_000) val n = LedgerProofVerifier() n.connect(nodecores[0]) - val peerinfo = nodecores[0].http.getPeerInfo() - peerinfo.connectedNodes shouldHaveSize 1 + ensureMiniNodeIsConnected() nodecores[0].http.generateBlocks(100, addr1.toString()) + ensureMiniNodeIsConnected() + val req = RpcEvent.newBuilder() .setLedgerProofRequest( RpcLedgerProofRequest.newBuilder() @@ -65,8 +75,11 @@ class LedgerProofTest : BaseIntegrationTest() { .build() n.sendEvent(req) + + ensureMiniNodeIsConnected() + // wait until reply is received - waitUntil { n.reply != null } + waitUntil(message = "Did not get reply for LedgerProofRequest") { n.reply != null } val reply = n.reply!! logger.debug(reply.toString()) diff --git a/src/test/kotlin/functional/PopMiningTest.kt b/src/test/kotlin/functional/PopMiningTest.kt index c2295c6..7e5e2a7 100644 --- a/src/test/kotlin/functional/PopMiningTest.kt +++ b/src/test/kotlin/functional/PopMiningTest.kt @@ -17,7 +17,6 @@ import org.veriblock.sdk.models.Address import org.veriblock.sdk.services.SerializeDeserializeService import java.security.Security -@TestInstance(TestInstance.Lifecycle.PER_CLASS) class PopMiningTest : BaseIntegrationTest() { init { // for VPM diff --git a/src/test/kotlin/functional/TxLimitTest.kt b/src/test/kotlin/functional/TxLimitTest.kt index a031fd1..787dcdd 100644 --- a/src/test/kotlin/functional/TxLimitTest.kt +++ b/src/test/kotlin/functional/TxLimitTest.kt @@ -13,7 +13,6 @@ import testframework.waitUntil import testframework.wrapper.apm.MineRequest import kotlin.test.Test -@TestInstance(TestInstance.Lifecycle.PER_CLASS) class TxLimitTest : BaseIntegrationTest() { class NoErrorException(message: String): Exception(message) diff --git a/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt b/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt index 94fcd49..1bfb657 100644 --- a/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt +++ b/src/test/kotlin/functional/nodecore/NodeCoreMempoolSyncTest.kt @@ -14,7 +14,6 @@ import testframework.wrapper.nodecore.Output import testframework.wrapper.nodecore.SendCoinsRequest import kotlin.test.Test -@TestInstance(TestInstance.Lifecycle.PER_CLASS) class NodeCoreMempoolSyncTest : BaseIntegrationTest() { override suspend fun setup() = coroutineScope { addNodecore() @@ -82,8 +81,9 @@ class NodeCoreMempoolSyncTest : BaseIntegrationTest() { nodecores[0].http.getPendingTransactions().transactions[0].txId shouldBe txId // Add a new node and connect it to the network. It should get the pending transactions too - addNodecore().start() - connectNodes(nodecores[1], nodecores[2]) + val nc = addNodecore() + nc.start() + connectNodes(nodecores[1], nc) syncAllNodecores(nodecores) } From b0d4f955e444c6095e8697162515dc731e4cfda3 Mon Sep 17 00:00:00 2001 From: Aleksa Milosevic Date: Wed, 13 Apr 2022 19:10:19 +0200 Subject: [PATCH 09/12] Update BaseIntegrationTest.kt --- src/main/kotlin/testframework/BaseIntegrationTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/testframework/BaseIntegrationTest.kt b/src/main/kotlin/testframework/BaseIntegrationTest.kt index 9ac1b4b..817fb08 100644 --- a/src/main/kotlin/testframework/BaseIntegrationTest.kt +++ b/src/main/kotlin/testframework/BaseIntegrationTest.kt @@ -10,8 +10,8 @@ import testframework.wrapper.nodecore.TestNodecore import org.slf4j.LoggerFactory import testframework.wrapper.btcsq.TestBtcsq -val nodecoreVersion = System.getenv("INT_NODECORE_VERSION") ?: "0.4.13-rc.12.dev.1" -val apmVersion = System.getenv("INT_APM_VERSION") ?: "0.4.13-rc.12.dev.1" +val nodecoreVersion = System.getenv("INT_NODECORE_VERSION") ?: "0.4.13-rc.14" +val apmVersion = System.getenv("INT_APM_VERSION") ?: "0.4.13-rc.14" val btcsqVersion = System.getenv("INT_BTCSQ_VERSION") ?: "master-47363b0" enum class TestStatus(val state: String) { From cd15335323bad363120a2bc672acd3a8730e0ce8 Mon Sep 17 00:00:00 2001 From: Aleksa Milosevic Date: Wed, 13 Apr 2022 19:10:45 +0200 Subject: [PATCH 10/12] Bump version --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 729d1c8..512edd9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,8 +13,8 @@ jobs: runs-on: ubuntu-latest env: # specify versions to test - INT_NODECORE_VERSION: "0.4.13-rc.12.dev.1" - INT_APM_VERSION: "0.4.13-rc.12.dev.1" + INT_NODECORE_VERSION: "0.4.13-rc.14" + INT_APM_VERSION: "0.4.13-rc.14" INT_BTCSQ_VERSION: "master-47363b0" INT_LOG_LEVEL: "DEBUG" From aae1bf6ad5f3eb8ec783afc9b33cc2a65bdfca41 Mon Sep 17 00:00:00 2001 From: Aleksa Milosevic Date: Wed, 13 Apr 2022 19:17:56 +0200 Subject: [PATCH 11/12] Update BaseIntegrationTest.kt --- src/main/kotlin/testframework/BaseIntegrationTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/testframework/BaseIntegrationTest.kt b/src/main/kotlin/testframework/BaseIntegrationTest.kt index 817fb08..61e5f7b 100644 --- a/src/main/kotlin/testframework/BaseIntegrationTest.kt +++ b/src/main/kotlin/testframework/BaseIntegrationTest.kt @@ -11,7 +11,7 @@ import org.slf4j.LoggerFactory import testframework.wrapper.btcsq.TestBtcsq val nodecoreVersion = System.getenv("INT_NODECORE_VERSION") ?: "0.4.13-rc.14" -val apmVersion = System.getenv("INT_APM_VERSION") ?: "0.4.13-rc.14" +val apmVersion = System.getenv("INT_APM_VERSION") ?: "0.4.13-rc.13" val btcsqVersion = System.getenv("INT_BTCSQ_VERSION") ?: "master-47363b0" enum class TestStatus(val state: String) { From 7c8001a5fd3cc1f65bbcc4cbba33badc72587c38 Mon Sep 17 00:00:00 2001 From: Aleksa Milosevic Date: Wed, 13 Apr 2022 19:18:17 +0200 Subject: [PATCH 12/12] APM version fix --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 512edd9..4c97105 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: env: # specify versions to test INT_NODECORE_VERSION: "0.4.13-rc.14" - INT_APM_VERSION: "0.4.13-rc.14" + INT_APM_VERSION: "0.4.13-rc.13" INT_BTCSQ_VERSION: "master-47363b0" INT_LOG_LEVEL: "DEBUG"