-
Notifications
You must be signed in to change notification settings - Fork 275
Expand file tree
/
Copy pathexecnode.go
More file actions
126 lines (109 loc) · 4.68 KB
/
Copy pathexecnode.go
File metadata and controls
126 lines (109 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//go:build simulated
// SPDX-License-Identifier: BUSL-1.1
//
// Copyright (C) 2025, Berachain Foundation. All rights reserved.
// Use of this software is governed by the Business Source License included
// in the LICENSE file of this repository and at www.mariadb.com/bsl11.
//
// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY
// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER
// VERSIONS OF THE LICENSED WORK.
//
// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF
// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF
// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE).
//
// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
// TITLE.
package execution
import (
"fmt"
"net/http"
"path/filepath"
"testing"
"github.com/berachain/beacon-kit/primitives/net/url"
"github.com/ory/dockertest"
"github.com/ory/dockertest/docker"
"github.com/stretchr/testify/require"
)
// ExecNode represents a test instance of an execution client node running inside a Docker container.
// The CmdStrBuilder field is used to generate the command string that initializes and runs the node.
type ExecNode struct {
homeDir string
image docker.PullImageOptions
CmdStrBuilder func(genesisFile string) string
}
// NewExecNode returns a new ExecNode instance configured with the given home directory,
// Docker image options, and a command string builder.
func NewExecNode(homeDir string, image docker.PullImageOptions, builder func(genesisFile string) string) *ExecNode {
return &ExecNode{
homeDir: homeDir,
image: image,
CmdStrBuilder: builder,
}
}
// Start launches the execution client container using dockertest, waits until the client is ready,
// and returns the container resource along with the connection URL for the Auth RPC endpoint.
func (e *ExecNode) Start(t *testing.T, genesisFile string) (*Resource, *url.ConnectionURL, *url.ConnectionURL) {
t.Helper()
// Create a new Docker pool.
pool, err := dockertest.NewPool("")
require.NoError(t, err, "failed to create Docker pool")
require.NotNil(t, pool, "Docker pool is nil")
// Verify that we can connect to the Docker daemon.
err = pool.Client.Ping()
require.NoErrorf(t, err, "could not connect to Docker: %s", err)
// Refresh the image from the registry, but tolerate an unreachable registry when the
// image is already present locally.
if pullErr := pool.Client.PullImage(e.image, docker.AuthConfiguration{}); pullErr != nil {
_, inspectErr := pool.Client.InspectImage(e.image.Repository + ":" + e.image.Tag)
require.NoErrorf(t, inspectErr,
"failed to pull image %s:%s and it is not present locally (pull error: %v)",
e.image.Repository, e.image.Tag, pullErr,
)
}
// Resolve the absolute path to the local test files.
absPath, err := filepath.Abs("../files")
require.NoError(t, err, "failed to determine absolute path for test files")
require.NotNil(t, e.CmdStrBuilder, "CmdStrBuilder is nil")
cmdStr := e.CmdStrBuilder(genesisFile)
// Run the container with custom commands that initialize and run the client.
resource, err := pool.RunWithOptions(&dockertest.RunOptions{
Repository: e.image.Repository,
Tag: e.image.Tag,
// Override the default entrypoint to use /bin/sh so we can chain commands.
Entrypoint: []string{"/bin/sh"},
Cmd: []string{
"-c",
cmdStr,
},
// Expose required ports for EL RPC, Auth RPC, and P2P communication.
ExposedPorts: []string{"8545/tcp", "8551/tcp", "30303/tcp"},
// Bind mount the local test data and JWT files to the container.
Mounts: []string{
fmt.Sprintf("%s:/%s", e.homeDir, "testdata"),
fmt.Sprintf("%s:/%s", absPath, "testing/files"),
},
})
require.NoError(t, err, "failed to run container")
// Build the connection URLs for EL RPC and Auth RPC.
elRPC, err := url.NewFromRaw("http://" + resource.GetHostPort("8545/tcp"))
require.NoError(t, err, "failed to create EL RPC URL")
authRPC, err := url.NewFromRaw("http://" + resource.GetHostPort("8551/tcp"))
require.NoError(t, err, "failed to create Auth RPC URL")
t.Logf("Auth RPC URL: %s", authRPC.String())
// Wait until the EL RPC endpoint is available by retrying HTTP GET requests.
err = pool.Retry(func() error {
resp, httpErr := http.Get(elRPC.String())
if httpErr != nil {
return httpErr
}
defer resp.Body.Close()
return nil
})
require.NoError(t, err, "Container did not become ready in time")
return &Resource{Resource: resource}, authRPC, elRPC
}