From 6158f707d74c227512bec050f2e85f4eeaee5908 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Tue, 18 Nov 2025 09:07:32 -0800 Subject: [PATCH 1/2] Record metrics for mainnet forking --- internal/test/test.go | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/internal/test/test.go b/internal/test/test.go index 1f6438fc1..0cf2e7f19 100644 --- a/internal/test/test.go +++ b/internal/test/test.go @@ -26,6 +26,7 @@ import ( "os" "path/filepath" "regexp" + goRuntime "runtime" "strings" cdcTests "github.com/onflow/cadence-tools/test" @@ -41,6 +42,7 @@ import ( "github.com/onflow/flow-cli/common/branding" + "github.com/onflow/flow-cli/build" "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/internal/util" ) @@ -184,6 +186,12 @@ func testCode( flags flagsTests, ) (*result, error) { logger := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).With().Timestamp().Logger() + + // Track network resolutions per file for pragma-based fork detection + // Map: filename -> resolved network name + fileNetworkResolutions := make(map[string]string) + var currentTestFile string + // Resolve network labels using flow.json state resolveNetworkFromState := func(label string) (string, bool) { network, err := state.Networks().ByName(strings.ToLower(strings.TrimSpace(label))) @@ -193,6 +201,16 @@ func testCode( if strings.TrimSpace(network.Host) == "" { return "", false } + + // Track network resolution for current test file (indicates pragma-based fork usage) + // Only track if it's not the default "testing" network + normalizedLabel := strings.ToLower(strings.TrimSpace(label)) + if currentTestFile != "" && normalizedLabel != "testing" { + if _, exists := fileNetworkResolutions[currentTestFile]; !exists { + fileNetworkResolutions[currentTestFile] = normalizedLabel + } + } + return network.Host, true } @@ -284,6 +302,9 @@ func testCode( testResults := make(map[string]cdcTests.Results, 0) exitCode := 0 for scriptPath, code := range testFiles { + // Set current test file for network resolution tracking + currentTestFile = scriptPath + fileRunner := runner. WithImportResolver(importResolver(scriptPath, state)). WithFileResolver(fileResolver(scriptPath, state)). @@ -344,6 +365,45 @@ func testCode( break } } + + // Clear current test file after processing + currentTestFile = "" + } + + // Track fork test usage metrics per file + // Priority: pragma-based resolution first (more direct), then static flags + for scriptPath := range testFiles { + // Check if this file used pragma-based fork + if resolvedNetwork, hasPragma := fileNetworkResolutions[scriptPath]; hasPragma { + // Fork mode via pragma (e.g., #fork(mainnet) in test code) + command.TrackEvent("test-fork", map[string]any{ + "fork_source": "pragma", + "network": resolvedNetwork, + "chain_id": "", + "has_height": false, + "version": build.Semver(), + "os": goRuntime.GOOS, + "ci": os.Getenv("CI") != "", + }) + } else if forkCfg != nil { + // Fork mode via static flags (--fork or --fork-host) + forkSource := "static-flag" + if flags.ForkHost != "" { + forkSource = "fork-host-flag" + } else if flags.Fork != "" { + forkSource = "fork-flag" + } + + command.TrackEvent("test-fork", map[string]any{ + "fork_source": forkSource, + "network": networkLabel, + "chain_id": forkCfg.ChainID.String(), + "has_height": forkCfg.ForkHeight > 0, + "version": build.Semver(), + "os": goRuntime.GOOS, + "ci": os.Getenv("CI") != "", + }) + } } return &result{ From 5cca4c09b4c5ccea0cdebd519a208a68fa92a440 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Tue, 18 Nov 2025 09:39:48 -0800 Subject: [PATCH 2/2] lighten metrics --- internal/test/test.go | 84 +++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/internal/test/test.go b/internal/test/test.go index 0cf2e7f19..2bdebe4a7 100644 --- a/internal/test/test.go +++ b/internal/test/test.go @@ -186,12 +186,12 @@ func testCode( flags flagsTests, ) (*result, error) { logger := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).With().Timestamp().Logger() - + // Track network resolutions per file for pragma-based fork detection // Map: filename -> resolved network name fileNetworkResolutions := make(map[string]string) var currentTestFile string - + // Resolve network labels using flow.json state resolveNetworkFromState := func(label string) (string, bool) { network, err := state.Networks().ByName(strings.ToLower(strings.TrimSpace(label))) @@ -201,7 +201,7 @@ func testCode( if strings.TrimSpace(network.Host) == "" { return "", false } - + // Track network resolution for current test file (indicates pragma-based fork usage) // Only track if it's not the default "testing" network normalizedLabel := strings.ToLower(strings.TrimSpace(label)) @@ -210,7 +210,7 @@ func testCode( fileNetworkResolutions[currentTestFile] = normalizedLabel } } - + return network.Host, true } @@ -304,7 +304,7 @@ func testCode( for scriptPath, code := range testFiles { // Set current test file for network resolution tracking currentTestFile = scriptPath - + fileRunner := runner. WithImportResolver(importResolver(scriptPath, state)). WithFileResolver(fileResolver(scriptPath, state)). @@ -365,45 +365,61 @@ func testCode( break } } - + // Clear current test file after processing currentTestFile = "" } - // Track fork test usage metrics per file - // Priority: pragma-based resolution first (more direct), then static flags - for scriptPath := range testFiles { - // Check if this file used pragma-based fork - if resolvedNetwork, hasPragma := fileNetworkResolutions[scriptPath]; hasPragma { - // Fork mode via pragma (e.g., #fork(mainnet) in test code) - command.TrackEvent("test-fork", map[string]any{ - "fork_source": "pragma", - "network": resolvedNetwork, - "chain_id": "", - "has_height": false, - "version": build.Semver(), - "os": goRuntime.GOOS, - "ci": os.Getenv("CI") != "", - }) - } else if forkCfg != nil { - // Fork mode via static flags (--fork or --fork-host) - forkSource := "static-flag" + // Track fork test usage metrics - aggregate into single event + hasPragmaFiles := len(fileNetworkResolutions) > 0 + hasStaticFork := forkCfg != nil + + if hasPragmaFiles || hasStaticFork { + // Determine primary fork source + forkSource := "none" + var primaryNetwork string + var chainID string + hasHeight := false + + if hasPragmaFiles { + // Pragma takes priority - collect unique networks + forkSource = "pragma" + networkSet := make(map[string]bool) + for _, network := range fileNetworkResolutions { + networkSet[network] = true + } + // Use first resolved network as primary (for single-value tracking) + for _, network := range fileNetworkResolutions { + primaryNetwork = network + break + } + // If multiple networks, note that in source + if len(networkSet) > 1 { + forkSource = "pragma-mixed" + } + } else if hasStaticFork { + // Static flags if flags.ForkHost != "" { forkSource = "fork-host-flag" } else if flags.Fork != "" { forkSource = "fork-flag" } - - command.TrackEvent("test-fork", map[string]any{ - "fork_source": forkSource, - "network": networkLabel, - "chain_id": forkCfg.ChainID.String(), - "has_height": forkCfg.ForkHeight > 0, - "version": build.Semver(), - "os": goRuntime.GOOS, - "ci": os.Getenv("CI") != "", - }) + primaryNetwork = networkLabel + chainID = forkCfg.ChainID.String() + hasHeight = forkCfg.ForkHeight > 0 } + + command.TrackEvent("test-fork", map[string]any{ + "fork_source": forkSource, + "network": primaryNetwork, + "chain_id": chainID, + "has_height": hasHeight, + "pragma_files": len(fileNetworkResolutions), + "total_files": len(testFiles), + "version": build.Semver(), + "os": goRuntime.GOOS, + "ci": os.Getenv("CI") != "", + }) } return &result{