Skip to content

Commit 35eb1fa

Browse files
authored
Merge branch 'main' into dx-1040-benchspy-p99
2 parents cf7ec29 + d6febbd commit 35eb1fa

File tree

7 files changed

+1605
-62
lines changed

7 files changed

+1605
-62
lines changed

framework/.changeset/v0.9.4.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Test local S3 provider: public bucket policy

framework/components/s3provider/minio.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,36 @@ func (mf MinioFactory) run(m *Minio) (Provider, error) {
244244
return nil, err
245245
}
246246

247+
myPolicy := fmt.Sprintf(`
248+
{
249+
"Version": "2012-10-17",
250+
"Statement": [
251+
{
252+
"Action": [
253+
"s3:GetObject"
254+
],
255+
"Effect": "Allow",
256+
"Principal": {
257+
"AWS": [
258+
"*"
259+
]
260+
},
261+
"Resource": [
262+
"arn:aws:s3:::%s/*"
263+
],
264+
"Sid": ""
265+
}
266+
]
267+
}
268+
`, m.GetBucket())
269+
270+
err = minioClient.SetBucketPolicy(ctx, m.GetBucket(), myPolicy)
271+
if err != nil {
272+
framework.L.Warn().Str("error", err.Error()).Msg("failed to set public policy to minio bucket")
273+
274+
return nil, err
275+
}
276+
247277
return m, nil
248278
}
249279

framework/components/s3provider/minio_test.go

Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package s3provider
33
import (
44
"context"
55
"fmt"
6+
"io"
7+
"net/http"
68
"testing"
79

810
"github.com/google/go-cmp/cmp"
@@ -27,17 +29,19 @@ func TestNew(t *testing.T) {
2729

2830
// Test Output
2931
output := s3provider.Output()
30-
require.True(t,
31-
cmp.Equal(&Output{
32-
AccessKey: accessKey,
33-
SecretKey: secretKey,
34-
Bucket: DefaultBucket,
35-
ConsoleURL: s3provider.GetConsoleURL(),
36-
Endpoint: s3provider.GetEndpoint(),
37-
BaseEndpoint: fmt.Sprintf("%s:%d", DefaultHost, port),
38-
Region: s3provider.GetRegion(),
39-
UseCache: false,
40-
}, output))
32+
expected := &Output{
33+
AccessKey: accessKey,
34+
SecretKey: secretKey,
35+
Bucket: DefaultBucket,
36+
ConsoleURL: s3provider.GetConsoleURL(),
37+
ConsoleBaseURL: s3provider.GetConsoleBaseURL(),
38+
Endpoint: s3provider.GetEndpoint(),
39+
BaseEndpoint: fmt.Sprintf("%s:%d", DefaultHost, port),
40+
Region: s3provider.GetRegion(),
41+
UseCache: false,
42+
}
43+
fmt.Printf("%#v\n%#v\n", expected, output)
44+
require.True(t, cmp.Equal(expected, output))
4145
require.Len(t, output.AccessKey, accessKeyLength)
4246
require.Len(t, output.SecretKey, secretKeyLength)
4347

@@ -48,7 +52,20 @@ func TestNew(t *testing.T) {
4852
})
4953
require.NoError(t, err)
5054

51-
helperUploadFile(t, minioClient, s3provider.GetBucket())
55+
info, err := helperUploadFile(minioClient, s3provider.GetBucket())
56+
require.NoError(t, err)
57+
require.Equal(t, int64(7), info.Size)
58+
59+
statusCode, err := helperDownloadFile(
60+
fmt.Sprintf(
61+
"http://%s/%s/%s",
62+
output.Endpoint,
63+
output.Bucket,
64+
info.Key,
65+
),
66+
)
67+
require.NoError(t, err)
68+
require.Equal(t, http.StatusOK, statusCode)
5269
}
5370

5471
func TestNewFrom(t *testing.T) {
@@ -64,16 +81,17 @@ func TestNewFrom(t *testing.T) {
6481
require.NoError(t, err)
6582

6683
// Test Output
67-
fmt.Printf("%#v\n", output)
68-
require.True(t,
69-
cmp.Equal(&Output{
70-
Bucket: DefaultBucket,
71-
ConsoleURL: fmt.Sprintf("http://%s:%d", "127.0.0.1", consolePort),
72-
Endpoint: fmt.Sprintf("%s:%d", "127.0.0.1", port),
73-
BaseEndpoint: fmt.Sprintf("%s:%d", "minio", port),
74-
Region: DefaultRegion,
75-
UseCache: false,
76-
}, output, cmpopts.IgnoreFields(Output{}, "AccessKey", "SecretKey")))
84+
expected := &Output{
85+
Bucket: DefaultBucket,
86+
ConsoleURL: fmt.Sprintf("http://%s:%d", "127.0.0.1", consolePort),
87+
ConsoleBaseURL: fmt.Sprintf("http://%s:%d", DefaultHost, consolePort),
88+
Endpoint: fmt.Sprintf("%s:%d", "127.0.0.1", port),
89+
BaseEndpoint: fmt.Sprintf("%s:%d", DefaultHost, port),
90+
Region: DefaultRegion,
91+
UseCache: false,
92+
}
93+
fmt.Printf("%#v\n%#v\n", expected, output)
94+
require.True(t, cmp.Equal(expected, output, cmpopts.IgnoreFields(Output{}, "AccessKey", "SecretKey")))
7795
require.Len(t, output.AccessKey, accessKeyLength)
7896
require.Len(t, output.SecretKey, secretKeyLength)
7997

@@ -84,10 +102,23 @@ func TestNewFrom(t *testing.T) {
84102
})
85103
require.NoError(t, err)
86104

87-
helperUploadFile(t, minioClient, output.Bucket)
105+
info, err := helperUploadFile(minioClient, output.Bucket)
106+
require.NoError(t, err)
107+
require.Equal(t, int64(7), info.Size)
108+
109+
statusCode, err := helperDownloadFile(
110+
fmt.Sprintf(
111+
"http://%s/%s/%s",
112+
output.Endpoint,
113+
output.Bucket,
114+
info.Key,
115+
),
116+
)
117+
require.NoError(t, err)
118+
require.Equal(t, http.StatusOK, statusCode)
88119
}
89120

90-
func helperUploadFile(t *testing.T, minioClient *minio.Client, bucket string) {
121+
func helperUploadFile(minioClient *minio.Client, bucket string) (*minio.UploadInfo, error) {
91122
// Test file upload
92123
filename := "test.txt"
93124
filePath := "./" + filename
@@ -99,6 +130,23 @@ func helperUploadFile(t *testing.T, minioClient *minio.Client, bucket string) {
99130
filePath,
100131
minio.PutObjectOptions{ContentType: contentType},
101132
)
102-
require.NoError(t, err)
103-
require.Equal(t, int64(7), info.Size)
133+
if err != nil {
134+
return nil, err
135+
}
136+
return &info, nil
137+
}
138+
139+
func helperDownloadFile(url string) (int, error) {
140+
fmt.Printf("Downloading: %s\n", url)
141+
resp, err := http.Get(url) //nolint:gosec //ignoring G107
142+
if err != nil {
143+
return 0, err
144+
}
145+
defer func(Body io.ReadCloser) {
146+
err := Body.Close()
147+
if err != nil {
148+
panic(err)
149+
}
150+
}(resp.Body)
151+
return resp.StatusCode, nil
104152
}

tools/flakeguard/runner/parser/parser.go

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ type testProcessingState struct {
108108
temporaryOutputsByRunID map[string][]string // runID -> []string of normal output
109109
panicDetectionMode bool
110110
raceDetectionMode bool
111-
detectedEntries []entry // Raw entries collected during panic/race
112-
key string // Test key (pkg/TestName)
113-
filePath string // File path currently being processed (for logging)
111+
detectedEntries []rawEventData // Raw entries collected during panic/race
112+
key string // Test key (pkg/TestName)
113+
filePath string // File path currently being processed (for logging)
114114
}
115115

116116
// parseTestResults orchestrates the multi-pass parsing approach.
@@ -257,6 +257,20 @@ func (p *defaultParser) processEventsPerTest(eventsByTest map[string][]rawEventD
257257
p.processEvent(state, rawEv)
258258
}
259259

260+
// If after processing all events, and these are still true
261+
// it means there were no terminal actions (pass/fail/skip) after a panic or race.
262+
if state.panicDetectionMode || state.raceDetectionMode {
263+
firstDetected := state.detectedEntries[0]
264+
terminalEvent := entry{
265+
Action: "fail",
266+
Test: firstDetected.Event.Test,
267+
Package: firstDetected.Event.Package,
268+
Output: "",
269+
Elapsed: 0.0, // No elapsed time
270+
}
271+
p.handlePanicRaceTermination(state, terminalEvent, firstDetected.RunID)
272+
}
273+
260274
p.finalizeOutputs(state, cfg)
261275
result.Runs = len(state.processedRunIDs)
262276
processedTestDetails[key] = result
@@ -271,13 +285,28 @@ func (p *defaultParser) processEvent(state *testProcessingState, rawEv rawEventD
271285

272286
// 1. Handle Output / Panic/Race Start Detection
273287
if event.Output != "" {
274-
panicRaceStarted := p.handleOutputEvent(state, event, runID)
275-
if panicRaceStarted || state.panicDetectionMode || state.raceDetectionMode {
276-
if state.panicDetectionMode || state.raceDetectionMode {
277-
state.detectedEntries = append(state.detectedEntries, event)
278-
}
288+
// already detected panic or race, collect non-empty outputs
289+
if state.panicDetectionMode || state.raceDetectionMode {
290+
state.detectedEntries = append(state.detectedEntries, rawEv)
291+
return
292+
}
293+
294+
if panicStarted := startPanicRe.MatchString(event.Output); panicStarted {
295+
state.panicDetectionMode = true
296+
state.detectedEntries = append(state.detectedEntries, rawEv)
297+
return
298+
}
299+
300+
if raceStarted := startRaceRe.MatchString(event.Output); raceStarted {
301+
state.raceDetectionMode = true
302+
state.detectedEntries = append(state.detectedEntries, rawEv)
279303
return
280304
}
305+
306+
if state.temporaryOutputsByRunID[runID] == nil {
307+
state.temporaryOutputsByRunID[runID] = []string{}
308+
}
309+
state.temporaryOutputsByRunID[runID] = append(state.temporaryOutputsByRunID[runID], event.Output)
281310
}
282311

283312
// 2. Handle Panic/Race Termination
@@ -290,31 +319,6 @@ func (p *defaultParser) processEvent(state *testProcessingState, rawEv rawEventD
290319
}
291320
}
292321

293-
// handleOutputEvent handles output collection and panic/race start detection.
294-
// Returns true if panic/race mode started.
295-
func (p *defaultParser) handleOutputEvent(state *testProcessingState, event entry, runID string) (panicRaceStarted bool) {
296-
if state.panicDetectionMode || state.raceDetectionMode {
297-
return false
298-
}
299-
300-
if startPanicRe.MatchString(event.Output) {
301-
state.detectedEntries = append(state.detectedEntries, event)
302-
state.panicDetectionMode = true
303-
return true
304-
}
305-
if startRaceRe.MatchString(event.Output) {
306-
state.detectedEntries = append(state.detectedEntries, event)
307-
state.raceDetectionMode = true
308-
return true
309-
}
310-
311-
if state.temporaryOutputsByRunID[runID] == nil {
312-
state.temporaryOutputsByRunID[runID] = []string{}
313-
}
314-
state.temporaryOutputsByRunID[runID] = append(state.temporaryOutputsByRunID[runID], event.Output)
315-
return false
316-
}
317-
318322
// handlePanicRaceTermination processes the end of a panic/race block.
319323
func (p *defaultParser) handlePanicRaceTermination(state *testProcessingState, event entry, runID string) {
320324
terminalAction := event.Action == "pass" || event.Action == "fail" || event.Action == "skip"
@@ -324,12 +328,12 @@ func (p *defaultParser) handlePanicRaceTermination(state *testProcessingState, e
324328

325329
var outputs []string
326330
for _, de := range state.detectedEntries {
327-
outputs = append(outputs, de.Output)
331+
outputs = append(outputs, de.Event.Output)
328332
}
329333
outputStr := strings.Join(outputs, "\n")
330334
currentPackage := event.Package
331335
if currentPackage == "" && len(state.detectedEntries) > 0 {
332-
currentPackage = state.detectedEntries[0].Package
336+
currentPackage = state.detectedEntries[0].Event.Package
333337
}
334338

335339
attributedTestName := event.Test
@@ -378,7 +382,7 @@ func (p *defaultParser) handlePanicRaceTermination(state *testProcessingState, e
378382
}
379383

380384
// Reset state
381-
state.detectedEntries = []entry{}
385+
state.detectedEntries = []rawEventData{}
382386
state.panicDetectionMode = false
383387
state.raceDetectionMode = false
384388
}

tools/flakeguard/runner/parser/parser_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,3 +1075,85 @@ func TestParseFiles_IgnoreParentFailures(t *testing.T) {
10751075
})
10761076
}
10771077
}
1078+
1079+
func TestParseFiles_WithPanicEventFile(t *testing.T) {
1080+
t.Parallel()
1081+
1082+
parser := NewParser()
1083+
filePath := "testdata/events-with-panic.json"
1084+
results, _, err := parser.ParseFiles([]string{filePath}, "run", 1, Config{})
1085+
1086+
if err != nil {
1087+
t.Fatalf("Failed to parse event file: %v", err)
1088+
}
1089+
1090+
assert.Equal(t, 6, len(results), "Expected 6 test results from file.")
1091+
1092+
// Map test names to expected values for easier assertions
1093+
expected := map[string]struct {
1094+
pkg string
1095+
pkgPanic bool
1096+
panic bool
1097+
passRatio float64
1098+
runs int
1099+
failures int
1100+
successes int
1101+
skipped bool
1102+
skips int
1103+
}{
1104+
"Test_EventHandlerStateSync": {
1105+
pkg: "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/capabilities/workflows/syncer", pkgPanic: true, panic: false, passRatio: 1, runs: 1, failures: 0, successes: 1, skipped: false, skips: 0,
1106+
},
1107+
"Test_InitialStateSync": {
1108+
pkg: "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/capabilities/workflows/syncer", pkgPanic: true, panic: false, passRatio: 1, runs: 1, failures: 0, successes: 1, skipped: false, skips: 0,
1109+
},
1110+
"Test_RegistrySyncer_SkipsEventsNotBelongingToDON": {
1111+
pkg: "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/capabilities/workflows/syncer", pkgPanic: true, panic: false, passRatio: 1, runs: 1, failures: 0, successes: 1, skipped: false, skips: 0,
1112+
},
1113+
"Test_RegistrySyncer_WorkflowRegistered_InitiallyActivated": {
1114+
pkg: "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/capabilities/workflows/syncer", pkgPanic: true, panic: true, passRatio: 0, runs: 1, failures: 1, successes: 0, skipped: false, skips: 0,
1115+
},
1116+
"Test_RegistrySyncer_WorkflowRegistered_InitiallyPaused": {
1117+
pkg: "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/capabilities/workflows/syncer", pkgPanic: true, panic: false, passRatio: 1, runs: 1, failures: 0, successes: 1, skipped: false, skips: 0,
1118+
},
1119+
"Test_SecretsWorker": {
1120+
pkg: "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/capabilities/workflows/syncer", pkgPanic: false, panic: false, passRatio: 1, runs: 0, failures: 0, successes: 0, skipped: true, skips: 1,
1121+
},
1122+
}
1123+
1124+
for _, r := range results {
1125+
exp, ok := expected[r.TestName]
1126+
require.True(t, ok, "Unexpected test name: %s", r.TestName)
1127+
assert.Equal(t, exp.pkg, r.TestPackage, "Package mismatch for %s", r.TestName)
1128+
assert.Equal(t, exp.pkgPanic, r.PackagePanic, "PackagePanic mismatch for %s", r.TestName)
1129+
assert.Equal(t, exp.panic, r.Panic, "Panic mismatch for %s", r.TestName)
1130+
assert.InDelta(t, exp.passRatio, r.PassRatio, 0.001, "PassRatio mismatch for %s", r.TestName)
1131+
assert.Equal(t, exp.runs, r.Runs, "Runs mismatch for %s", r.TestName)
1132+
assert.Equal(t, exp.failures, r.Failures, "Failures mismatch for %s", r.TestName)
1133+
assert.Equal(t, exp.successes, r.Successes, "Successes mismatch for %s", r.TestName)
1134+
assert.Equal(t, exp.skipped, r.Skipped, "Skipped mismatch for %s", r.TestName)
1135+
assert.Equal(t, exp.skips, r.Skips, "Skips count mismatch for %s", r.TestName)
1136+
}
1137+
1138+
1139+
}
1140+
1141+
func TestParseFiles_WithPanicEventFileSpecific(t *testing.T) {
1142+
t.Parallel()
1143+
1144+
parser := NewParser()
1145+
filePath := "testdata/events-with-panic-single.json"
1146+
1147+
results, _, err := parser.ParseFiles([]string{filePath}, "run", 1, Config{})
1148+
if err != nil {
1149+
t.Fatalf("Failed to parse event file: %v", err)
1150+
}
1151+
assert.Equal(t, 1, len(results), "Expected 6 test results from file.")
1152+
1153+
testResult := results[0]
1154+
1155+
assert.True(t, testResult.Panic, "Expected test result to be marked as panic")
1156+
assert.True(t, testResult.PackagePanic, "Expected test result to be marked as panic")
1157+
assert.Equal(t, "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/capabilities/workflows/syncer", testResult.TestPackage, "Test package mismatch")
1158+
assert.Equal(t, "Test_RegistrySyncer_WorkflowRegistered_InitiallyActivated", testResult.TestName, "Test name mismatch")
1159+
}

0 commit comments

Comments
 (0)