Skip to content

Commit

Permalink
Merge pull request #35 from vitekkor/34-fix-new-tests
Browse files Browse the repository at this point in the history
#34: fix test
  • Loading branch information
vitekkor authored Apr 24, 2023
2 parents 12f9efa + 83b3ade commit de4b05e
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/badges/branches.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion .github/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions blockchain/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ springBoot {


tasks.test {
maxHeapSize = "2048m"
useJUnitPlatform()
finalizedBy(tasks.jacocoTestReport)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.yield
import mu.KotlinLogging.logger
import org.springframework.stereotype.Service
import java.util.Collections
Expand Down Expand Up @@ -53,6 +54,7 @@ class BlockGeneratorService(
val data = generateData()
val previousHash = getPreviousHash()
do {
yield()
val newBlock = Block(
index = lastIndex + 1,
previousHash = previousHash,
Expand Down Expand Up @@ -82,7 +84,7 @@ class BlockGeneratorService(
} catch (e: IllegalArgumentException) {
log.trace { "Invalid block $newBlock. Regenerate..." }
}
} while (job.isActive)
} while (true)
}

private fun getPreviousHash(): String {
Expand Down
14 changes: 7 additions & 7 deletions blockchain/src/main/kotlin/com/vitekkor/blockchain/util/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.vitekkor.blockchain.util

import java.security.MessageDigest
import kotlin.random.Random
import kotlin.streams.asSequence

fun String.sha256(): String {
val bytes = this.toByteArray()
Expand All @@ -17,11 +16,12 @@ tailrec fun fibonacci(n: Long, a: Long = 0, b: Long = 1): Long = when (n) {
else -> fibonacci(n - 1, b, a + b)
}

fun generateData(): String {
fun generateData(random: Random = Random): String {
val source = ('A'..'Z') + ('a'..'z') + ('0'..'9')
val length = Random.nextLong(0, 256)
return java.util.Random().ints(length, 0, source.size)
.asSequence()
.map(source::get)
.joinToString("")
val length = random.nextLong(0, 256)
var i = 0
return generateSequence {
if (i++ >= length) return@generateSequence null
random.nextInt(0, source.size)
}.map(source::get).joinToString("")
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import com.vitekkor.blockchain.model.HttpOutgoingMessage
import com.vitekkor.blockchain.util.generateData
import io.mockk.every
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import org.awaitility.Awaitility
import org.awaitility.Durations
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
Expand Down Expand Up @@ -247,4 +249,12 @@ internal class BlockGeneratorServiceIntegrationTest {
assertEquals(expectedResponse, actualResponse)
}
}

companion object {
@JvmStatic
@AfterAll
fun unmock() {
unmockkAll()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.vitekkor.blockchain.service

import com.ninjasquad.springmockk.MockkBean
import com.vitekkor.blockchain.model.Block
import com.vitekkor.blockchain.model.HttpOutgoingMessage
import com.vitekkor.blockchain.util.generateData
Expand All @@ -21,13 +22,17 @@ internal class BlockGeneratorServiceTest {
@Autowired
private lateinit var blockGeneratorService: BlockGeneratorService

@MockkBean
private lateinit var nodeClient: NodeClient

@BeforeEach
fun cleanUp() {
ReflectionTestUtils.setField(blockGeneratorService, "blocks", mutableListOf<Block>())
every { nodeClient.sendNewBlock(any()) } returns true
}

@Test
fun blocksGenerationTest() {
fun blocksGenerationTest() {
mockkStatic(::generateData)
every { generateData() } returns "Не до конца раскрыта тема природы в данном блокчейне..."

Expand All @@ -41,7 +46,7 @@ internal class BlockGeneratorServiceTest {
}

@Test
fun oneBlockGenerationTest() {
fun oneBlockGenerationTest() {
mockkStatic(::generateData)
every { generateData() } returns "Не до конца раскрыта тема природы в данном блокчейне..."

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.vitekkor.blockchain.service

import com.ninjasquad.springmockk.SpykBean
import com.vitekkor.blockchain.configuration.properties.GenerationStrategy
import com.vitekkor.blockchain.configuration.properties.GenerationStrategyProperties
import com.vitekkor.blockchain.model.HttpOutgoingMessage
import com.vitekkor.blockchain.util.generateData
import io.mockk.every
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.awaitility.Awaitility
import org.awaitility.Durations
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.util.ReflectionTestUtils
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
import kotlin.test.assertTrue

@AutoConfigureMockMvc
@SpringBootTest
internal class GenerationStrategyTest {
@Autowired
private lateinit var mockMvc: MockMvc

@Autowired
private lateinit var blockGeneratorService: BlockGeneratorService

@SpykBean
private lateinit var generationStrategyProperties: GenerationStrategyProperties

@Test
fun fibonacciStrategyTest() {
every { generationStrategyProperties.generationStrategyName } returns GenerationStrategy.FIBONACCI
mockkStatic(::generateData)
every { generateData() } returns "Мимо тещиного дома я без шуток не хожу"
ReflectionTestUtils.setField(blockGeneratorService, "lastNonce", 14000L)

mockMvc.perform(MockMvcRequestBuilders.get("/start"))
.andExpect(MockMvcResultMatchers.status().isOk)

lateinit var result: HttpOutgoingMessage.BlockChainMessage

Awaitility.await().atMost(Durations.ONE_MINUTE).untilAsserted {
mockMvc.perform(MockMvcRequestBuilders.get("/blockChain"))
.andExpect(MockMvcResultMatchers.status().isOk)
.andDo {
result = Json.decodeFromString(it.response.contentAsString)
assertTrue(result.blocks.isNotEmpty())
}
mockMvc.perform(MockMvcRequestBuilders.get("/stop"))
.andExpect(MockMvcResultMatchers.status().isOk)
assertTrue(result.blocks.size == 1)
}
}

@Test
fun randomStrategyTest() {
every { generationStrategyProperties.generationStrategyName } returns GenerationStrategy.RANDOM
mockkStatic(::generateData)
every { generateData() } returns "Мимо тещиного дома я без шуток не хожу"

mockMvc.perform(MockMvcRequestBuilders.get("/start"))
.andExpect(MockMvcResultMatchers.status().isOk)

lateinit var result: HttpOutgoingMessage.BlockChainMessage

Awaitility.await().atMost(Durations.ONE_MINUTE).untilAsserted {
mockMvc.perform(MockMvcRequestBuilders.get("/blockChain"))
.andExpect(MockMvcResultMatchers.status().isOk)
.andDo {
result = Json.decodeFromString(it.response.contentAsString)
assertTrue(result.blocks.isNotEmpty())
}
mockMvc.perform(MockMvcRequestBuilders.get("/stop"))
.andExpect(MockMvcResultMatchers.status().isOk)
assertTrue(result.blocks.size == 1)
}
}

companion object {
@JvmStatic
@AfterAll
fun unmock() {
unmockkAll()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@ import com.vitekkor.blockchain.stub.NodeStubDelegate
import com.vitekkor.blockchain.util.generateData
import io.mockk.every
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import org.awaitility.Awaitility
import org.awaitility.Durations
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.AfterEach
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.web.client.TestRestTemplate
import org.springframework.boot.test.web.client.getForEntity
import org.springframework.boot.test.web.client.postForEntity
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.util.ReflectionTestUtils
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
Expand All @@ -29,6 +33,7 @@ import kotlin.test.assertTrue
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
properties = ["blockchain.nodes=http://localhost:8080/stub"]
)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
internal class NodeClientTest {

@Autowired
Expand All @@ -55,6 +60,11 @@ internal class NodeClientTest {
nodeStubDelegate.blockValidationLambda = { HttpOutgoingMessage.BlockAcceptedMessage(it) }
}

@AfterEach
fun stopNode() {
assertTrue(testRestTemplate.getForEntity<String>("/stop").statusCode.is2xxSuccessful)
}

@Test
fun allBlocksNotAcceptedTest() {
nodeStubDelegate.blocks = blocks
Expand Down Expand Up @@ -91,6 +101,8 @@ internal class NodeClientTest {
assertTrue(it.statusCode.is2xxSuccessful)
assertNotNull(it.body)
assertTrue(it.body?.blocks?.size == 11)
assertTrue(testRestTemplate.getForEntity<String>("/stop").statusCode.is2xxSuccessful)
assertTrue(testRestTemplate.getForEntity<String>("/start").statusCode.is2xxSuccessful)
}
}
}
Expand Down Expand Up @@ -176,6 +188,7 @@ internal class NodeClientTest {
@Test
fun getBlockChainExceptionTest() {
mockkStatic(::generateData)
every { generateData() } returnsMany blocks.map { it.data }
var i = 0

nodeStubDelegate.blocks = blocks.dropLast(1)
Expand All @@ -191,8 +204,7 @@ internal class NodeClientTest {
if (i++ > 0) {
nodeStubDelegate.getBlockChainPreHook = {}
} else {
ReflectionTestUtils.setField(blockGeneratorService, "lastNonce", 114200)
Thread.sleep(1000)
ReflectionTestUtils.setField(blockGeneratorService, "lastNonce", 25300)
}
it.last()
}
Expand All @@ -202,7 +214,41 @@ internal class NodeClientTest {

assertTrue(testRestTemplate.getForEntity<String>("/start").statusCode.is2xxSuccessful)

ReflectionTestUtils.setField(blockGeneratorService, "lastNonce", 113200)
ReflectionTestUtils.setField(blockGeneratorService, "lastNonce", 25300)

Awaitility.await().atMost(Durations.ONE_MINUTE.multipliedBy(2)).untilAsserted {
testRestTemplate.getForEntity<HttpOutgoingMessage.BlockChainMessage>("/blockChain").let {
assertTrue(it.statusCode.is2xxSuccessful)
assertNotNull(it.body)
assertTrue(it.body?.blocks?.size == 11)
}
}
}

@Test
fun sendNewNodeExceptionTest() {
mockkStatic(::generateData)
every { generateData() } returnsMany blocks.filter { it.index == 1L || it.index == 11L }.map { it.data }

nodeStubDelegate.blocks = blocks.dropLast(1)
nodeStubDelegate.blockValidationLambda = {
throw NoBlocksInNodeException()
}

nodeStubDelegate.getBlockChainPreHook = {
ReflectionTestUtils.setField(blockGeneratorService, "lastNonce", (blocks.last().nonce - 1000L))
}

nodeStubDelegate.lastBlockLambda = {
nodeStubDelegate.blockValidationLambda = { block ->
HttpOutgoingMessage.BlockAcceptedMessage(block)
}
it.last()
}

assertTrue(testRestTemplate.getForEntity<String>("/start").statusCode.is2xxSuccessful)

ReflectionTestUtils.setField(blockGeneratorService, "lastNonce", 25300)

Awaitility.await().atMost(Durations.ONE_MINUTE.multipliedBy(2)).untilAsserted {
testRestTemplate.getForEntity<HttpOutgoingMessage.BlockChainMessage>("/blockChain").let {
Expand All @@ -213,4 +259,34 @@ internal class NodeClientTest {
}
}

@Test
fun generateGenesisTest() {
mockkStatic(::generateData)
every { generateData() } returns "Не до конца раскрыта тема природы в данном блокчейне..."

nodeStubDelegate.blockValidationLambda = {
assertEquals(1L, it.index)
assertEquals("", it.previousHash)
HttpOutgoingMessage.BlockAcceptedMessage(it)
}

ReflectionTestUtils.setField(blockGeneratorService, "lastNonce", 130000L)

assertTrue(testRestTemplate.getForEntity<String>("/generateGenesys").statusCode.is2xxSuccessful)

testRestTemplate.getForEntity<HttpOutgoingMessage.BlockChainMessage>("/blockChain").let {
assertTrue(it.statusCode.is2xxSuccessful)
assertNotNull(it.body)
assertTrue(it.body?.blocks?.size == 1)
}
}

companion object {
@JvmStatic
@AfterAll
fun unmock() {
unmockkAll()
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import org.springframework.stereotype.Component

@Component
class NodeStubDelegate {
@Volatile
var blocks = listOf<Block>()

@Volatile
lateinit var blockValidationLambda: (Block) -> HttpOutgoingMessage

@Volatile
lateinit var lastBlockLambda: (List<Block>) -> Block

@Volatile
var getBlockChainPreHook = {}

fun getLastBlock(): Block {
Expand Down
Loading

0 comments on commit de4b05e

Please sign in to comment.