Skip to content

Commit 3ecf053

Browse files
committed
Reject test options in the fake pipelines service as the service does
1 parent 510740f commit 3ecf053

3 files changed

Lines changed: 54 additions & 0 deletions

File tree

‎libs/testserver/pipelines.go‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ func (s *FakeWorkspace) PipelineStartUpdate(pipelineId string, body []byte) Resp
181181
Body: map[string]string{"error_code": "INVALID_PARAMETER_VALUE", "message": "test_options requires test_only to be true."},
182182
}
183183
}
184+
if test.TestOptions != nil {
185+
if message := pipelineTestOptionsError(test.TestOptions.PytestArgs, test.TestOptions.TestSelection); message != "" {
186+
return Response{
187+
StatusCode: 400,
188+
Body: map[string]string{"error_code": "INVALID_PARAMETER_VALUE", "message": message},
189+
}
190+
}
191+
}
184192

185193
updateId := nextUUID()
186194
update := &fakePipelineUpdate{

‎libs/testserver/pipelines_testing.go‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,31 @@ type pipelineTestRequest struct {
105105

106106
var pipelineTestFunctionRegexp = regexp.MustCompile(`(?m)^def (test_\w+)\(`)
107107

108+
// pipelineTestOptionsError returns the service's message for test options that it rejects, or "". Like
109+
// PipelineTestSelection in the service, pytest_args holds -k and -m, each followed by a value that is not
110+
// empty and does not start with "-", and each test selection is an absolute workspace path.
111+
func pipelineTestOptionsError(pytestArgs, selection []string) string {
112+
for i := 0; i < len(pytestArgs); i += 2 {
113+
option := pytestArgs[i]
114+
switch {
115+
case option != "-k" && option != "-m":
116+
return fmt.Sprintf("pytest_args accepts only -k and -m, each followed by its value. Got '%s'.", option)
117+
case i+1 == len(pytestArgs):
118+
return fmt.Sprintf("The pytest_args option '%s' must be followed by its value.", option)
119+
case strings.TrimSpace(pytestArgs[i+1]) == "":
120+
return fmt.Sprintf("The value of the pytest_args option '%s' must not be empty.", option)
121+
case strings.HasPrefix(pytestArgs[i+1], "-"):
122+
return fmt.Sprintf("The value of the pytest_args option '%s' must not start with '-'. Got '%s'.", option, pytestArgs[i+1])
123+
}
124+
}
125+
for _, entry := range selection {
126+
if p, _, _ := strings.Cut(strings.TrimSpace(entry), "::"); !strings.HasPrefix(p, "/") {
127+
return fmt.Sprintf("The test selection '%s' must be an absolute workspace path, such as /Workspace/Users/someone@example.com/orders/tests/test_orders.py.", entry)
128+
}
129+
}
130+
return ""
131+
}
132+
108133
// collectPipelineTests stands in for pytest collection: it finds the top-level "def test_*"
109134
// functions in the workspace test_*.py files under each selection, or under rootPath without one.
110135
// Like origin.test_case_id, a test ID is the absolute workspace path of its file followed by the

‎libs/testserver/pipelines_testing_test.go‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,27 @@ func TestPipelineStartUpdateRejectsTestOptionsWithoutTestOnly(t *testing.T) {
166166
assert.Equal(t, 400, response.StatusCode)
167167
}
168168

169+
func TestPipelineStartUpdateRejectsInvalidTestOptions(t *testing.T) {
170+
workspace := NewFakeWorkspace("http://test", "dbapi123")
171+
pipelineID := createTestPipelineWithTests(t, workspace)
172+
173+
// The messages are the service's, from PipelineTestSelection.
174+
for options, message := range map[string]string{
175+
`{"pytest_args": ["-korders"]}`: "pytest_args accepts only -k and -m, each followed by its value. Got '-korders'.",
176+
`{"pytest_args": ["-x"]}`: "pytest_args accepts only -k and -m, each followed by its value. Got '-x'.",
177+
`{"pytest_args": ["-m"]}`: "The pytest_args option '-m' must be followed by its value.",
178+
`{"pytest_args": ["-k", " "]}`: "The value of the pytest_args option '-k' must not be empty.",
179+
`{"pytest_args": ["-k", "-m"]}`: "The value of the pytest_args option '-k' must not start with '-'. Got '-m'.",
180+
`{"test_selection": ["tests/test_a.py::t"]}`: "The test selection 'tests/test_a.py::t' must be an absolute workspace path, such as /Workspace/Users/someone@example.com/orders/tests/test_orders.py.",
181+
} {
182+
response := workspace.PipelineStartUpdate(pipelineID, []byte(`{"test_only": true, "test_options": `+options+`}`))
183+
assert.Equal(t, 400, response.StatusCode, options)
184+
assert.Equal(t, map[string]string{"error_code": "INVALID_PARAMETER_VALUE", "message": message}, response.Body, options)
185+
}
186+
187+
startTestUpdate(t, workspace, pipelineID, `{"test_only": true, "test_options": {"pytest_args": ["-k", "orders", "-m", "smoke"], "test_selection": ["`+testRootPath+`/tests"]}}`)
188+
}
189+
169190
func TestPipelineFiniteUpdateIsActiveUntilItEnds(t *testing.T) {
170191
workspace := NewFakeWorkspace("http://test", "dbapi123")
171192
pipelineID := createTestPipelineWithTests(t, workspace)

0 commit comments

Comments
 (0)