Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/framework-codegen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Framework Code Generation
on:
push:

jobs:
test:
defaults:
run:
working-directory: framework/
env:
LOKI_TENANT_ID: promtail
LOKI_URL: http://localhost:3030/loki/api/v1/push
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
strategy:
fail-fast: false
matrix:
test:
- name: TestSmokeGenerate
count: 1
timeout: 10m
name: ${{ matrix.test.name }}
steps:
- name: Checkout repo
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- name: Configure AWS credentials using OIDC
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
with:
role-to-assume: ${{ secrets.PUBLIC_AWS_ECR_ROLE }}
aws-region: us-east-1
- name: Authenticate to ECR Public
id: login-ecr-public
uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1
with:
registry-type: public
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: framework/go.mod
- name: Cache Go modules
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: go-modules-${{ hashFiles('framework/go.sum') }}-${{ runner.os }}-framework-codegen
restore-keys: |
go-modules-${{ runner.os }}-framework-codegen
go-modules-${{ runner.os }}
- name: Install dependencies
run: go mod download
- name: Run Codegen Tests
run: |
go test -timeout ${{ matrix.test.timeout }} -v -count ${{ matrix.test.count }} -run ${{ matrix.test.name }}
- name: Upload Logs
if: always()
uses: actions/upload-artifact@v4
with:
name: container-logs-${{ matrix.test.name }}
path: framework/logs
retention-days: 1
6 changes: 1 addition & 5 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@
- [Framework](./framework/overview.md)
- [Basic Usage](./framework/getting_started.md)
- [Getting Started](./framework/getting_started.md)
- [Your First Test](./framework/first_test.md)
- [NodeSet Environment](./framework/nodeset_environment.md)
- [NodeSet (Capabilities)](./framework/nodeset_capabilities.md)
- [NodeSet (Local Docker builds)](./framework/nodeset_docker_rebuild.md)
- [Generating Developer Environment](./framework/generate.md)
- [Advanced Usage](./framework/configuration.md)
- [CLI](./framework/cli.md)
- [Configuration](./framework/configuration.md)
- [Debugging Tests](framework/components/debug.md)
- [Generating Tests](framework/generate.md)
- [Creating your own components](./developing/developing_components.md)
- [Exposing Components](framework/components/state.md)
- [Asserting Logs](./developing/asserting_logs.md)
Expand Down
22 changes: 18 additions & 4 deletions book/src/framework/generate.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
# Generating Tests
# Generating Chainlink Environment

Some types of tests may require a lot of boilerplate and configurability, for example load and chaos tests.
Our code generation tools automatically build complete Chainlink environments and test templates, which minimizes documentation and provides a framework that is both structured and easily extensible.

We provide code generation tool that help you to start with best practes in such cases.
Let's read `help` first and then build an environment for a single EVM network:
```bash
ctf gen -h
# generate a new Chainlink environment in "devenv" directory with 4 Chainlink nodes and one EVM network. Generate CLI called "pcli" and enter the shell
ctf gen env --cli pcli --product-name MyProduct --output-dir devenv --nodes 4
```

All generators have `-h` or `--help` flag, please read the docs!
Follow further instructions in `devenv/README.md`

# Generating Infrastructure Testing Template

If you have Chainlink infrastructure already deployed it's useful to generate a workload + chaos suite template.
```bash
ctf gen load -h
# generate test suite named ChaosGen, with workload + default chaos experiments (fail + latency) for all the pods that have app.kubernetes.io/instance annotation
ctf gen load -w -n ChaosGen default
```
1 change: 1 addition & 0 deletions framework/.changeset/v0.12.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Codegeneration for Devenv
4 changes: 4 additions & 0 deletions framework/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# dev environment generated by manually testing CLI
cmd/devenv/
# dev environments generated by automated tests
test-env*/
2 changes: 1 addition & 1 deletion framework/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

Modular and data-driven harness for Chainlink on-chain and off-chain components.

[![Documentation](https://img.shields.io/badge/Documentation-MDBook-blue?style=for-the-badge)](https://smartcontractkit.github.io/chainlink-testing-framework/framework/overview.html)
[![Documentation](https://img.shields.io/badge/Documentation-MDBook-blue?style=for-the-badge)](https://smartcontractkit.github.io/chainlink-testing-framework/framework/overview.html)
148 changes: 148 additions & 0 deletions framework/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"

"github.com/pelletier/go-toml"
Expand All @@ -25,6 +27,119 @@ func main() {
Aliases: []string{"g"},
Usage: "Generates various test templates",
Subcommands: []*cli.Command{
{
Name: "env",
Aliases: []string{"e"},
Usage: "Generate a Chainlink Node developer environment",
Description: `🔗 Chainlink's Developer Environment Generator 🔗

Prerequisites:
Just will be automatically installed if not available (via Homebrew on macOS).
For other platforms, please install it manually: https://github.com/casey/just

Usage:

⚙️ Generate basic environment:
ctf gen env --cli myenv --output-dir devenv --product-name Knilniahc --nodes 4

📜 Read the docs in devenv/README.md

🔧 Address all TODO comments and customize it
`,
ArgsUsage: "",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "cli",
Aliases: []string{"c"},
Usage: "Your devenv CLI binary name",
},
&cli.StringFlag{
Name: "output-dir",
Aliases: []string{"o"},
Value: "devenv",
Usage: "Your devenv directory",
},
&cli.StringFlag{
Name: "product-name",
Aliases: []string{"r"},
Usage: "Your product name",
},
&cli.StringFlag{
Name: "product-configuration-type",
Aliases: []string{"p"},
Value: "evm-single",
Usage: "Product configuration type/layout (single network, multi-network, etc)",
},
&cli.IntFlag{
Name: "nodes",
Aliases: []string{"n"},
Value: 4,
Usage: "Chainlink Nodes",
},
},
Action: func(c *cli.Context) error {
outputDir := c.String("output-dir")
productConfType := c.String("product-configuration-type")
nodes := c.Int("nodes")
cliName := c.String("cli")
if cliName == "" {
return fmt.Errorf("CLI name can't be empty, choose your CLI name")
}
productName := c.String("product-name")
if productName == "" {
return fmt.Errorf("Product name must be specified, call your product somehow, any name")
}
framework.L.Info().
Str("OutputDir", outputDir).
Str("Name", cliName).
Int("CLNodes", nodes).
Str("ProductConfigurationType", productConfType).
Msg("Generating developer environment")

cg, err := framework.NewEnvBuilder(cliName, nodes, productConfType, productName).
OutputDir(outputDir).
Build()
if err != nil {
return fmt.Errorf("failed to create codegen: %w", err)
}
if err := cg.Write(); err != nil {
return fmt.Errorf("failed to generate module: %w", err)
}

fmt.Println()
fmt.Printf("📁 Your environment directory is: %s\n", outputDir)
fmt.Printf("💻 Your CLI name is: %s\n", cliName)
fmt.Printf("📜 More docs can be found in %s/README.md\n", outputDir)
fmt.Printf("⬛ Entering the shell..\n")
fmt.Println()

// Ensure 'just' is installed before proceeding
if err := ensureJustInstalled(); err != nil {
return fmt.Errorf("failed to ensure 'just' is installed: %w", err)
}

cmd := exec.Command("just", "cli")
cmd.Env = os.Environ()
cmd.Dir = outputDir
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to build CLI via Justfile: %w, output: %s", err, string(out))
}
if err := os.Chdir(outputDir); err != nil {
return err
}
cmd = exec.Command(cliName, "sh")
cmd.Env = os.Environ()
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to enter devenv shell: %w", err)
}
return nil
},
},
{
Name: "load",
Aliases: []string{"l"},
Expand Down Expand Up @@ -359,3 +474,36 @@ func RemoveCacheFiles() error {
framework.L.Info().Msg("All cache files has been removed")
return nil
}

// ensureJustInstalled checks if 'just' is available in PATH, and if not, attempts to install it.
// On macOS, it tries to install via Homebrew. On other platforms, it provides installation instructions.
func ensureJustInstalled() error {
// Check if just is already available
if _, err := exec.LookPath("just"); err == nil {
return nil
}

fmt.Println("⚠️ 'just' command not found in PATH")
fmt.Println("📦 Attempting to install 'just'...")

// Try to install via Homebrew on macOS
if runtime.GOOS == "darwin" {
// Check if Homebrew is available
if _, err := exec.LookPath("brew"); err == nil {
fmt.Println("🍺 Installing 'just' via Homebrew...")
cmd := exec.Command("brew", "install", "just")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to install 'just' via Homebrew: %w. Please install manually: brew install just", err)
}
fmt.Println("✅ Successfully installed 'just'")
return nil
}
// Homebrew not available, provide instructions
return fmt.Errorf("'just' is not installed and Homebrew is not available. Please install 'just' manually:\n brew install just\n Or visit: https://github.com/casey/just")
}

// For non-macOS platforms, provide installation instructions
return fmt.Errorf("'just' is not installed. Please install it manually:\n Visit: https://github.com/casey/just\n Or use your package manager (e.g., apt install just, pacman -S just)")
}
Loading
Loading