Skip to content

Commit 69d79ff

Browse files
committed
Merge branch 'main' of github.com:smartcontractkit/chainlink-testing-framework into useParrot
2 parents a64b094 + c6274a5 commit 69d79ff

File tree

9 files changed

+179
-6
lines changed

9 files changed

+179
-6
lines changed

.github/workflows/framework-golden-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jobs:
8484
- name: Set up Go
8585
uses: actions/setup-go@v5
8686
with:
87-
go-version: 1.23
87+
go-version: stable
8888
- name: Cache Go modules
8989
uses: actions/cache@v4
9090
with:

.github/workflows/framework.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
- name: Set up Go
3939
uses: actions/setup-go@v5
4040
with:
41-
go-version: 1.23
41+
go-version: stable
4242
- name: Cache Go modules
4343
uses: actions/cache@v4
4444
with:

.github/workflows/lint.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ jobs:
2626
name: Clean go mods
2727
runs-on: ubuntu-latest
2828
steps:
29-
- name: Set up Go 1.23.3
29+
- name: Set up Go
3030
uses: actions/setup-go@v5
3131
with:
32-
go-version: '1.23.3'
32+
go-version: stable
3333
- name: Install gomods
3434
run: go install github.com/jmank88/[email protected]
3535
- name: Check out code
@@ -88,7 +88,7 @@ jobs:
8888
use-go-cache: true
8989
go-cache-dep-path: ${{ matrix.project.path }}go.sum
9090
- name: golangci-lint ${{ needs.tools.outputs.golangci-lint-version }}
91-
uses: golangci/golangci-lint-action@051d91933864810ecd5e2ea2cfd98f6a5bca5347 # v6.3.2
91+
uses: golangci/golangci-lint-action@e0ebdd245eea59746bb0b28ea6a9871d3e35fbc9 # v6.3.3
9292
with:
9393
version: v${{ needs.tools.outputs.golangci-lint-version }}
9494
args: --out-format checkstyle:golangci-lint-report.xml

book/src/framework/components/blockchains/solana.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ arm64 f4hrenh9it/solana:latest - used locally
1616
contracts_dir = "."
1717
# optional, in case you need some custom image
1818
# image = "solanalabs/solana:v1.18.26"
19+
# you can add docker cmd params, for example to clone some contracts
20+
docker_cmd_params = ["--clone", "y9MdSjD9Beg9EFaeQGdMpESFWLNdSfZKQKeYLBfmnjJ", "-u", "https://api.mainnet-beta.solana.com"]
21+
1922

2023
# optional
2124
# To deploy a solana program, we can provide a mapping of program name to program id.

framework/.changeset/v0.5.1.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Override solana-test-validator cmd params
2+
- Copy annotator API to use it in tests explicitly for non-k8s stuff

framework/components/blockchain/solana.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func defaultSolana(in *Input) {
4646
func newSolana(in *Input) (*Output, error) {
4747
defaultSolana(in)
4848
ctx := context.Background()
49+
4950
containerName := framework.DefaultTCName("blockchain-node")
5051
// Solana do not allow to set ws port, it just uses --rpc-port=N and sets WS as N+1 automatically
5152
bindPort := fmt.Sprintf("%s/tcp", in.Port)
@@ -89,6 +90,7 @@ func newSolana(in *Input) (*Output, error) {
8990
"--rpc-port", in.Port,
9091
"--mint", in.PublicKey,
9192
}, flags...)
93+
args = append(args, in.DockerCmdParamsOverrides...)
9294

9395
req := testcontainers.ContainerRequest{
9496
AlwaysPullImage: in.PullImage,

framework/grafana/grafana.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package framework
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
"time"
7+
8+
"github.com/go-resty/resty/v2"
9+
)
10+
11+
type Client struct {
12+
resty *resty.Client
13+
}
14+
15+
// NewGrafanaClient initializes a new Grafana client with the specified URL and API key.
16+
func NewGrafanaClient(url, apiKey string) *Client {
17+
return &Client{
18+
resty: resty.New().
19+
SetBaseURL(url).
20+
SetHeader("Authorization", "Bearer "+apiKey),
21+
}
22+
}
23+
24+
type Annotation struct {
25+
ID int64 `json:"id"`
26+
AlertID int64 `json:"alertId"`
27+
DashboardID int64 `json:"dashboardId"`
28+
DashboardUID string `json:"dashboardUID"`
29+
PanelID int64 `json:"panelId"`
30+
PrevState string `json:"prevState"`
31+
NewState string `json:"newState"`
32+
Text string `json:"text"`
33+
Time time.Time `json:"time"`
34+
TimeEnd time.Time `json:"timeEnd"`
35+
Created time.Time `json:"created"`
36+
Updated time.Time `json:"updated"`
37+
Tags []interface{} `json:"tags"`
38+
Data interface{} `json:"data"`
39+
}
40+
41+
type AnnotationsQueryParams struct {
42+
Limit *int
43+
AlertID *int
44+
DashboardID *int
45+
DashboardUID *string
46+
Type *string
47+
From *time.Time
48+
To *time.Time
49+
}
50+
51+
type PostAnnotation struct {
52+
DashboardID *int
53+
PanelID *int
54+
DashboardUID string
55+
Time *time.Time
56+
TimeEnd *time.Time
57+
Tags []string
58+
Text string
59+
}
60+
61+
type PostAnnotationResponse struct {
62+
Message string `json:"message"`
63+
ID int64 `json:"id"`
64+
}
65+
66+
// GetAnnotations retrieves a list of annotations based on specified query parameters.
67+
func (c *Client) GetAnnotations(params AnnotationsQueryParams) ([]Annotation, *resty.Response, error) {
68+
query := make(url.Values)
69+
if params.Limit != nil {
70+
query.Set("limit", fmt.Sprintf("%d", *params.Limit))
71+
}
72+
if params.AlertID != nil {
73+
query.Set("alertId", fmt.Sprintf("%d", *params.AlertID))
74+
}
75+
if params.DashboardID != nil {
76+
query.Set("dashboardId", fmt.Sprintf("%d", *params.DashboardID))
77+
}
78+
if params.DashboardUID != nil {
79+
query.Set("dashboardUID", *params.DashboardUID)
80+
}
81+
if params.Type != nil {
82+
query.Set("type", *params.Type)
83+
}
84+
85+
if (params.From != nil && params.To == nil) || (params.To != nil && params.From == nil) {
86+
return nil, nil, fmt.Errorf("both From and To must be set")
87+
}
88+
89+
if params.From != nil {
90+
query.Set("from", fmt.Sprintf("%d", params.From.UnixMilli()))
91+
}
92+
if params.To != nil {
93+
query.Set("to", fmt.Sprintf("%d", params.To.UnixMilli()))
94+
}
95+
96+
var result []Annotation
97+
r, err := c.resty.R().
98+
SetResult(&result).
99+
SetQueryString(query.Encode()).
100+
Get("/api/annotations")
101+
return result, r, err
102+
}
103+
104+
// PostAnnotation sends a new annotation to a specified dashboard.
105+
func (c *Client) PostAnnotation(annotation PostAnnotation) (PostAnnotationResponse, *resty.Response, error) {
106+
a := map[string]interface{}{
107+
"dashboardUID": annotation.DashboardUID,
108+
"tags": annotation.Tags,
109+
"text": annotation.Text,
110+
}
111+
if annotation.DashboardID != nil {
112+
a["dashboardId"] = *annotation.DashboardID
113+
}
114+
if annotation.PanelID != nil {
115+
a["panelId"] = *annotation.PanelID
116+
}
117+
if annotation.Time != nil {
118+
a["time"] = annotation.Time.UnixMilli()
119+
}
120+
if annotation.TimeEnd != nil {
121+
a["timeEnd"] = annotation.TimeEnd.UnixMilli()
122+
}
123+
var result PostAnnotationResponse
124+
r, err := c.resty.R().
125+
SetBody(a).
126+
SetResult(&result).
127+
Post("/api/annotations")
128+
return result, r, err
129+
}

framework/grafana/grafana_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package framework
2+
3+
import (
4+
"os"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
// TestPostAnnotationIntegration tests the PostAnnotation method against a real Grafana instance.
12+
func TestPostAnnotationIntegration(t *testing.T) {
13+
t.Skip("manual grafana integration test")
14+
grafanaURL := os.Getenv("GRAFANA_URL")
15+
apiKey := os.Getenv("GRAFANA_TOKEN")
16+
if grafanaURL == "" || apiKey == "" {
17+
t.Skip("Skipping integration test: GRAFANA_URL or GRAFANA_API_KEY environment variables not set")
18+
}
19+
client := NewGrafanaClient(grafanaURL, apiKey)
20+
21+
annotation := PostAnnotation{
22+
DashboardUID: "WaspDebug",
23+
Text: "CTFv2 test annotation",
24+
Tags: []string{"tag-1", "tag-2"},
25+
Time: Ptr(time.Now().Add(-1 * time.Minute)),
26+
TimeEnd: Ptr(time.Now()),
27+
}
28+
response, resp, err := client.PostAnnotation(annotation)
29+
assert.NoError(t, err, "PostAnnotation should not return an error")
30+
assert.Equal(t, 200, resp.StatusCode(), "Expected HTTP status code 200")
31+
assert.NotEmpty(t, response.ID, "Annotation ID should not be empty")
32+
assert.NotEmpty(t, response.Message, "Annotation message should not be empty")
33+
}
34+
35+
func Ptr[T any](value T) *T {
36+
return &value
37+
}

tools/flakeguard/reports/presentation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func buildSettingsTable(testReport *TestReport, maxPassRatio float64) [][]string
157157
{"**Setting**", "**Value**"},
158158
{"Project", testReport.GoProject},
159159
{"Max Pass Ratio", fmt.Sprintf("%.2f%%", maxPassRatio*100)},
160-
{"Test Run Count", fmt.Sprintf("%d", testReport.SummaryData.UniqueTestsRun)},
160+
{"Test Run Count", fmt.Sprintf("%d", testReport.SummaryData.TestRunCount)},
161161
{"Race Detection", fmt.Sprintf("%t", testReport.RaceDetection)},
162162
}
163163
if len(testReport.ExcludedTests) > 0 {

0 commit comments

Comments
 (0)