Merge pull request #38 from p2p-org/ganache_in_tests
Integration tests with ganache and SpringBootTest
This commit is contained in:
@@ -58,6 +58,7 @@ configurations {
|
|||||||
compile.exclude group: "org.slf4j", module: "log4j-over-slf4j"
|
compile.exclude group: "org.slf4j", module: "log4j-over-slf4j"
|
||||||
// should be used only for generation of the stubs, the lib contains grpc classes
|
// should be used only for generation of the stubs, the lib contains grpc classes
|
||||||
compile.exclude group: "com.salesforce.servicelibs", module: "reactor-grpc"
|
compile.exclude group: "com.salesforce.servicelibs", module: "reactor-grpc"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -101,6 +102,13 @@ dependencies {
|
|||||||
testImplementation libs.java.websocket
|
testImplementation libs.java.websocket
|
||||||
testImplementation libs.equals.verifier
|
testImplementation libs.equals.verifier
|
||||||
testImplementation libs.groovy
|
testImplementation libs.groovy
|
||||||
|
testImplementation libs.bundles.testcontainers
|
||||||
|
testImplementation libs.bundles.junit
|
||||||
|
|
||||||
|
testImplementation(libs.spring.boot.starter.test) {
|
||||||
|
exclude module: 'spring-boot-starter-logging'
|
||||||
|
}
|
||||||
|
testImplementation libs.grpc.testing
|
||||||
|
|
||||||
detektPlugins libs.detekt.formatting
|
detektPlugins libs.detekt.formatting
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,14 @@ spring-security-core = { module = "org.springframework.security:spring-security-
|
|||||||
spring-security-web = { module = "org.springframework.security:spring-security-web", version.ref = "spring-security" }
|
spring-security-web = { module = "org.springframework.security:spring-security-web", version.ref = "spring-security" }
|
||||||
spring-security-config = { module = "org.springframework.security:spring-security-config", version.ref = "spring-security" }
|
spring-security-config = { module = "org.springframework.security:spring-security-config", version.ref = "spring-security" }
|
||||||
|
|
||||||
|
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "spring-boot" }
|
||||||
|
|
||||||
|
testcontainers = "org.testcontainers:testcontainers:1.17.5"
|
||||||
|
testcontainers-ganache = "io.github.ganchix:testcontainers-java-module-ganache:0.0.4"
|
||||||
|
|
||||||
|
junit-jupiter = "org.junit.jupiter:junit-jupiter:5.9.1"
|
||||||
|
assertj = "org.assertj:assertj-core:3.23.1"
|
||||||
|
|
||||||
[bundles]
|
[bundles]
|
||||||
apache-commons = ["commons-io", "apache-commons-lang3", "apache-commons-collections4"]
|
apache-commons = ["commons-io", "apache-commons-lang3", "apache-commons-collections4"]
|
||||||
etherjar = ["etherjar-domain", "etherjar-hex", "etherjar-rpc-api", "etherjar-rpc-http", "etherjar-rpc-ws", "etherjar-tx", "etherjar-contract", "etherjar-erc20"]
|
etherjar = ["etherjar-domain", "etherjar-hex", "etherjar-rpc-api", "etherjar-rpc-http", "etherjar-rpc-ws", "etherjar-tx", "etherjar-contract", "etherjar-erc20"]
|
||||||
@@ -122,6 +130,9 @@ netty = ["netty-common", "netty-transport", "netty-handler-core", "netty-handler
|
|||||||
reactor = ["reactor-core", "reactor-netty", "reactor-extra", "reactor-kotlin"]
|
reactor = ["reactor-core", "reactor-netty", "reactor-extra", "reactor-kotlin"]
|
||||||
slf4j = ["slf4j-api", "slf4j-jul", "slf4j-jcl", "log4j-slf4j"]
|
slf4j = ["slf4j-api", "slf4j-jul", "slf4j-jcl", "log4j-slf4j"]
|
||||||
spring-framework = ["spring-boot-starter", "spring-security-core", "spring-security-web", "spring-security-config"]
|
spring-framework = ["spring-boot-starter", "spring-security-core", "spring-security-web", "spring-security-config"]
|
||||||
|
testcontainers = ["testcontainers", "testcontainers-ganache"]
|
||||||
|
junit = ["junit-jupiter", "assertj"]
|
||||||
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
|
|||||||
@@ -33,9 +33,11 @@ import org.springframework.boot.SpringApplication
|
|||||||
import org.springframework.context.ApplicationContext
|
import org.springframework.context.ApplicationContext
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.context.annotation.Profile
|
||||||
import org.springframework.core.env.Environment
|
import org.springframework.core.env.Environment
|
||||||
import org.springframework.scheduling.annotation.EnableAsync
|
import org.springframework.scheduling.annotation.EnableAsync
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling
|
import org.springframework.scheduling.annotation.EnableScheduling
|
||||||
|
import org.springframework.util.ResourceUtils
|
||||||
import reactor.core.scheduler.Scheduler
|
import reactor.core.scheduler.Scheduler
|
||||||
import reactor.core.scheduler.Schedulers
|
import reactor.core.scheduler.Schedulers
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -47,8 +49,8 @@ import kotlin.system.exitProcess
|
|||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
open class Config(
|
open class Config(
|
||||||
@Autowired private val env: Environment,
|
private val env: Environment,
|
||||||
@Autowired private val ctx: ApplicationContext
|
private val ctx: ApplicationContext
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -61,7 +63,12 @@ open class Config(
|
|||||||
private var configFilePath: File? = null
|
private var configFilePath: File? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
configFilePath = getConfigPath()
|
configFilePath = if (env.activeProfiles.contains("integration-test")) {
|
||||||
|
ResourceUtils.getFile("classpath:integration/dshackle.yaml")
|
||||||
|
} else {
|
||||||
|
getConfigPath()
|
||||||
|
}
|
||||||
|
|
||||||
Global.version = env.getProperty("version.app", Global.version).let {
|
Global.version = env.getProperty("version.app", Global.version).let {
|
||||||
if (it.contains("SNAPSHOT")) {
|
if (it.contains("SNAPSHOT")) {
|
||||||
listOfNotNull(it, env.getProperty("version.commit")).joinToString("-")
|
listOfNotNull(it, env.getProperty("version.commit")).joinToString("-")
|
||||||
@@ -95,6 +102,7 @@ open class Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@Profile("!integration-test")
|
||||||
open fun mainConfig(@Autowired fileResolver: FileResolver): MainConfig {
|
open fun mainConfig(@Autowired fileResolver: FileResolver): MainConfig {
|
||||||
val f = configFilePath ?: throw IllegalStateException("Config path is not set")
|
val f = configFilePath ?: throw IllegalStateException("Config path is not set")
|
||||||
log.info("Using config: ${f.absolutePath}")
|
log.info("Using config: ${f.absolutePath}")
|
||||||
|
|||||||
111
src/test/kotlin/io/emeraldpay/dshackle/IntegrationTest.kt
Normal file
111
src/test/kotlin/io/emeraldpay/dshackle/IntegrationTest.kt
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package io.emeraldpay.dshackle
|
||||||
|
|
||||||
|
import io.emeraldpay.api.proto.BlockchainGrpc
|
||||||
|
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||||
|
import io.emeraldpay.api.proto.Common.ChainRef
|
||||||
|
import io.emeraldpay.dshackle.config.MainConfig
|
||||||
|
import io.emeraldpay.dshackle.config.MainConfigReader
|
||||||
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
|
import io.github.ganchix.ganache.Account
|
||||||
|
import io.github.ganchix.ganache.GanacheContainer
|
||||||
|
import io.grpc.BindableService
|
||||||
|
import io.grpc.inprocess.InProcessChannelBuilder
|
||||||
|
import io.grpc.inprocess.InProcessServerBuilder
|
||||||
|
import org.assertj.core.api.Assertions
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
|
import org.springframework.boot.test.context.TestConfiguration
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
|
import org.springframework.context.annotation.Profile
|
||||||
|
import org.springframework.test.context.ActiveProfiles
|
||||||
|
import org.springframework.util.ResourceUtils
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
@SpringBootTest(properties = ["spring.main.allow-bean-definition-overriding=true"])
|
||||||
|
@Import(Config::class)
|
||||||
|
@ActiveProfiles("integration-test")
|
||||||
|
class IntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
lateinit var services: List<BindableService>
|
||||||
|
|
||||||
|
lateinit var stub: BlockchainGrpc.BlockchainBlockingStub
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val PRIVATE_KEY_0 = "ae020c8ddb6fbc24e167b011666639d2ce3d4aa0d9c13d02d726d6865618a781"
|
||||||
|
val PRIVATE_KEY_1 = "81ad1ba5c4da47feb0f0163c0c61a66c4d0e6a66bd839827444b1e3362016140"
|
||||||
|
|
||||||
|
var ganacheContainer: GanacheContainer<*> = GanacheContainer<Nothing>().apply {
|
||||||
|
withAccounts(
|
||||||
|
listOf(
|
||||||
|
Account.builder().privateKey(PRIVATE_KEY_0).balance(BigInteger.valueOf(2000000000000000000)).build(),
|
||||||
|
Account.builder().privateKey(PRIVATE_KEY_1).balance(BigInteger.valueOf(2000000000000000000)).build()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
ganacheContainer.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun prepare() {
|
||||||
|
val serverName = InProcessServerBuilder.generateName()
|
||||||
|
val builder = InProcessServerBuilder.forName(serverName)
|
||||||
|
.directExecutor()
|
||||||
|
services.forEach { builder.addService(it) }
|
||||||
|
|
||||||
|
val managedChannel = InProcessChannelBuilder.forName(serverName).directExecutor().build()
|
||||||
|
val server = builder.build()
|
||||||
|
server.start()
|
||||||
|
|
||||||
|
stub = BlockchainGrpc.newBlockingStub(managedChannel)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test() {
|
||||||
|
val result = stub.describe(BlockchainOuterClass.DescribeRequest.newBuilder().build())
|
||||||
|
Assertions.assertThat(result.chainsCount).isEqualTo(1)
|
||||||
|
Assertions.assertThat(result.chainsList[0].chain).isEqualTo(ChainRef.CHAIN_ETHEREUM)
|
||||||
|
Assertions.assertThat(result.chainsList[0].nodesCount).isEqualTo(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestConfiguration
|
||||||
|
open class Config {
|
||||||
|
@Bean
|
||||||
|
@Profile("integration-test")
|
||||||
|
open fun mainConfig(@Autowired fileResolver: FileResolver): MainConfig {
|
||||||
|
val reader = MainConfigReader(fileResolver)
|
||||||
|
val config = reader.read(
|
||||||
|
ResourceUtils.getFile("classpath:integration/dshackle.yaml")
|
||||||
|
.inputStream()
|
||||||
|
)!!
|
||||||
|
patch(config)
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun patch(config: MainConfig) {
|
||||||
|
config.upstreams?.upstreams?.add(
|
||||||
|
UpstreamsConfig.Upstream<UpstreamsConfig.EthereumPosConnection>().apply {
|
||||||
|
id = "ganache"
|
||||||
|
nodeId = 1
|
||||||
|
chain = "ethereum"
|
||||||
|
connection = UpstreamsConfig.EthereumPosConnection().apply {
|
||||||
|
execution = UpstreamsConfig.EthereumConnection().apply {
|
||||||
|
rpc = UpstreamsConfig.HttpEndpoint(
|
||||||
|
URI.create(
|
||||||
|
"http://" + ganacheContainer.getHost() + ":" + ganacheContainer.getMappedPort(8545) + "/"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/test/resources/integration/dshackle.yaml
Normal file
21
src/test/resources/integration/dshackle.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
version: v1
|
||||||
|
host: 0.0.0.0
|
||||||
|
port: 2450
|
||||||
|
tls:
|
||||||
|
enabled: false
|
||||||
|
proxy:
|
||||||
|
host: 0.0.0.0
|
||||||
|
port: 8550
|
||||||
|
routes:
|
||||||
|
- id: eth
|
||||||
|
blockchain: ethereum
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enabled: false
|
||||||
|
extended: true
|
||||||
|
|
||||||
|
signed-response:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
cluster:
|
||||||
|
upstreams:
|
||||||
Reference in New Issue
Block a user