-
Notifications
You must be signed in to change notification settings - Fork 11
[TE-5134] Add --tag-filters option to filter tests by markers #426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0b84a10
f773ced
45f3cd1
f8631b6
275be6d
6cac698
b66f625
1a7169a
fb712ca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| golang 1.25.2 | ||
| nodejs 24.9.0 | ||
| python 3.13.2 | ||
| uv 0.9.26 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,8 +11,13 @@ import ( | |
| ) | ||
|
|
||
| // createRequestParam generates the parameters needed for a test plan request. | ||
| // For runners other than "rspec", it constructs the test plan parameters with all test files. | ||
| // For the "rspec" runner, it filters the test files through the Test Engine API and splits the filtered files into examples. | ||
| // | ||
| // For the Rspec, Cucumber and Pytest runner, it fetches test files through the Test Engine API | ||
| // that are slow or contain skipped tests. These files are then split into examples | ||
| // The remaining files are sent as is. | ||
| // | ||
| // If tag filtering is enabled, all files are split into examples to support filtering. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| // Currently only the Pytest runner supports tag filtering. | ||
| func createRequestParam(ctx context.Context, cfg *config.Config, files []string, client api.Client, runner TestRunner) (api.TestPlanParams, error) { | ||
| testFiles := []plan.TestCase{} | ||
| for _, file := range files { | ||
|
|
@@ -50,10 +55,21 @@ func createRequestParam(ctx context.Context, cfg *config.Config, files []string, | |
| debug.Println("Splitting by example") | ||
| } | ||
|
|
||
| // The SplitByExample flag indicates whether to filter slow files for splitting by example. | ||
| // Regardless of the flag's state, the API will still filter other files that need to be split by example, such as those containing skipped tests. | ||
| // Therefore, we must filter and split files even when SplitByExample is disabled. | ||
| testParams, err := filterAndSplitFiles(ctx, cfg, client, testFiles, runner) | ||
| var testParams api.TestPlanParamsTest | ||
| var err error | ||
|
|
||
| // If tag filtering is enabled, we must split all files to allow to enable filtering. | ||
| // Tag filtering is currently only supported for pytest. | ||
| if cfg.TagFilters != "" && runner.Name() == "pytest" { | ||
| testParams, err = splitAllFiles(testFiles, runner) | ||
| } else { | ||
| // The SplitByExample flag indicates whether to split slow files into examples. | ||
| // Regardless of the flag's state, the API will still return other test files that need to | ||
| // be split by example, such as those containing skipped tests. | ||
| // Therefore, we must fetch and split files even when SplitByExample is disabled. | ||
| testParams, err = filterAndSplitFiles(ctx, cfg, client, testFiles, runner) | ||
| } | ||
|
|
||
| if err != nil { | ||
| return api.TestPlanParams{}, err | ||
| } | ||
|
|
@@ -69,6 +85,26 @@ func createRequestParam(ctx context.Context, cfg *config.Config, files []string, | |
| }, nil | ||
| } | ||
|
|
||
| // Splits all the test files into examples to support tag filtering. | ||
| func splitAllFiles(files []plan.TestCase, runner TestRunner) (api.TestPlanParamsTest, error) { | ||
| debug.Printf("Splitting all %d files", len(files)) | ||
| filePaths := make([]string, 0, len(files)) | ||
| for _, file := range files { | ||
| filePaths = append(filePaths, file.Path) | ||
| } | ||
|
|
||
| examples, err := runner.GetExamples(filePaths) | ||
| if err != nil { | ||
| return api.TestPlanParamsTest{}, fmt.Errorf("get examples: %w", err) | ||
| } | ||
|
|
||
| debug.Printf("Got %d examples from all files", len(examples)) | ||
|
|
||
| return api.TestPlanParamsTest{ | ||
| Examples: examples, | ||
| }, nil | ||
| } | ||
|
|
||
| // filterAndSplitFiles filters the test files through the Test Engine API and splits the filtered files into examples. | ||
| // It returns the test plan parameters with the examples from the filtered files and the remaining files. | ||
| // An error is returned if there is a failure in any of the process. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -693,7 +693,6 @@ func TestCreateRequestParams(t *testing.T) { | |
| TestCommand: "rspec", | ||
| }, | ||
| }) | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤔 why these whitespace removals?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems the linter in my editor is doing this! I'll see if I can track down which one
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep it was We had an internal discussion about using |
||
| if err != nil { | ||
| t.Errorf("createRequestParam() error = %v", err) | ||
| } | ||
|
|
@@ -778,7 +777,6 @@ func TestCreateRequestParams_NonRSpec(t *testing.T) { | |
| } | ||
|
|
||
| got, err := createRequestParam(context.Background(), &cfg, files, *client, r) | ||
|
|
||
| if err != nil { | ||
| t.Errorf("createRequestParam() error = %v", err) | ||
| } | ||
|
|
@@ -838,7 +836,6 @@ func TestCreateRequestParams_PytestPants(t *testing.T) { | |
| } | ||
|
|
||
| got, err := createRequestParam(context.Background(), &cfg, files, *client, runner) | ||
|
|
||
| if err != nil { | ||
| t.Errorf("createRequestParam() error = %v", err) | ||
| } | ||
|
|
@@ -935,7 +932,6 @@ func TestCreateRequestParams_NoFilteredFiles(t *testing.T) { | |
| TestCommand: "rspec", | ||
| }, | ||
| }) | ||
|
|
||
| if err != nil { | ||
| t.Errorf("createRequestParam() error = %v", err) | ||
| } | ||
|
|
@@ -962,6 +958,122 @@ func TestCreateRequestParams_NoFilteredFiles(t *testing.T) { | |
| } | ||
| } | ||
|
|
||
| func TestCreateRequestParams_WithTagFilters(t *testing.T) { | ||
| cfg := config.Config{ | ||
| OrganizationSlug: "my-org", | ||
| SuiteSlug: "my-suite", | ||
| Identifier: "identifier", | ||
| Parallelism: 2, | ||
| Branch: "main", | ||
| TestRunner: "pytest", | ||
| TagFilters: "team:frontend", | ||
| } | ||
|
|
||
| client := api.NewClient(api.ClientConfig{ | ||
| ServerBaseUrl: "example.com", | ||
| }) | ||
|
|
||
| files := []string{ | ||
| "../runner/testdata/pytest/failed_test.py", | ||
| "../runner/testdata/pytest/test_sample.py", | ||
| "../runner/testdata/pytest/spells/test_expelliarmus.py", | ||
| } | ||
|
|
||
| got, err := createRequestParam(context.Background(), &cfg, files, *client, runner.Pytest{ | ||
| RunnerConfig: runner.RunnerConfig{ | ||
| TestCommand: "pytest", | ||
| TagFilters: "team:frontend", | ||
| }, | ||
| }) | ||
| if err != nil { | ||
| t.Errorf("createRequestParam() error = %v", err) | ||
| } | ||
|
|
||
| want := api.TestPlanParams{ | ||
| Identifier: "identifier", | ||
| Parallelism: 2, | ||
| Branch: "main", | ||
| Runner: "pytest", | ||
| Tests: api.TestPlanParamsTest{ | ||
| Examples: []plan.TestCase{ | ||
| { | ||
| Format: "example", | ||
| Identifier: "runner/testdata/pytest/test_sample.py::test_happy", | ||
| Name: "test_happy", | ||
| Path: "runner/testdata/pytest/test_sample.py::test_happy", | ||
| Scope: "runner/testdata/pytest/test_sample.py", | ||
| }, | ||
| { | ||
| Format: "example", | ||
| Identifier: "runner/testdata/pytest/spells/test_expelliarmus.py::TestExpelliarmus::test_knocks_wand_out", | ||
| Name: "test_knocks_wand_out", | ||
| Path: "runner/testdata/pytest/spells/test_expelliarmus.py::TestExpelliarmus::test_knocks_wand_out", | ||
| Scope: "runner/testdata/pytest/spells/test_expelliarmus.py::TestExpelliarmus", | ||
| }, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| if diff := cmp.Diff(got, want); diff != "" { | ||
| t.Errorf("createRequestParam() diff (-got +want):\n%s", diff) | ||
| } | ||
| } | ||
|
|
||
| func TestCreateRequestParams_WithTagFilters_NonPytest(t *testing.T) { | ||
| svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| fmt.Fprint(w, ` | ||
| { | ||
| "tests": [] | ||
| }`) | ||
| })) | ||
| defer svr.Close() | ||
|
|
||
| cfg := config.Config{ | ||
| OrganizationSlug: "my-org", | ||
| SuiteSlug: "my-suite", | ||
| Identifier: "identifier", | ||
| Parallelism: 2, | ||
| Branch: "main", | ||
| TestRunner: "rspec", | ||
| TagFilters: "team:frontend", | ||
| } | ||
|
|
||
| client := api.NewClient(api.ClientConfig{ | ||
| ServerBaseUrl: svr.URL, | ||
| }) | ||
|
|
||
| files := []string{ | ||
| "testdata/rspec/spec/fruits/apple_spec.rb", | ||
| "testdata/rspec/spec/fruits/banana_spec.rb", | ||
| } | ||
|
|
||
| got, err := createRequestParam(context.Background(), &cfg, files, *client, runner.Rspec{ | ||
| RunnerConfig: runner.RunnerConfig{ | ||
| TestCommand: "rspec", | ||
| }, | ||
| }) | ||
| if err != nil { | ||
| t.Errorf("createRequestParam() error = %v", err) | ||
| } | ||
|
|
||
| want := api.TestPlanParams{ | ||
| Identifier: "identifier", | ||
| Parallelism: 2, | ||
| Branch: "main", | ||
| Runner: "rspec", | ||
| Tests: api.TestPlanParamsTest{ | ||
| Files: []plan.TestCase{ | ||
| {Path: "testdata/rspec/spec/fruits/apple_spec.rb"}, | ||
| {Path: "testdata/rspec/spec/fruits/banana_spec.rb"}, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| if diff := cmp.Diff(got, want); diff != "" { | ||
| t.Errorf("createRequestParam() diff (-got +want):\n%s", diff) | ||
| } | ||
| } | ||
|
|
||
| func TestSendMetadata(t *testing.T) { | ||
| originalVersion := version.Version | ||
| version.Version = "0.1.0" | ||
|
|
@@ -1019,7 +1131,6 @@ func TestSendMetadata(t *testing.T) { | |
| } else { | ||
| w.WriteHeader(http.StatusOK) | ||
| } | ||
|
|
||
| })) | ||
| defer svr.Close() | ||
|
|
||
|
|
@@ -1070,7 +1181,6 @@ func TestRunTestsWithRetry_NoTestCases_Success(t *testing.T) { | |
| failOnNoTests := false | ||
|
|
||
| testResult, err := runTestsWithRetry(testRunner, &testCases, maxRetries, []plan.TestCase{}, &timeline, true, failOnNoTests) | ||
|
|
||
| if err != nil { | ||
| t.Errorf("runTestsWithRetry(...) error = %v, want nil", err) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarifying comments to not confuse
filter_testswith tag filtering. This class is actually fetching test files, not really filtering down the tests/files to execute.