Merge pull request #14638 from roidelapluie/evalsubtest

promqltest: run each eval command in a subtest
pull/15492/head
George Krajcsovits 2024-12-03 12:41:37 +01:00 committed by GitHub
commit aceabbc81c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 34 additions and 11 deletions

View File

@ -66,7 +66,7 @@ var testStartTime = time.Unix(0, 0).UTC()
// LoadedStorage returns storage with generated data using the provided load statements. // LoadedStorage returns storage with generated data using the provided load statements.
// Non-load statements will cause test errors. // Non-load statements will cause test errors.
func LoadedStorage(t testutil.T, input string) *teststorage.TestStorage { func LoadedStorage(t testutil.T, input string) *teststorage.TestStorage {
test, err := newTest(t, input) test, err := newTest(t, input, false)
require.NoError(t, err) require.NoError(t, err)
for _, cmd := range test.cmds { for _, cmd := range test.cmds {
@ -125,11 +125,17 @@ func RunBuiltinTests(t TBRun, engine promql.QueryEngine) {
// RunTest parses and runs the test against the provided engine. // RunTest parses and runs the test against the provided engine.
func RunTest(t testutil.T, input string, engine promql.QueryEngine) { func RunTest(t testutil.T, input string, engine promql.QueryEngine) {
require.NoError(t, runTest(t, input, engine)) require.NoError(t, runTest(t, input, engine, false))
} }
func runTest(t testutil.T, input string, engine promql.QueryEngine) error { // testTest allows tests to be run in "test-the-test" mode (true for
test, err := newTest(t, input) // testingMode). This is a special mode for testing test code execution itself.
func testTest(t testutil.T, input string, engine promql.QueryEngine) error {
return runTest(t, input, engine, true)
}
func runTest(t testutil.T, input string, engine promql.QueryEngine, testingMode bool) error {
test, err := newTest(t, input, testingMode)
// Why do this before checking err? newTest() can create the test storage and then return an error, // Why do this before checking err? newTest() can create the test storage and then return an error,
// and we want to make sure to clean that up to avoid leaking goroutines. // and we want to make sure to clean that up to avoid leaking goroutines.
@ -164,6 +170,8 @@ func runTest(t testutil.T, input string, engine promql.QueryEngine) error {
// against a test storage. // against a test storage.
type test struct { type test struct {
testutil.T testutil.T
// testingMode distinguishes between normal execution and test-execution mode.
testingMode bool
cmds []testCommand cmds []testCommand
@ -174,10 +182,11 @@ type test struct {
} }
// newTest returns an initialized empty Test. // newTest returns an initialized empty Test.
func newTest(t testutil.T, input string) (*test, error) { func newTest(t testutil.T, input string, testingMode bool) (*test, error) {
test := &test{ test := &test{
T: t, T: t,
cmds: []testCommand{}, cmds: []testCommand{},
testingMode: testingMode,
} }
err := test.parse(input) err := test.parse(input)
test.clear() test.clear()
@ -1078,6 +1087,7 @@ func (t *test) exec(tc testCommand, engine promql.QueryEngine) error {
} }
func (t *test) execEval(cmd *evalCmd, engine promql.QueryEngine) error { func (t *test) execEval(cmd *evalCmd, engine promql.QueryEngine) error {
do := func() error {
if cmd.isRange { if cmd.isRange {
return t.execRangeEval(cmd, engine) return t.execRangeEval(cmd, engine)
} }
@ -1085,6 +1095,19 @@ func (t *test) execEval(cmd *evalCmd, engine promql.QueryEngine) error {
return t.execInstantEval(cmd, engine) return t.execInstantEval(cmd, engine)
} }
if t.testingMode {
return do()
}
if tt, ok := t.T.(*testing.T); ok {
tt.Run(fmt.Sprintf("line %d/%s", cmd.line, cmd.expr), func(t *testing.T) {
require.NoError(t, do())
})
return nil
}
return errors.New("t.T is not testing.T")
}
func (t *test) execRangeEval(cmd *evalCmd, engine promql.QueryEngine) error { func (t *test) execRangeEval(cmd *evalCmd, engine promql.QueryEngine) error {
q, err := engine.NewRangeQuery(t.context, t.storage, nil, cmd.expr, cmd.start, cmd.end, cmd.step) q, err := engine.NewRangeQuery(t.context, t.storage, nil, cmd.expr, cmd.start, cmd.end, cmd.step)
if err != nil { if err != nil {

View File

@ -595,7 +595,7 @@ eval range from 0 to 5m step 5m testmetric
for name, testCase := range testCases { for name, testCase := range testCases {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
err := runTest(t, testCase.input, NewTestEngine(t, false, 0, DefaultMaxSamplesPerQuery)) err := testTest(t, testCase.input, NewTestEngine(t, false, 0, DefaultMaxSamplesPerQuery))
if testCase.expectedError == "" { if testCase.expectedError == "" {
require.NoError(t, err) require.NoError(t, err)