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.
// Non-load statements will cause test errors.
func LoadedStorage(t testutil.T, input string) *teststorage.TestStorage {
test, err := newTest(t, input)
test, err := newTest(t, input, false)
require.NoError(t, err)
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.
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 {
test, err := newTest(t, input)
// testTest allows tests to be run in "test-the-test" mode (true for
// 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,
// 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.
type test struct {
testutil.T
// testingMode distinguishes between normal execution and test-execution mode.
testingMode bool
cmds []testCommand
@ -174,10 +182,11 @@ type test struct {
}
// 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{
T: t,
cmds: []testCommand{},
T: t,
cmds: []testCommand{},
testingMode: testingMode,
}
err := test.parse(input)
test.clear()
@ -1078,11 +1087,25 @@ func (t *test) exec(tc testCommand, engine promql.QueryEngine) error {
}
func (t *test) execEval(cmd *evalCmd, engine promql.QueryEngine) error {
if cmd.isRange {
return t.execRangeEval(cmd, engine)
do := func() error {
if cmd.isRange {
return t.execRangeEval(cmd, engine)
}
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 {

View File

@ -595,7 +595,7 @@ eval range from 0 to 5m step 5m testmetric
for name, testCase := range testCases {
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 == "" {
require.NoError(t, err)