Skip to content

Commit

Permalink
Migrate referenceTests to Junit5 (#3850)
Browse files Browse the repository at this point in the history
* Remove deprecated cleanup task
* Move util class into test-support
This is because this class can be used outside the scope of the junit tests but it'll not be part of main
* Move referenceTests into its own scope
* Migrate referenceTests to Junit5

I inlined `o.h.b.e.vm.AbstractRetryingTest` into `o.h.b.e.vm.VMReferenceTest` because there was a single usage of the abstraction and also because it wasn't portable to how Junit5 parameters work

Signed-off-by: Diego López León <dieguitoll@gmail.com>

Co-authored-by: Danno Ferrin <danno.ferrin@gmail.com>
Co-authored-by: Sally MacFarlane <sally.macfarlane@consensys.net>
  • Loading branch information
3 people authored Jun 2, 2022
1 parent 5b55c0a commit 02d389a
Show file tree
Hide file tree
Showing 26 changed files with 304 additions and 388 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[submodule "eth-ref-tests"]
path = ethereum/referencetests/src/test/resources
path = ethereum/referencetests/src/reference-test/external-resources
url = https://github.com/ethereum/tests.git
ignore = all
[submodule "qbft-ref-tests"]
Expand Down
124 changes: 0 additions & 124 deletions ethereum/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,6 @@ jar {
}
}

sourceSets {
test {
java {
compileClasspath += main.output
runtimeClasspath += main.output
srcDirs += file('./build/generated/sources/referencetests/java/test')
}
}
}

dependencies {
api 'org.slf4j:slf4j-api'

Expand Down Expand Up @@ -72,7 +62,6 @@ dependencies {
testImplementation project(path: ':config', configuration: 'testSupportArtifacts')
testImplementation project(path: ':ethereum:api')
testImplementation project(path: ':ethereum:referencetests')
testImplementation project(path: ':ethereum:referencetests', configuration: 'testOutput')
testImplementation project(':testutil')

testImplementation 'junit:junit'
Expand Down Expand Up @@ -125,119 +114,6 @@ task testJar(type: Jar) {
from sourceSets.test.output
}

test {
exclude 'org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.class'
exclude 'org/hyperledger/besu/ethereum/core/TransactionTest.class'
exclude 'org/hyperledger/besu/ethereum/vm/**ReferenceTest.class'
exclude 'org/hyperledger/besu/ethereum/vm/blockchain/**.class'
exclude 'org/hyperledger/besu/ethereum/vm/generalstate/**.class'
}

def generateTestFiles(FileTree jsonPath, File templateFile, String pathstrip, String destination, String namePrefix, String ... excludedPath) {
mkdir(destination)
def referenceTestTemplate = templateFile.text

// This is how many json files to include in each test file
def fileSets = jsonPath.getFiles().collate(5)

fileSets.eachWithIndex { fileSet, idx ->
def paths = []
fileSet.each { testJsonFile ->
def parentFile = testJsonFile.getParentFile()
def parentPathFile = parentFile.getPath().substring(parentFile.getPath().indexOf(pathstrip))
if (!testJsonFile.getName().toString().startsWith(".") && !excludedPath.contains(parentPathFile)) {
def pathFile = testJsonFile.getPath()
paths << pathFile.substring(pathFile.indexOf(pathstrip))
}
}

def testFile = file(destination + "/" + namePrefix + "_" + idx + ".java")

def allPaths = '"' + paths.join('", "') + '"'

def testFileContents = referenceTestTemplate
.replaceAll("%%TESTS_FILE%%", allPaths)
.replaceAll("%%TESTS_NAME%%", namePrefix + "_" + idx)
testFile.newWriter().withWriter { w -> w << testFileContents }
}
}

task blockchainReferenceTestsSetup {
inputs.files fileTree('../referencetests/src/test/resources/BlockchainTests')
outputs.files "./build/generated/sources/referencetests/java/test/org/hyperledger/besu/ethereum/vm/blockchain"
generateTestFiles(
fileTree('../referencetests/src/test/resources/BlockchainTests'),
file("./src/test/resources/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTest.java.template"),
"BlockchainTests",
"./build/generated/sources/referencetests/java/test/org/hyperledger/besu/ethereum/vm/blockchain",
"BlockchainReferenceTest",
("BlockchainTests/InvalidBlocks/bcExpectSection") // exclude test for test filling tool
)
}

task generalstateReferenceTestsSetup {
inputs.files fileTree("../referencetests/src/test/resources/GeneralStateTests")
outputs.files "./build/generated/sources/referencetests/java/test/org/hyperledger/besu/ethereum/vm/generalstate"
generateTestFiles(
fileTree("../referencetests/src/test/resources/GeneralStateTests"),
file("./src/test/resources/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTest.java.template"),
"GeneralStateTests",
"./build/generated/sources/referencetests/java/test/org/hyperledger/besu/ethereum/vm/generalstate",
"GeneralStateReferenceTest"
)
}

task generalstateRegressionReferenceTestsSetup {
inputs.files fileTree("./src/test/resources/regressions/generalstate")
outputs.files "./build/generated/sources/referencetests/java/test/org/hyperledger/besu/ethereum/vm/generalstate"
generateTestFiles(
fileTree("./src/test/resources/regressions/generalstate"),
file("./src/test/resources/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTest.java.template"),
"regressions",
"./build/generated/sources/referencetests/java/test/org/hyperledger/besu/ethereum/vm/generalstate",
"GeneralStateRegressionReferenceTest"
)
}

//TODO delete in Jan 2022. This is left as a migration aid for reference tests moving to the build directory
task cleanupReferenceTests(type: Delete) {
delete fileTree("./src/test/java/org/hyperledger/besu/ethereum/vm/generalstate/") {
include("**/GeneralStateReferenceTest*.java")
include("**/GeneralStateRegressionReferenceTest*.java")
include("**/LegacyGeneralStateReferenceTest*.java")
include("**/LegacyGeneralStateRegressionReferenceTest*.java")
}
delete fileTree("./src/test/java/org/hyperledger/besu/ethereum/vm/blockchain/") {
include("**/BlockchainReferenceTest*.java")
include("**/LegacyBlockchainReferenceTest*.java")
}
}

clean.dependsOn(cleanupReferenceTests)

task referenceTests(type: Test, dependsOn: [
"blockchainReferenceTestsSetup",
"generalstateReferenceTestsSetup",
"generalstateRegressionReferenceTestsSetup",
"compileTestJava"
]) {
compileTestJava.mustRunAfter blockchainReferenceTestsSetup
compileTestJava.mustRunAfter generalstateReferenceTestsSetup
compileTestJava.mustRunAfter generalstateRegressionReferenceTestsSetup
doFirst {
if (!file("../referencetests/src/test/resources/README.md").exists()) {
throw new GradleException("ethereum/referencetests/src/test/resources/README.md missing: please clone submodules (git submodule update --init --recursive)")
}
}
scanForTestClasses = false
enableAssertions = true
include 'org/hyperledger/besu/ethereum/core/TransactionTest.class'
include 'org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.class'
include 'org/hyperledger/besu/ethereum/vm/**ReferenceTest.class'
include 'org/hyperledger/besu/ethereum/vm/blockchain/**.class'
include 'org/hyperledger/besu/ethereum/vm/generalstate/**.class'
}

artifacts {
testArtifacts testJar
testSupportArtifacts testSupportJar
Expand Down
123 changes: 118 additions & 5 deletions ethereum/referencetests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,70 @@
* SPDX-License-Identifier: Apache-2.0
*/

def blockchainReferenceTests = tasks.register("blockchainReferenceTests") {
final referenceTestsPath = 'src/reference-test/external-resources/BlockchainTests'
final generatedTestsPath = "$buildDir/generated/sources/reference-test/$name/java"
inputs.files fileTree(referenceTestsPath),
fileTree(generatedTestsPath)
outputs.files generatedTestsPath
generateTestFiles(
fileTree(referenceTestsPath),
file("src/reference-test/templates/BlockchainReferenceTest.java.template"),
"BlockchainTests",
"$generatedTestsPath/org/hyperledger/besu/ethereum/vm/blockchain",
"BlockchainReferenceTest",
("BlockchainTests/InvalidBlocks/bcExpectSection") // exclude test for test filling tool
)
}

def generalstateReferenceTests = tasks.register("generalstateReferenceTests") {
final referenceTestsPath = "src/reference-test/external-resources/GeneralStateTests"
final generatedTestsPath = "$buildDir/generated/sources/reference-test/$name/java"
inputs.files fileTree(referenceTestsPath),
fileTree(generatedTestsPath)
outputs.files generatedTestsPath
generateTestFiles(
fileTree(referenceTestsPath),
file("src/reference-test/templates/GeneralStateReferenceTest.java.template"),
"GeneralStateTests",
"$generatedTestsPath/org/hyperledger/besu/ethereum/vm/generalstate",
"GeneralStateReferenceTest"
)
}

def generalstateRegressionReferenceTests = tasks.register("generalstateRegressionReferenceTests") {
final referenceTestsPath = "src/reference-test/resources/regressions/generalstate"
final generatedTestsPath = "$buildDir/generated/sources/reference-test/$name/java"
inputs.files fileTree(referenceTestsPath),
fileTree(generatedTestsPath)
outputs.files generatedTestsPath
generateTestFiles(
fileTree(referenceTestsPath),
file("src/reference-test/templates/GeneralStateReferenceTest.java.template"),
"regressions",
"$generatedTestsPath/org/hyperledger/besu/ethereum/vm/generalstate",
"GeneralStateRegressionReferenceTest"
)
}

sourceSets {
test {
referenceTest {
java {
compileClasspath += main.output
runtimeClasspath += main.output
srcDirs "src/reference-test/java",
blockchainReferenceTests,
generalstateReferenceTests,
generalstateRegressionReferenceTests
}
resources {
include '*Tests/**/*.json'
srcDirs 'src/reference-test/resources',
'src/reference-test/external-resources',
'src/reference-test/templates'
}
}
}

configurations { testOutput }

dependencies {
implementation project(':config')
implementation project(':crypto')
Expand All @@ -36,7 +90,36 @@ dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'com.google.guava:guava'

testOutput sourceSets.test.output
referenceTestImplementation project(path: ':config')
referenceTestImplementation project(path: ':datatypes')
referenceTestImplementation project(path: ':ethereum:core')
referenceTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
referenceTestImplementation project(path: ':ethereum:rlp')
referenceTestImplementation project(path: ':ethereum:rlp', configuration: 'testSupportArtifacts')
referenceTestImplementation project(path: ':ethereum:trie')
referenceTestImplementation project(path: ':evm')
referenceTestImplementation project(path: ':testutil')
referenceTestImplementation project(path: ':util')
referenceTestImplementation 'com.fasterxml.jackson.core:jackson-databind'
referenceTestImplementation 'com.google.guava:guava'
referenceTestImplementation 'org.apache.tuweni:tuweni-bytes'
referenceTestImplementation 'org.assertj:assertj-core'
referenceTestImplementation 'org.junit.jupiter:junit-jupiter-api'
referenceTestImplementation 'org.junit.jupiter:junit-jupiter-params'

referenceTestRuntimeOnly 'org.junit.jupiter:junit-jupiter'
}

task referenceTests(type: Test) {
useJUnitPlatform()
doFirst {
if (!file("src/reference-test/external-resources/README.md").exists()) {
throw new GradleException("ethereum/referencetest/src/reference-test/external-resources/README.md missing: please clone submodules (git submodule update --init --recursive)")
}
}
description = 'Runs ETH reference tests.'
testClassesDirs = sourceSets.referenceTest.output.classesDirs
classpath = sourceSets.referenceTest.runtimeClasspath
}

task ('validateReferenceTestSubmodule') {
Expand Down Expand Up @@ -77,3 +160,33 @@ following commands:
}
}
processResources.dependsOn('validateReferenceTestSubmodule')

def generateTestFiles(FileTree jsonPath, File templateFile, String pathstrip, String destination, String namePrefix, String ... excludedPath) {
def pep = mkdir(destination)
def referenceTestTemplate = templateFile.text

// This is how many json files to include in each test file
def fileSets = jsonPath.getFiles().collate(5)

fileSets.eachWithIndex { fileSet, idx ->
def paths = []
fileSet.each { testJsonFile ->
def parentFile = testJsonFile.getParentFile()
def parentPathFile = parentFile.getPath().substring(parentFile.getPath().indexOf(pathstrip))
if (!testJsonFile.getName().toString().startsWith(".") && !excludedPath.contains(parentPathFile)) {
def pathFile = testJsonFile.getPath()
paths << pathFile.substring(pathFile.indexOf(pathstrip))
}
}

def testFile = file(destination + "/" + namePrefix + "_" + idx + ".java")


def allPaths = '"' + paths.join('", "') + '"'

def testFileContents = referenceTestTemplate
.replaceAll("%%TESTS_FILE%%", allPaths)
.replaceAll("%%TESTS_NAME%%", namePrefix + "_" + idx)
testFile.newWriter().withWriter { w -> w << testFileContents }
}
}
Loading

0 comments on commit 02d389a

Please sign in to comment.