avoid port re-use across unit test runs (#4374)

In Jenkins CI we run two instances of unit tests concurrently.
This can trigger CI failure when the same port numbers are re-used
by the different test instances. Fixed one more issue of this by
allowing user configuration of the base port number.
This commit is contained in:
Etan Kissling 2022-11-30 15:29:08 +01:00 committed by GitHub
parent 096c43db59
commit 7878e8083b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 37 deletions

View File

@ -159,17 +159,28 @@ libbacktrace:
# EXECUTOR_NUMBER: [0, 1] (depends on max number of concurrent CI jobs) # EXECUTOR_NUMBER: [0, 1] (depends on max number of concurrent CI jobs)
# #
# The following port ranges are allocated (entire continuous range): # The following port ranges are allocated (entire continuous range):
#
# Unit tests:
# - NIMBUS_TEST_KEYMANAGER_BASE_PORT + [0, 4)
#
# REST tests:
# - --base-port
# - --base-rest-port
# - --base-metrics-port
#
# Local testnets (entire continuous range):
# - --base-port + [0, --nodes + --light-clients) # - --base-port + [0, --nodes + --light-clients)
# - --base-rest-port + [0, --nodes) # - --base-rest-port + [0, --nodes)
# - --base-metrics-port + [0, --nodes) # - --base-metrics-port + [0, --nodes)
# - --base-vc-metrics-port + [0, --nodes] # - --base-vc-metrics-port + [0, --nodes]
# - --base-remote-signer-port + [0, --remote-signers) # - --base-remote-signer-port + [0, --remote-signers)
# #
# If --run-geth or --run-nimbus is specified (only these ports): # Local testnets with --run-geth or --run-nimbus (only these ports):
# - --base-el-net-port + --el-port-offset * [0, --nodes + --light-clients) # - --base-el-net-port + --el-port-offset * [0, --nodes + --light-clients)
# - --base-el-http-port + --el-port-offset * [0, --nodes + --light-clients) # - --base-el-http-port + --el-port-offset * [0, --nodes + --light-clients)
# - --base-el-ws-port + --el-port-offset * [0, --nodes + --light-clients) # - --base-el-ws-port + --el-port-offset * [0, --nodes + --light-clients)
# - --base-el-auth-rpc-port + --el-port-offset * [0, --nodes + --light-clients) # - --base-el-auth-rpc-port + --el-port-offset * [0, --nodes + --light-clients)
UNIT_TEST_BASE_PORT := 9950
restapi-test: restapi-test:
./tests/simulation/restapi.sh \ ./tests/simulation/restapi.sh \
@ -315,7 +326,11 @@ endif
for TEST_BINARY in $(XML_TEST_BINARIES); do \ for TEST_BINARY in $(XML_TEST_BINARIES); do \
PARAMS="--xml:build/$${TEST_BINARY}.xml --console"; \ PARAMS="--xml:build/$${TEST_BINARY}.xml --console"; \
echo -e "\nRunning $${TEST_BINARY} $${PARAMS}\n"; \ echo -e "\nRunning $${TEST_BINARY} $${PARAMS}\n"; \
build/$${TEST_BINARY} $${PARAMS} || { echo -e "\n$${TEST_BINARY} $${PARAMS} failed; Last 50 lines from the log:"; tail -n50 "$${TEST_BINARY}.log"; exit 1; }; \ NIMBUS_TEST_KEYMANAGER_BASE_PORT=$$(( $(UNIT_TEST_BASE_PORT) + EXECUTOR_NUMBER * 25 )) \
build/$${TEST_BINARY} $${PARAMS} || { \
echo -e "\n$${TEST_BINARY} $${PARAMS} failed; Last 50 lines from the log:"; \
tail -n50 "$${TEST_BINARY}.log"; exit 1; \
}; \
done; \ done; \
rm -rf 0000-*.json t_slashprot_migration.* *.log block_sim_db rm -rf 0000-*.json t_slashprot_migration.* *.log block_sim_db
for TEST_BINARY in $(TEST_BINARIES); do \ for TEST_BINARY in $(TEST_BINARIES); do \
@ -324,7 +339,10 @@ endif
elif [[ "$${TEST_BINARY}" == "block_sim" ]]; then PARAMS="--validators=8000 --slots=160"; \ elif [[ "$${TEST_BINARY}" == "block_sim" ]]; then PARAMS="--validators=8000 --slots=160"; \
fi; \ fi; \
echo -e "\nRunning $${TEST_BINARY} $${PARAMS}\n"; \ echo -e "\nRunning $${TEST_BINARY} $${PARAMS}\n"; \
build/$${TEST_BINARY} $${PARAMS} || { echo -e "\n$${TEST_BINARY} $${PARAMS} failed; Last 50 lines from the log:"; tail -n50 "$${TEST_BINARY}.log"; exit 1; }; \ build/$${TEST_BINARY} $${PARAMS} || { \
echo -e "\n$${TEST_BINARY} $${PARAMS} failed; Last 50 lines from the log:"; \
tail -n50 "$${TEST_BINARY}.log"; exit 1; \
}; \
done; \ done; \
rm -rf 0000-*.json t_slashprot_migration.* *.log block_sim_db rm -rf 0000-*.json t_slashprot_migration.* *.log block_sim_db

View File

@ -28,10 +28,18 @@ import
type type
KeymanagerToTest = object KeymanagerToTest = object
ident: string
port: int port: int
validatorsDir: string validatorsDir: string
secretsDir: string secretsDir: string
# Individual port numbers derived by adding `ord` to configurable base port
PortKind {.pure.} = enum
PeerToPeer,
Metrics,
KeymanagerBN,
KeymanagerVC
const const
simulationDepositsCount = 128 simulationDepositsCount = 128
dataDir = "./test_keymanager_api" dataDir = "./test_keymanager_api"
@ -41,8 +49,7 @@ const
genesisFile = dataDir / "genesis.ssz" genesisFile = dataDir / "genesis.ssz"
bootstrapEnrFile = dataDir / "bootstrap_node.enr" bootstrapEnrFile = dataDir / "bootstrap_node.enr"
tokenFilePath = dataDir / "keymanager-token.txt" tokenFilePath = dataDir / "keymanager-token.txt"
keymanagerPortBN = 47000 defaultBasePort = 49000
keymanagerPortVC = 48000
correctTokenValue = "some secret token" correctTokenValue = "some secret token"
defaultFeeRecipient = Eth1Address.fromHex("0x000000000000000000000000000000000000DEAD") defaultFeeRecipient = Eth1Address.fromHex("0x000000000000000000000000000000000000DEAD")
@ -96,16 +103,6 @@ const
vcValidatorsDir = vcDataDir / "validators" vcValidatorsDir = vcDataDir / "validators"
vcSecretsDir = vcDataDir / "secrets" vcSecretsDir = vcDataDir / "secrets"
beaconNodeKeymanager = KeymanagerToTest(
port: keymanagerPortBN,
validatorsDir: nodeValidatorsDir,
secretsDir: nodeSecretsDir)
validatorClientKeymanager = KeymanagerToTest(
port: keymanagerPortVC,
validatorsDir: vcValidatorsDir,
secretsDir: vcSecretsDir)
func specifiedFeeRecipient(x: int): Eth1Address = func specifiedFeeRecipient(x: int): Eth1Address =
copyMem(addr result, unsafeAddr x, sizeof x) copyMem(addr result, unsafeAddr x, sizeof x)
@ -258,28 +255,28 @@ proc addPreTestRemoteKeystores(validatorsDir: string) =
err = res.error err = res.error
quit 1 quit 1
proc startBeaconNode {.raises: [Defect, CatchableError].} = proc startBeaconNode(basePort: int) {.raises: [Defect, CatchableError].} =
let rng = keys.newRng() let rng = keys.newRng()
copyHalfValidators(nodeDataDir, true) copyHalfValidators(nodeDataDir, true)
addPreTestRemoteKeystores(nodeValidatorsDir) addPreTestRemoteKeystores(nodeValidatorsDir)
let runNodeConf = try: BeaconNodeConf.load(cmdLine = mapIt([ let runNodeConf = try: BeaconNodeConf.load(cmdLine = mapIt([
"--tcp-port=49000", "--tcp-port=" & $(basePort + PortKind.PeerToPeer.ord),
"--udp-port=49000", "--udp-port=" & $(basePort + PortKind.PeerToPeer.ord),
"--discv5=off", "--discv5=off",
"--network=" & dataDir, "--network=" & dataDir,
"--data-dir=" & nodeDataDir, "--data-dir=" & nodeDataDir,
"--validators-dir=" & nodeValidatorsDir, "--validators-dir=" & nodeValidatorsDir,
"--secrets-dir=" & nodeSecretsDir, "--secrets-dir=" & nodeSecretsDir,
"--metrics-address=127.0.0.1", "--metrics-address=127.0.0.1",
"--metrics-port=48008", "--metrics-port=" & $(basePort + PortKind.Metrics.ord),
"--rest=true", "--rest=true",
"--rest-address=127.0.0.1", "--rest-address=127.0.0.1",
"--rest-port=" & $keymanagerPortBN, "--rest-port=" & $(basePort + PortKind.KeymanagerBN.ord),
"--keymanager=true", "--keymanager=true",
"--keymanager-address=127.0.0.1", "--keymanager-address=127.0.0.1",
"--keymanager-port=" & $keymanagerPortBN, "--keymanager-port=" & $(basePort + PortKind.KeymanagerBN.ord),
"--keymanager-token-file=" & tokenFilePath, "--keymanager-token-file=" & tokenFilePath,
"--suggested-fee-recipient=" & $defaultFeeRecipient, "--suggested-fee-recipient=" & $defaultFeeRecipient,
"--doppelganger-detection=off"], it)) "--doppelganger-detection=off"], it))
@ -303,21 +300,21 @@ proc startBeaconNode {.raises: [Defect, CatchableError].} =
# os.removeDir dataDir # os.removeDir dataDir
proc startValidatorClient {.async, thread.} = proc startValidatorClient(basePort: int) {.async, thread.} =
let rng = keys.newRng() let rng = keys.newRng()
copyHalfValidators(vcDataDir, false) copyHalfValidators(vcDataDir, false)
addPreTestRemoteKeystores(vcValidatorsDir) addPreTestRemoteKeystores(vcValidatorsDir)
let runValidatorClientConf = try: ValidatorClientConf.load(cmdLine = mapIt([ let runValidatorClientConf = try: ValidatorClientConf.load(cmdLine = mapIt([
"--beacon-node=http://127.0.0.1:47000", "--beacon-node=http://127.0.0.1:" & $(basePort + PortKind.KeymanagerBN.ord),
"--data-dir=" & vcDataDir, "--data-dir=" & vcDataDir,
"--validators-dir=" & vcValidatorsDir, "--validators-dir=" & vcValidatorsDir,
"--secrets-dir=" & vcSecretsDir, "--secrets-dir=" & vcSecretsDir,
"--suggested-fee-recipient=" & $defaultFeeRecipient, "--suggested-fee-recipient=" & $defaultFeeRecipient,
"--keymanager=true", "--keymanager=true",
"--keymanager-address=127.0.0.1", "--keymanager-address=127.0.0.1",
"--keymanager-port=" & $keymanagerPortVC, "--keymanager-port=" & $(basePort + PortKind.KeymanagerVC.ord),
"--keymanager-token-file=" & tokenFilePath], it)) "--keymanager-token-file=" & tokenFilePath], it))
except: except:
quit 1 quit 1
@ -499,13 +496,7 @@ proc runTests(keymanager: KeymanagerToTest) {.async.} =
] ]
) )
keymanagerKind = testFlavour = " [" & keymanager.ident & "]" & preset()
if keymanager.port == keymanagerPortBN:
" [Beacon Node]"
else:
" [Validator Client]"
testFlavour = keymanagerKind & preset()
suite "Serialization/deserialization" & testFlavour: suite "Serialization/deserialization" & testFlavour:
proc `==`(a, b: Kdf): bool = proc `==`(a, b: Kdf): bool =
@ -1278,11 +1269,24 @@ proc runTests(keymanager: KeymanagerToTest) {.async.} =
response.status == 403 response.status == 403
responseJson["message"].getStr() == InvalidAuthorizationError responseJson["message"].getStr() == InvalidAuthorizationError
proc delayedTests {.async.} = proc delayedTests(basePort: int) {.async.} =
let
beaconNodeKeymanager = KeymanagerToTest(
ident: "Beacon Node",
port: basePort + PortKind.KeymanagerBN.ord,
validatorsDir: nodeValidatorsDir,
secretsDir: nodeSecretsDir)
validatorClientKeymanager = KeymanagerToTest(
ident: "Validator Client",
port: basePort + PortKind.KeymanagerVC.ord,
validatorsDir: vcValidatorsDir,
secretsDir: vcSecretsDir)
while bnStatus != BeaconNodeStatus.Running: while bnStatus != BeaconNodeStatus.Running:
await sleepAsync(1.seconds) await sleepAsync(1.seconds)
asyncSpawn startValidatorClient() asyncSpawn startValidatorClient(basePort)
await sleepAsync(2.seconds) await sleepAsync(2.seconds)
@ -1296,13 +1300,26 @@ proc delayedTests {.async.} =
bnStatus = BeaconNodeStatus.Stopping bnStatus = BeaconNodeStatus.Stopping
proc main() {.async.} = proc main(basePort: int) {.async.} =
if dirExists(dataDir): if dirExists(dataDir):
os.removeDir dataDir os.removeDir dataDir
asyncSpawn delayedTests() asyncSpawn delayedTests(basePort)
prepareNetwork() prepareNetwork()
startBeaconNode() startBeaconNode(basePort)
waitFor main() let
basePortStr = os.getEnv("NIMBUS_TEST_KEYMANAGER_BASE_PORT", $defaultBasePort)
basePort =
try:
let val = parseInt(basePortStr)
if val < 0 or val > (uint16.high.int - PortKind.high.ord):
fatal "Invalid base port arg", basePort = basePortStr
quit 1
val
except ValueError as exc:
fatal "Invalid base port arg", basePort = basePortStr, exc = exc.msg
quit 1
waitFor main(basePort)