support parallel unit tests

This commit is contained in:
colinlyguo
2024-03-16 17:24:05 +08:00
parent e29a08876d
commit fdaaacb45e
6 changed files with 63 additions and 66 deletions

View File

@@ -102,12 +102,6 @@ jobs:
working-directory: 'rollup'
run: |
make rollup_bins
- name: Set permissions for consensus and execution directories
run: |
sudo chown -R runner:runner ./common/docker-compose/l1/consensus
sudo chmod -R 755 ./common/docker-compose/l1/consensus
sudo chown -R runner:runner ./common/docker-compose/l1/execution
sudo chmod -R 755 ./common/docker-compose/l1/execution
- name: Test rollup packages
working-directory: 'rollup'
run: |

View File

@@ -1,5 +1,7 @@
consensus/beacondata
consensus/beacondata*
consensus/genesis.ssz
consensus/validatordata
consensus/validatordata*
consensus/data*
execution/geth
execution/geth.ipc
execution/data*

View File

@@ -23,18 +23,4 @@ while : ; do
echo "$networks" | xargs -r docker network rm || echo "Warning: Failed to remove some networks."
done
# Remove consensus data directories if they exist
if [ -d "./consensus/beacondata" ] || [ -d "./consensus/validatordata" ] || [ -d "./consensus/genesis.ssz" ]; then
rm -rf ./consensus/beacondata ./consensus/validatordata ./consensus/genesis.ssz
echo "Consensus data removed."
else
echo "No consensus data to remove."
fi
# Remove execution data directory if it exists
if [ -d "./execution/geth" ]; then
rm -rf ./execution/geth
echo "Execution data removed."
else
echo "No execution data to remove."
fi
rm -rf ./consensus/data* ./execution/data*

View File

@@ -9,17 +9,19 @@ import (
"path/filepath"
"time"
"github.com/cloudflare/cfssl/log"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log"
tc "github.com/testcontainers/testcontainers-go/modules/compose"
"github.com/testcontainers/testcontainers-go/wait"
)
// PoSL1TestEnv represents the config needed to test in PoS Layer 1.
type PoSL1TestEnv struct {
rootDir string
compose tc.ComposeStack
gethHTTPPort int
workDir string
compose tc.ComposeStack
gethHTTPPort int
hostPath string
dataPathRandom string
}
// NewPoSL1TestEnv creates and initializes a new instance of PoSL1TestEnv with a random HTTP port.
@@ -29,40 +31,47 @@ func NewPoSL1TestEnv() (*PoSL1TestEnv, error) {
return nil, fmt.Errorf("failed to find project root directory: %v", err)
}
getRandomPort := func(min, max int) (int, error) {
maxInt := big.NewInt(int64(max - min))
var randInt *big.Int
randInt, err = rand.Int(rand.Reader, maxInt)
if err != nil {
return 0, err
}
return int(randInt.Int64()) + min, nil
hostPath, found := os.LookupEnv("HOST_PATH")
if !found {
hostPath = ""
}
gethHTTPPort, err := getRandomPort(1024, 65535)
rnd, err := rand.Int(rand.Reader, big.NewInt(65536-1024))
if err != nil {
return nil, fmt.Errorf("failed to generate a secure random port for Geth HTTP: %v", err)
return nil, fmt.Errorf("failed to generate a random: %v", err)
}
gethHTTPPort := int(rnd.Int64()) + 1024
if err := os.Setenv("GETH_HTTP_PORT", fmt.Sprintf("%d", gethHTTPPort)); err != nil {
return nil, fmt.Errorf("failed to set GETH_HTTP_PORT: %v", err)
}
return &PoSL1TestEnv{
rootDir: filepath.Join(rootDir, "common", "docker-compose", "l1"),
gethHTTPPort: gethHTTPPort,
workDir: filepath.Join(rootDir, "common", "docker-compose", "l1"),
gethHTTPPort: gethHTTPPort,
hostPath: hostPath,
dataPathRandom: fmt.Sprintf("data_%d", time.Now().UnixNano()),
}, nil
}
// Start starts the PoS L1 test environment by running the associated Docker Compose configuration.
func (e *PoSL1TestEnv) Start() error {
var err error
e.compose, err = tc.NewDockerCompose([]string{filepath.Join(e.rootDir, "docker-compose.yml")}...)
e.compose, err = tc.NewDockerCompose([]string{filepath.Join(e.workDir, "docker-compose.yml")}...)
if err != nil {
return fmt.Errorf("failed to create docker compose: %w", err)
}
if err = e.compose.WaitForService("geth", wait.NewHTTPStrategy("/").WithPort("8545/tcp").WithStartupTimeout(180*time.Second)).WithOsEnv().Up(context.Background()); err != nil {
env := map[string]string{
"GETH_HTTP_PORT": fmt.Sprintf("%d", e.gethHTTPPort),
"DATA_PATH_RANDOM": e.dataPathRandom,
}
if e.hostPath != "" {
env["HOST_PATH"] = e.hostPath
}
if err = e.compose.WaitForService("geth", wait.NewHTTPStrategy("/").WithPort("8545/tcp").WithStartupTimeout(15*time.Second)).WithEnv(env).Up(context.Background()); err != nil {
if errStop := e.Stop(); errStop != nil {
log.Error("failed to stop PoS L1 test environment", "err", errStop)
}
@@ -81,10 +90,8 @@ func (e *PoSL1TestEnv) Stop() error {
}
dirsToRemove := []string{
filepath.Join(e.rootDir, "consensus", "beacondata"),
filepath.Join(e.rootDir, "consensus", "validatordata"),
filepath.Join(e.rootDir, "consensus", "genesis.ssz"),
filepath.Join(e.rootDir, "execution", "geth"),
filepath.Join(e.workDir, "consensus", e.dataPathRandom),
filepath.Join(e.workDir, "execution", e.dataPathRandom),
}
for _, dir := range dirsToRemove {
@@ -92,7 +99,6 @@ func (e *PoSL1TestEnv) Stop() error {
return fmt.Errorf("failed to remove data directory %s: %w", dir, err)
}
}
return nil
}

View File

@@ -1,5 +1,17 @@
version: "3.9"
services:
initialize-env:
image: "alpine:3.19.0"
command:
/bin/sh -c "apk add --no-cache rsync &&
mkdir -p /consensus/${DATA_PATH_RANDOM:-data} &&
rsync -a --exclude '${DATA_PATH_RANDOM:-data}' /consensus/ /consensus/${DATA_PATH_RANDOM:-data}/ &&
mkdir -p /execution/${DATA_PATH_RANDOM:-data} &&
rsync -a --exclude '${DATA_PATH_RANDOM:-data}' /execution/ /execution/${DATA_PATH_RANDOM:-data}/"
volumes:
- ${HOST_PATH:-../../..}/common/docker-compose/l1/consensus:/consensus
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution:/execution
# Creates a genesis state for the beacon chain using a YAML configuration file and
# a deterministic set of 64 validators.
create-beacon-chain-genesis:
@@ -15,28 +27,23 @@ services:
- --geth-genesis-json-in=/execution/genesis.json
- --geth-genesis-json-out=/execution/genesis.json
volumes:
- ${HOST_PATH:-../../..}/common/docker-compose/l1/consensus:/consensus
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution:/execution
# Removes the database of the go-ethereum execution client to ensure we start from a clean state.
# (geth has a `removedb` option, but it asks for a keyboard confirmation, so we use this instead)
geth-remove-db:
image: "alpine:3.19.0"
command: rm -rf /execution/geth
volumes:
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution:/execution
- ${HOST_PATH:-../../..}/common/docker-compose/l1/consensus/${DATA_PATH_RANDOM:-data}:/consensus
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/${DATA_PATH_RANDOM:-data}:/execution
depends_on:
initialize-env:
condition: service_completed_successfully
# Sets up the genesis configuration for the go-ethereum client from a JSON file.
geth-genesis:
image: "ethereum/client-go:v1.13.14"
command: --datadir=/execution init /execution/genesis.json
volumes:
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution:/execution
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/genesis.json:/execution/genesis.json
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/${DATA_PATH_RANDOM:-data}:/execution
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/${DATA_PATH_RANDOM:-data}/genesis.json:/execution/genesis.json
depends_on:
create-beacon-chain-genesis:
condition: service_completed_successfully
geth-remove-db:
initialize-env:
condition: service_completed_successfully
# Runs a Prysm beacon chain from a specified genesis state created in the previous step
@@ -70,9 +77,9 @@ services:
create-beacon-chain-genesis:
condition: service_completed_successfully
volumes:
- ${HOST_PATH:-../../..}/common/docker-compose/l1/consensus:/consensus
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution:/execution
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/jwtsecret:/execution/jwtsecret
- ${HOST_PATH:-../../..}/common/docker-compose/l1/consensus/${DATA_PATH_RANDOM:-data}:/consensus
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/${DATA_PATH_RANDOM:-data}:/execution
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/${DATA_PATH_RANDOM:-data}/jwtsecret:/execution/jwtsecret
# Runs the go-ethereum execution client with the specified, unlocked account and necessary
# APIs to allow for proof-of-stake consensus via Prysm.
@@ -92,6 +99,7 @@ services:
- --password=/execution/geth_password.txt
- --nodiscover
- --syncmode=full
- --ipcdisable
ports:
- ${GETH_HTTP_PORT:-8545}:8545
depends_on:
@@ -100,9 +108,9 @@ services:
beacon-chain:
condition: service_started
volumes:
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution:/execution
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/jwtsecret:/execution/jwtsecret
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/geth_password.txt:/execution/geth_password.txt
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/${DATA_PATH_RANDOM:-data}:/execution
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/${DATA_PATH_RANDOM:-data}/jwtsecret:/execution/jwtsecret
- ${HOST_PATH:-../../..}/common/docker-compose/l1/execution/${DATA_PATH_RANDOM:-data}/geth_password.txt:/execution/geth_password.txt
# We run a validator client with 64, deterministically-generated keys that match
# The validator keys present in the beacon chain genesis state generated a few steps above.
@@ -120,4 +128,4 @@ services:
beacon-chain:
condition: service_started
volumes:
- ${HOST_PATH:-../../..}/common/docker-compose/l1/consensus:/consensus
- ${HOST_PATH:-../../..}/common/docker-compose/l1/consensus/${DATA_PATH_RANDOM:-data}:/consensus

View File

@@ -5,6 +5,7 @@ go 1.21
require (
github.com/Masterminds/semver/v3 v3.2.1
github.com/bits-and-blooms/bitset v1.12.0
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004
github.com/docker/docker v25.0.3+incompatible
github.com/gin-contrib/pprof v1.4.0
github.com/gin-gonic/gin v1.9.1