Skip to content

Commit e80214f

Browse files
authored
Compatibility testing CLI (#2412)
Compatibility testing CLI
1 parent fc6e123 commit e80214f

13 files changed

Lines changed: 637 additions & 2 deletions

File tree

book/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414

1515
require (
1616
github.com/DataDog/zstd v1.5.2 // indirect
17+
github.com/Masterminds/semver/v3 v3.4.0 // indirect
1718
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect
1819
github.com/block-vision/sui-go-sdk v1.0.6 // indirect
1920
github.com/cespare/cp v1.1.1 // indirect

book/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg6
88
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
99
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
1010
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
11+
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
12+
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
1113
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
1214
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
1315
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU=

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
- [Containers Network Isolation](framework/components/network_isolation.md)
2525
- [Fake Services](framework/components/mocking.md)
2626
- [Detecting Resource Leaks](framework/resource_leaks.md)
27+
- [Compatibility Testing](framework/compat.md)
2728
- [Copying Files](framework/copying_files.md)
2829
- [Running in Kubernetes](./framework/kubernetes.md)
2930
- [External Environment](framework/components/external.md)

book/src/framework/compat.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Compatibility Testing
2+
3+
We have a simple tool to check compatibility for CL nodes. The example command will filter and sort the available tags, rollback and install the oldest version, and then begin performing automatic upgrades to verify that each subsequent version remains compatible with the previous one.
4+
5+
```bash
6+
ctf compat backward \
7+
--buildcmd "just cli" \
8+
--envcmd "cl r" \
9+
--testcmd "cl test ocr2 TestSmoke/rounds" \
10+
--include_tags +compat \
11+
--nodes 3 \
12+
--versions_back 3
13+
```
14+
15+
Since some of our products have a different release and tagging strategies you should add `+compat` tags to all released versions and use this tool in CI to check compatibility on `+compat` tag.
16+
17+
Use `ctf compat restore` to rollback to current branch (default is `develop`)

framework/.changeset/v0.14.4.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Compatibility testing CLI

framework/cmd/main.go

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os/exec"
88
"path/filepath"
99
"runtime"
10+
"slices"
1011
"strings"
1112

1213
"github.com/pelletier/go-toml"
@@ -258,9 +259,134 @@ Be aware that any TODO requires your attention before your run the final test!
258259
},
259260
},
260261
{
261-
Name: "config",
262+
Name: "compat",
262263
Aliases: []string{"c"},
263-
Usage: "Shapes your test config, removes outputs, formatting ,etc",
264+
Usage: "Performs cluster compatibility testing",
265+
Subcommands: []*cli.Command{
266+
{
267+
Name: "restore",
268+
Aliases: []string{"r"},
269+
Flags: []cli.Flag{
270+
&cli.StringFlag{
271+
Name: "base_branch",
272+
Usage: "Base branch on which to restore",
273+
Value: "develop",
274+
},
275+
},
276+
Usage: "Restores back to develop",
277+
Action: func(c *cli.Context) error {
278+
return framework.RestoreToBranch(c.String("base_branch"))
279+
},
280+
},
281+
{
282+
Name: "backward",
283+
Aliases: []string{"b"},
284+
Flags: []cli.Flag{
285+
&cli.IntFlag{
286+
Name: "versions_back",
287+
Aliases: []string{"v"},
288+
Usage: "How many versions back to test",
289+
Value: 1,
290+
},
291+
&cli.IntFlag{
292+
Name: "nodes",
293+
Aliases: []string{"n"},
294+
Usage: "How many nodes to upgrade",
295+
Value: 3,
296+
},
297+
&cli.StringFlag{
298+
Name: "registry",
299+
Aliases: []string{"r"},
300+
Usage: "Docker Image registry for Chainlink node",
301+
Value: "smartcontract/chainlink",
302+
},
303+
&cli.StringFlag{
304+
Name: "buildcmd",
305+
Aliases: []string{"b"},
306+
Usage: "Environment build command",
307+
Value: "just cli",
308+
},
309+
&cli.StringFlag{
310+
Name: "envcmd",
311+
Aliases: []string{"e"},
312+
Usage: "Environment bootstrap command",
313+
},
314+
&cli.StringFlag{
315+
Name: "testcmd",
316+
Aliases: []string{"t"},
317+
Usage: "Test verification command",
318+
},
319+
&cli.StringSliceFlag{
320+
Name: "include_tags",
321+
Usage: "Patterns to include specific tags (e.g., beta,rc,v0,v1)",
322+
},
323+
&cli.StringSliceFlag{
324+
Name: "exclude_tags",
325+
Usage: "Patterns to exclude specific tags (e.g., beta,rc,v0,v1)",
326+
Value: cli.NewStringSlice("beta", "rc", "v0", "ccip", "cre", "datastreams"),
327+
},
328+
},
329+
Usage: "Rollbacks N versions back, runs the test the upgrades CL nodes with new versions",
330+
Action: func(c *cli.Context) error {
331+
versionsBack := c.Int("versions_back")
332+
registry := c.String("registry")
333+
include := c.StringSlice("include_tags")
334+
exclude := c.StringSlice("exclude_tags")
335+
336+
buildcmd := c.String("buildcmd")
337+
envcmd := c.String("envcmd")
338+
testcmd := c.String("testcmd")
339+
nodes := c.Int("nodes")
340+
// test logic is:
341+
// - rollback to selected tag
342+
// - spin up the env and perform the initial smoke test
343+
// - upgrade N CL nodes with preversing DB volume (shared database)
344+
// - perform the test again
345+
// - repeat until all the new versions are validated
346+
tags, err := framework.RollbackToEarliestSemverTag(versionsBack, include, exclude)
347+
if err != nil {
348+
return err
349+
}
350+
if envcmd == "" || testcmd == "" {
351+
framework.L.Info().Msg("No envcmd or testcmd provided, skipping")
352+
return nil
353+
}
354+
if _, err := framework.ExecCmdWithContext(c.Context, buildcmd); err != nil {
355+
return err
356+
}
357+
if _, err := framework.ExecCmdWithContext(c.Context, envcmd); err != nil {
358+
return err
359+
}
360+
if _, err := framework.ExecCmdWithContext(c.Context, testcmd); err != nil {
361+
return err
362+
}
363+
// reverse and skip current version
364+
slices.Reverse(tags)
365+
tags = tags[1:]
366+
// TODO: remove it with real tags when they match
367+
for _, tag := range tags {
368+
tagToPull := strings.ReplaceAll(tag, "+compat", "")
369+
for i := range nodes {
370+
err := framework.UpgradeContainer(
371+
c.Context,
372+
fmt.Sprintf("don-node%d", i),
373+
fmt.Sprintf("%s:%s", registry, tagToPull))
374+
if err != nil {
375+
return err
376+
}
377+
}
378+
if _, err := framework.ExecCmd(testcmd); err != nil {
379+
return err
380+
}
381+
}
382+
return nil
383+
},
384+
},
385+
},
386+
},
387+
{
388+
Name: "config",
389+
Usage: "Shapes your test config, removes outputs, formatting ,etc",
264390
Subcommands: []*cli.Command{
265391
{
266392
Name: "fmt",

0 commit comments

Comments
 (0)