-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
982 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"regexp" | ||
"strings" | ||
|
||
"github.com/spf13/cobra" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
type JobConfig struct { | ||
Jobs map[string]struct { | ||
Strategy struct { | ||
Matrix struct { | ||
Test []struct { | ||
Path string `yaml:"path"` | ||
TestOpts string `yaml:"testOpts"` | ||
} `yaml:"test"` | ||
} `yaml:"matrix"` | ||
} `yaml:"strategy"` | ||
} `yaml:"jobs"` | ||
} | ||
|
||
var checkTestsCmd = &cobra.Command{ | ||
Use: "check-tests [directory] [yaml file]", | ||
Short: "Check if all tests in a directory are included in the test configurations YAML file", | ||
Args: cobra.ExactArgs(2), | ||
Run: func(_ *cobra.Command, args []string) { | ||
directory := args[0] | ||
yamlFile := args[1] | ||
excludedDirs := []string{"../../citool"} | ||
tests, err := extractTests(directory, excludedDirs) | ||
if err != nil { | ||
fmt.Println("Error extracting tests:", err) | ||
os.Exit(1) | ||
} | ||
|
||
checkTestsInPipeline(yamlFile, tests) | ||
}, | ||
} | ||
|
||
// extractTests scans the given directory and subdirectories (except the excluded ones) | ||
// for Go test files, extracts test function names, and returns a slice of Test. | ||
func extractTests(dir string, excludeDirs []string) ([]Test, error) { | ||
var tests []Test | ||
|
||
// Resolve to absolute path | ||
absDir, err := filepath.Abs(dir) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// filepath.WalkDir provides more control and is more efficient for skipping directories | ||
err = filepath.WalkDir(absDir, func(path string, d os.DirEntry, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Check if the current path is one of the excluded directories | ||
for _, exclude := range excludeDirs { | ||
absExclude, _ := filepath.Abs(exclude) | ||
if strings.HasPrefix(path, absExclude) { | ||
if d.IsDir() { | ||
return filepath.SkipDir // Skip this directory | ||
} | ||
return nil // Skip this file | ||
} | ||
} | ||
|
||
if !d.IsDir() && strings.HasSuffix(d.Name(), "_test.go") { | ||
content, err := os.ReadFile(path) | ||
if err != nil { | ||
return err | ||
} | ||
re := regexp.MustCompile(`func (Test\w+)`) | ||
matches := re.FindAllSubmatch(content, -1) | ||
for _, match := range matches { | ||
funcName := string(match[1]) | ||
if funcName == "TestMain" { // Skip "TestMain" | ||
continue | ||
} | ||
tests = append(tests, Test{ | ||
Name: funcName, | ||
Path: mustExtractSubpath(path, "integration-tests"), | ||
}) | ||
} | ||
} | ||
return nil | ||
}) | ||
|
||
return tests, err | ||
} | ||
|
||
// ExtractSubpath extracts a specific subpath from a given full path. | ||
// If the subpath is not found, it returns an error. | ||
func mustExtractSubpath(fullPath, subPath string) string { | ||
index := strings.Index(fullPath, subPath) | ||
if index == -1 { | ||
panic("subpath not found in the provided full path") | ||
} | ||
return fullPath[index:] | ||
} | ||
|
||
func checkTestsInPipeline(yamlFile string, tests []Test) { | ||
data, err := os.ReadFile(yamlFile) | ||
if err != nil { | ||
fmt.Printf("Error reading YAML file: %s\n", err) | ||
return | ||
} | ||
|
||
var config Config | ||
err = yaml.Unmarshal(data, &config) | ||
if err != nil { | ||
fmt.Printf("Error parsing YAML: %s\n", err) | ||
return | ||
} | ||
|
||
missingTests := []string{} // Track missing tests | ||
|
||
for _, test := range tests { | ||
found := false | ||
for _, item := range config.Tests { | ||
if item.Path == test.Path { | ||
if strings.Contains(item.TestCmd, "-test.run") { | ||
if matchTestNameInCmd(item.TestCmd, test.Name) { | ||
found = true | ||
break | ||
} | ||
} else { | ||
found = true | ||
break | ||
} | ||
} | ||
} | ||
if !found { | ||
missingTests = append(missingTests, fmt.Sprintf("ERROR: Test '%s' in file '%s' does not have CI configuration in '%s'", test.Name, test.Path, yamlFile)) | ||
} | ||
} | ||
|
||
if len(missingTests) > 0 { | ||
for _, missing := range missingTests { | ||
fmt.Println(missing) | ||
} | ||
os.Exit(1) // Exit with a failure status | ||
} | ||
} | ||
|
||
// matchTestNameInCmd checks if the given test name matches the -test.run pattern in the command string. | ||
func matchTestNameInCmd(cmd string, testName string) bool { | ||
testRunRegex := regexp.MustCompile(`-test\.run ([^\s]+)`) | ||
matches := testRunRegex.FindStringSubmatch(cmd) | ||
if len(matches) > 1 { | ||
// Extract the regex pattern used in the -test.run command | ||
pattern := matches[1] | ||
|
||
// Escape regex metacharacters in the testName before matching | ||
escapedTestName := regexp.QuoteMeta(testName) | ||
|
||
// Check if the escaped test name matches the extracted pattern | ||
return regexp.MustCompile(pattern).MatchString(escapedTestName) | ||
} | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package cmd | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestMatchTestNameInCmd(t *testing.T) { | ||
tests := []struct { | ||
cmd string | ||
testName string | ||
expected bool | ||
}{ | ||
{"go test -test.run ^TestExample$", "TestExample", true}, | ||
{"go test -test.run ^TestExample$", "TestAnother", false}, | ||
{"go test -test.run ^TestExample$ -v", "TestExample", true}, | ||
{"go test -test.run ^TestExamplePart$", "TestExample", false}, | ||
{"go test -test.run ^TestWithNumbers123$", "TestWithNumbers123", true}, | ||
{"go test -test.run ^Test_With_Underscores$", "Test_With_Underscores", true}, | ||
{"go test -test.run ^Test-With-Dash$", "Test-With-Dash", true}, | ||
{"go test -test.run ^TestWithSpace Space$", "TestWithSpace Space", true}, | ||
{"go test -test.run ^TestWithNewline\nNewline$", "TestWithNewline\nNewline", true}, | ||
{"go test -test.run ^TestOne$|^TestTwo$", "TestOne", true}, | ||
{"go test -test.run ^TestOne$|^TestTwo$", "TestTwo", true}, | ||
{"go test -test.run ^TestOne$|^TestTwo$", "TestThree", false}, | ||
{"go test -test.run TestOne|TestTwo", "TestTwo", true}, | ||
{"go test -test.run TestOne|TestTwo", "TestOne", true}, | ||
{"go test -test.run TestOne|TestTwo|TestThree", "TestFour", false}, | ||
{"go test -test.run ^TestOne$|TestTwo$", "TestTwo", true}, | ||
{"go test -test.run ^TestOne$|TestTwo|TestThree$", "TestThree", true}, | ||
{"go test -test.run TestOne|TestTwo|TestThree", "TestOne", true}, | ||
{"go test -test.run TestOne|TestTwo|TestThree", "TestThree", true}, | ||
{"go test -test.run ^TestA$|^TestB$|^TestC$", "TestA", true}, | ||
{"go test -test.run ^TestA$|^TestB$|^TestC$", "TestB", true}, | ||
{"go test -test.run ^TestA$|^TestB$|^TestC$", "TestD", false}, | ||
{"go test -test.run TestA|^TestB$|TestC", "TestB", true}, | ||
{"go test -test.run ^TestA|^TestB|TestC$", "TestA", true}, | ||
{"go test -test.run ^TestA|^TestB|TestC$", "TestC", true}, | ||
{"go test -test.run ^TestA|^TestB|TestC$", "TestD", false}, | ||
} | ||
|
||
for _, tt := range tests { | ||
result := matchTestNameInCmd(tt.cmd, tt.testName) | ||
if result != tt.expected { | ||
t.Errorf("matchTestNameInCmd(%s, %s) = %t; expected %t", tt.cmd, tt.testName, result, tt.expected) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/pelletier/go-toml/v2" | ||
"github.com/spf13/cobra" | ||
|
||
ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" | ||
ctf_config_types "github.com/smartcontractkit/chainlink-testing-framework/config/types" | ||
) | ||
|
||
var createTestConfigCmd = &cobra.Command{ | ||
Use: "create", | ||
Short: "Create a test config from the provided flags", | ||
Run: func(cmd *cobra.Command, _ []string) { | ||
var tc ctf_config.TestConfig | ||
|
||
var version, postgresVersion *string | ||
if cmd.Flags().Changed(ChainlinkVersionFlag) { | ||
version = &oc.ChainlinkVersion | ||
} | ||
if cmd.Flags().Changed(ChainlinkPostgresVersionFlag) { | ||
version = &oc.ChainlinkPostgresVersion | ||
} | ||
if version != nil || postgresVersion != nil { | ||
tc.ChainlinkImage = &ctf_config.ChainlinkImageConfig{ | ||
Version: version, | ||
PostgresVersion: postgresVersion, | ||
} | ||
} | ||
|
||
var upgradeVersion *string | ||
if cmd.Flags().Changed(ChainlinkUpgradeVersionFlag) { | ||
upgradeVersion = &oc.ChainlinkUpgradeVersion | ||
} | ||
if upgradeVersion != nil { | ||
tc.ChainlinkUpgradeImage = &ctf_config.ChainlinkImageConfig{ | ||
Version: upgradeVersion, | ||
} | ||
} | ||
|
||
var selectedNetworks *[]string | ||
if cmd.Flags().Changed(SelectedNetworksFlag) { | ||
selectedNetworks = &oc.SelectedNetworks | ||
} | ||
if selectedNetworks != nil { | ||
tc.Network = &ctf_config.NetworkConfig{ | ||
SelectedNetworks: oc.SelectedNetworks, | ||
} | ||
} | ||
|
||
var peryscopeEnabled *bool | ||
var pyroscopeServerURL, pyroscopeEnvironment, pyroscopeKey *string | ||
if cmd.Flags().Changed(PyroscopeEnabledFlag) { | ||
peryscopeEnabled = &oc.PyroscopeEnabled | ||
} | ||
if cmd.Flags().Changed(PyroscopeServerURLFlag) { | ||
pyroscopeServerURL = &oc.PyroscopeServerURL | ||
} | ||
if cmd.Flags().Changed(PyroscopeKeyFlag) { | ||
pyroscopeKey = &oc.PyroscopeKey | ||
} | ||
if cmd.Flags().Changed(PyroscopeEnvironmentFlag) { | ||
pyroscopeEnvironment = &oc.PyroscopeEnvironment | ||
} | ||
if peryscopeEnabled != nil { | ||
tc.Pyroscope = &ctf_config.PyroscopeConfig{ | ||
Enabled: peryscopeEnabled, | ||
ServerUrl: pyroscopeServerURL, | ||
Environment: pyroscopeEnvironment, | ||
Key: pyroscopeKey, | ||
} | ||
} | ||
|
||
var testLogCollect *bool | ||
if cmd.Flags().Changed(LoggingTestLogCollectFlag) { | ||
testLogCollect = &oc.LoggingTestLogCollect | ||
} | ||
var loggingRunID *string | ||
if cmd.Flags().Changed(LoggingRunIDFlag) { | ||
loggingRunID = &oc.LoggingRunID | ||
} | ||
var loggingLogTargets []string | ||
if cmd.Flags().Changed(LoggingLogTargetsFlag) { | ||
loggingLogTargets = oc.LoggingLogTargets | ||
} | ||
var loggingLokiTenantID *string | ||
if cmd.Flags().Changed(LoggingLokiTenantIDFlag) { | ||
loggingLokiTenantID = &oc.LoggingLokiTenantID | ||
} | ||
var loggingLokiBasicAuth *string | ||
if cmd.Flags().Changed(LoggingLokiBasicAuthFlag) { | ||
loggingLokiBasicAuth = &oc.LoggingLokiBasicAuth | ||
} | ||
var loggingLokiEndpoint *string | ||
if cmd.Flags().Changed(LoggingLokiEndpointFlag) { | ||
loggingLokiEndpoint = &oc.LoggingLokiEndpoint | ||
} | ||
var loggingGrafanaBaseURL *string | ||
if cmd.Flags().Changed(LoggingGrafanaBaseURLFlag) { | ||
loggingGrafanaBaseURL = &oc.LoggingGrafanaBaseURL | ||
} | ||
var loggingGrafanaDashboardURL *string | ||
if cmd.Flags().Changed(LoggingGrafanaDashboardURLFlag) { | ||
loggingGrafanaDashboardURL = &oc.LoggingGrafanaDashboardURL | ||
} | ||
var loggingGrafanaBearerToken *string | ||
if cmd.Flags().Changed(LoggingGrafanaBearerTokenFlag) { | ||
loggingGrafanaBearerToken = &oc.LoggingGrafanaBearerToken | ||
} | ||
|
||
if testLogCollect != nil || loggingRunID != nil || loggingLogTargets != nil || loggingLokiEndpoint != nil || loggingLokiTenantID != nil || loggingLokiBasicAuth != nil || loggingGrafanaBaseURL != nil || loggingGrafanaDashboardURL != nil || loggingGrafanaBearerToken != nil { | ||
tc.Logging = &ctf_config.LoggingConfig{} | ||
tc.Logging.TestLogCollect = testLogCollect | ||
tc.Logging.RunId = loggingRunID | ||
if loggingLogTargets != nil { | ||
tc.Logging.LogStream = &ctf_config.LogStreamConfig{ | ||
LogTargets: loggingLogTargets, | ||
} | ||
} | ||
if loggingLokiTenantID != nil || loggingLokiBasicAuth != nil || loggingLokiEndpoint != nil { | ||
tc.Logging.Loki = &ctf_config.LokiConfig{ | ||
TenantId: loggingLokiTenantID, | ||
BasicAuth: loggingLokiBasicAuth, | ||
Endpoint: loggingLokiEndpoint, | ||
} | ||
} | ||
if loggingGrafanaBaseURL != nil || loggingGrafanaDashboardURL != nil || loggingGrafanaBearerToken != nil { | ||
tc.Logging.Grafana = &ctf_config.GrafanaConfig{ | ||
BaseUrl: loggingGrafanaBaseURL, | ||
DashboardUrl: loggingGrafanaDashboardURL, | ||
BearerToken: loggingGrafanaBearerToken, | ||
} | ||
} | ||
} | ||
|
||
var privateEthereumNetworkExecutionLayer *string | ||
if cmd.Flags().Changed(PrivateEthereumNetworkExecutionLayerFlag) { | ||
privateEthereumNetworkExecutionLayer = &oc.PrivateEthereumNetworkExecutionLayer | ||
} | ||
var privateEthereumNetworkEthereumVersion *string | ||
if cmd.Flags().Changed(PrivateEthereumNetworkEthereumVersionFlag) { | ||
privateEthereumNetworkEthereumVersion = &oc.PrivateEthereumNetworkEthereumVersion | ||
} | ||
var privateEthereumNetworkCustomDockerImage *string | ||
if cmd.Flags().Changed(PrivateEthereumNetworkCustomDockerImageFlag) { | ||
privateEthereumNetworkCustomDockerImage = &oc.PrivateEthereumNetworkCustomDockerImages | ||
} | ||
if privateEthereumNetworkExecutionLayer != nil || privateEthereumNetworkEthereumVersion != nil || privateEthereumNetworkCustomDockerImage != nil { | ||
var el ctf_config_types.ExecutionLayer | ||
if privateEthereumNetworkExecutionLayer != nil { | ||
el = ctf_config_types.ExecutionLayer(*privateEthereumNetworkExecutionLayer) | ||
} | ||
var ev ctf_config_types.EthereumVersion | ||
if privateEthereumNetworkEthereumVersion != nil { | ||
ev = ctf_config_types.EthereumVersion(*privateEthereumNetworkEthereumVersion) | ||
} | ||
var customImages map[ctf_config.ContainerType]string | ||
if privateEthereumNetworkCustomDockerImage != nil { | ||
customImages = map[ctf_config.ContainerType]string{"execution_layer": *privateEthereumNetworkCustomDockerImage} | ||
} | ||
tc.PrivateEthereumNetwork = &ctf_config.EthereumNetworkConfig{ | ||
ExecutionLayer: &el, | ||
EthereumVersion: &ev, | ||
CustomDockerImages: customImages, | ||
} | ||
} | ||
|
||
configToml, err := toml.Marshal(tc) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Error marshalling TestConfig to TOML: %v\n", err) | ||
os.Exit(1) | ||
} | ||
|
||
fmt.Fprintln(cmd.OutOrStdout(), string(configToml)) | ||
}, | ||
} |
Oops, something went wrong.