Skip to content

Commit 7ef58b1

Browse files
committed
interactive
1 parent d198f2b commit 7ef58b1

File tree

11 files changed

+245
-8
lines changed

11 files changed

+245
-8
lines changed

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
- [Chainlink]()
3737
- [RPC]()
3838
- [Loki]()
39+
- [Interactive](framework/interactive.md)
3940
- [Continuous Integration](ci/ci.md)
4041
- [Libraries](./libraries.md)
4142
- [Seth](./libs/seth.md)
54.5 KB
Loading

book/src/framework/interactive.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Interactive
2+
3+
4+
For non-technical users or those building with Chainlink products outside of Golang, we offer an interactive method to deploy a NodeSet.
5+
6+
The only requirement is to have Docker running.
7+
8+
If you're on OS X, we recommend to use [OrbStack](https://orbstack.dev/).
9+
10+
For other platforms use [Docker Desktop](https://www.docker.com/products/docker-desktop/).
11+
12+
Download the latest CLI [here](https://github.com/smartcontractkit/chainlink-testing-framework/releases/tag/framework%2Fv0.1.6)
13+
14+
```
15+
./framework build node_set
16+
```
17+
![img.png](images/interactive-node-set.png)

book/src/overview.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Its primary purpose is to help Chainlink developers create extensive integration
66

77
It can also be helpful to those who just want to use chainlink oracles in their projects to help test their contracts, or even for those that aren't using chainlink.
88

9-
This documentation is for:
9+
This documentation is primarily for:
1010
- Developers looking to write end-to-end tests
1111
- Quality Assurance Engineers aiming to test locally
1212

@@ -15,3 +15,5 @@ To get started with writing tests, refer to the [Framework](./framework/getting_
1515
[Repository](https://github.com/smartcontractkit/chainlink-testing-framework) contains two major pieces:
1616
- [Framework](framework/overview.md)
1717
- [Libraries](libraries.md)
18+
19+
If you're a non-technical user or simply want to run a NodeSet, please refer to our [Interactive](framework/interactive.md) chapter.

framework/cmd/interactive.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"github.com/charmbracelet/huh"
6+
"github.com/smartcontractkit/chainlink-testing-framework/framework"
7+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
8+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/clnode"
9+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/postgres"
10+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set"
11+
"sync"
12+
)
13+
14+
type nodeSetForm struct {
15+
Network string
16+
CLVersion string
17+
Nodes int
18+
Observability bool
19+
Blockscout bool
20+
}
21+
22+
func createComponentsFromForm(f *nodeSetForm) error {
23+
var (
24+
bc *blockchain.Output
25+
_ *simple_node_set.Output
26+
err error
27+
)
28+
if err := framework.DefaultNetwork(&sync.Once{}); err != nil {
29+
return err
30+
}
31+
32+
switch f.Network {
33+
case "anvil":
34+
bc, err = blockchain.NewBlockchainNetwork(&blockchain.Input{
35+
Type: "anvil",
36+
Image: "f4hrenh9it/foundry",
37+
PullImage: true,
38+
Port: "8545",
39+
ChainID: "31337",
40+
})
41+
if err != nil {
42+
return err
43+
}
44+
}
45+
switch f.Nodes {
46+
case 5:
47+
nspecs := make([]*clnode.Input, 0)
48+
for i := 0; i < f.Nodes; i++ {
49+
nspecs = append(nspecs, &clnode.Input{
50+
DbInput: &postgres.Input{
51+
Image: "postgres:15.6",
52+
PullImage: true,
53+
},
54+
Node: &clnode.NodeInput{
55+
Image: f.CLVersion,
56+
PullImage: true,
57+
},
58+
})
59+
}
60+
_, err = simple_node_set.NewSharedDBNodeSet(&simple_node_set.Input{
61+
Nodes: 5,
62+
OverrideMode: "all",
63+
NodeSpecs: nspecs,
64+
}, bc, "")
65+
}
66+
return nil
67+
}
68+
69+
func runSetupForm() error {
70+
if !framework.IsDockerRunning() {
71+
return fmt.Errorf(`Docker daemon is not running!
72+
Please set up OrbStack (https://orbstack.dev/)
73+
or
74+
Docker Desktop (https://www.docker.com/products/docker-desktop/)
75+
`)
76+
}
77+
f := &nodeSetForm{}
78+
79+
form := huh.NewForm(
80+
huh.NewGroup(
81+
huh.NewSelect[string]().
82+
Title("Which network would you like to connect to?").
83+
Options(
84+
huh.NewOption("Anvil", "anvil"),
85+
).
86+
Value(&f.Network), // stores the selected network
87+
88+
huh.NewSelect[int]().
89+
Title("How many nodes do you need?").
90+
Options(
91+
huh.NewOption("5", 5),
92+
).
93+
Value(&f.Nodes), // stores the selected number of nodes
94+
95+
huh.NewSelect[string]().
96+
Title("Choose Chainlink node version").
97+
Options(
98+
huh.NewOption("public.ecr.aws/chainlink/chainlink:v2.17.0", "public.ecr.aws/chainlink/chainlink:v2.17.0")).
99+
Value(&f.CLVersion),
100+
huh.NewConfirm().
101+
Title("Do you need to spin up an observability stack?").
102+
Value(&f.Observability), // stores the observability option
103+
104+
huh.NewConfirm().
105+
Title("Do you need to spin up a Blockscout stack?").
106+
Value(&f.Blockscout), // stores the Blockscout option
107+
),
108+
)
109+
110+
err := form.Run()
111+
if err != nil {
112+
return fmt.Errorf("failed to run form: %w", err)
113+
}
114+
115+
fmt.Println("Configuration Summary:")
116+
fmt.Printf("Network: %s\n", f.Network)
117+
fmt.Printf("Chainlink version: %d\n", f.Nodes)
118+
fmt.Printf("Number of Nodes: %d\n", f.Nodes)
119+
fmt.Printf("Observability Stack: %v\n", f.Observability)
120+
fmt.Printf("Blockscout Stack: %v\n", f.Blockscout)
121+
122+
return createComponentsFromForm(f)
123+
}

framework/cmd/main.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ func main() {
2727
Usage: "Chainlink Testing Framework CLI",
2828
UsageText: "'ctf' is a useful utility that can:\n- clean up test docker containers\n- modify test files\n- create a local observability stack with Grafana/Loki/Pyroscope",
2929
Commands: []*cli.Command{
30+
{
31+
Name: "build",
32+
Aliases: []string{"b"},
33+
Usage: "Build an environment interactively, suitable for non-technical users",
34+
Subcommands: []*cli.Command{
35+
{
36+
Name: "node_set",
37+
Aliases: []string{"ns"},
38+
Usage: "Builds a NodeSet and connect it to some networks",
39+
Action: func(c *cli.Context) error {
40+
return runSetupForm()
41+
},
42+
},
43+
},
44+
},
3045
{
3146
Name: "config",
3247
Aliases: []string{"c"},

framework/components/simple_node_set/node_set.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ func NewSharedDBNodeSet(in *Input, bcOut *blockchain.Output, fakeUrl string) (*O
5454
}
5555

5656
func printOut(out *Output) {
57-
for _, n := range out.CLNodes {
58-
framework.L.Info().Str("URL", n.Node.HostURL).Msg("Chainlink node url")
57+
for i, n := range out.CLNodes {
58+
framework.L.Info().Str(fmt.Sprintf("Node-%d", i), n.Node.HostURL).Msg("Chainlink node url")
5959
}
6060
}
6161

framework/config.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/pelletier/go-toml/v2"
1212
"github.com/rs/zerolog"
1313
"github.com/stretchr/testify/require"
14+
"github.com/testcontainers/testcontainers-go"
1415
"github.com/testcontainers/testcontainers-go/network"
1516
"os"
1617
"path/filepath"
@@ -138,7 +139,8 @@ func Load[X any](t *testing.T) (*X, error) {
138139
// return nil, fmt.Errorf("failed to connect AWSSecretsManager: %w", err)
139140
// }
140141
//}
141-
err = DefaultNetwork(t, once)
142+
err = DefaultNetwork(once)
143+
require.NoError(t, err)
142144
if err != nil {
143145
return input, err
144146
}
@@ -149,16 +151,17 @@ func Load[X any](t *testing.T) (*X, error) {
149151
return input, nil
150152
}
151153

152-
func DefaultNetwork(t *testing.T, once *sync.Once) error {
154+
func DefaultNetwork(once *sync.Once) error {
155+
var net *testcontainers.DockerNetwork
156+
var err error
153157
once.Do(func() {
154-
net, err := network.New(
158+
net, err = network.New(
155159
context.Background(),
156160
network.WithLabels(map[string]string{"framework": "ctf"}),
157161
)
158-
require.NoError(t, err)
159162
DefaultNetworkName = net.Name
160163
})
161-
return nil
164+
return err
162165
}
163166

164167
func RenderTemplate(tmpl string, data interface{}) (string, error) {

framework/docker.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"github.com/docker/docker/client"
78
"github.com/docker/go-connections/nat"
89
"github.com/google/uuid"
910
tc "github.com/testcontainers/testcontainers-go"
@@ -13,6 +14,17 @@ import (
1314
"sync"
1415
)
1516

17+
func IsDockerRunning() bool {
18+
cli, err := client.NewClientWithOpts(client.FromEnv)
19+
if err != nil {
20+
return false
21+
}
22+
defer cli.Close()
23+
24+
_, err = cli.Ping(context.Background())
25+
return err == nil
26+
}
27+
1628
func GetHost(container tc.Container) (string, error) {
1729
host, err := container.Host(context.Background())
1830
if err != nil {

framework/go.mod

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.22
55
require (
66
github.com/aws/aws-sdk-go-v2/config v1.27.39
77
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.33.3
8+
github.com/charmbracelet/huh v0.6.0
89
github.com/davecgh/go-spew v1.1.1
910
github.com/docker/docker v27.1.1+incompatible
1011
github.com/docker/go-connections v0.5.0
@@ -28,6 +29,7 @@ require (
2829
dario.cat/mergo v1.0.0 // indirect
2930
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
3031
github.com/Microsoft/go-winio v0.6.2 // indirect
32+
github.com/atotto/clipboard v0.1.4 // indirect
3133
github.com/aws/aws-sdk-go-v2 v1.31.0 // indirect
3234
github.com/aws/aws-sdk-go-v2/credentials v1.17.37 // indirect
3335
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect
@@ -40,9 +42,17 @@ require (
4042
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3 // indirect
4143
github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 // indirect
4244
github.com/aws/smithy-go v1.21.0 // indirect
45+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
4346
github.com/bytedance/sonic v1.12.3 // indirect
4447
github.com/bytedance/sonic/loader v0.2.0 // indirect
48+
github.com/catppuccin/go v0.2.0 // indirect
4549
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
50+
github.com/charmbracelet/bubbles v0.20.0 // indirect
51+
github.com/charmbracelet/bubbletea v1.1.0 // indirect
52+
github.com/charmbracelet/lipgloss v0.13.0 // indirect
53+
github.com/charmbracelet/x/ansi v0.2.3 // indirect
54+
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
55+
github.com/charmbracelet/x/term v0.2.0 // indirect
4656
github.com/cloudwego/base64x v0.1.4 // indirect
4757
github.com/cloudwego/iasm v0.2.0 // indirect
4858
github.com/containerd/containerd v1.7.18 // indirect
@@ -53,6 +63,8 @@ require (
5363
github.com/creack/pty v1.1.21 // indirect
5464
github.com/distribution/reference v0.6.0 // indirect
5565
github.com/docker/go-units v0.5.0 // indirect
66+
github.com/dustin/go-humanize v1.0.1 // indirect
67+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
5668
github.com/felixge/httpsnoop v1.0.4 // indirect
5769
github.com/gabriel-vasile/mimetype v1.4.6 // indirect
5870
github.com/gin-contrib/sse v0.1.0 // indirect
@@ -68,10 +80,14 @@ require (
6880
github.com/klauspost/compress v1.17.4 // indirect
6981
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
7082
github.com/leodido/go-urn v1.4.0 // indirect
83+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
7184
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
7285
github.com/magiconair/properties v1.8.7 // indirect
7386
github.com/mattn/go-colorable v0.1.13 // indirect
7487
github.com/mattn/go-isatty v0.0.20 // indirect
88+
github.com/mattn/go-localereader v0.0.1 // indirect
89+
github.com/mattn/go-runewidth v0.0.16 // indirect
90+
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
7591
github.com/moby/docker-image-spec v1.3.1 // indirect
7692
github.com/moby/patternmatcher v0.6.0 // indirect
7793
github.com/moby/sys/sequential v0.5.0 // indirect
@@ -80,10 +96,14 @@ require (
8096
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
8197
github.com/modern-go/reflect2 v1.0.2 // indirect
8298
github.com/morikuni/aec v1.0.0 // indirect
99+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
100+
github.com/muesli/cancelreader v0.2.2 // indirect
101+
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
83102
github.com/opencontainers/go-digest v1.0.0 // indirect
84103
github.com/opencontainers/image-spec v1.1.0 // indirect
85104
github.com/pmezard/go-difflib v1.0.0 // indirect
86105
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
106+
github.com/rivo/uniseg v0.4.7 // indirect
87107
github.com/rogpeppe/go-internal v1.10.0 // indirect
88108
github.com/russross/blackfriday/v2 v2.1.0 // indirect
89109
github.com/shirou/gopsutil/v3 v3.23.12 // indirect

0 commit comments

Comments
 (0)