Repository: pingcap/tidb
File: pkg/executor/adapter_test.go (Go)

Code before:
		expectTimeout    bool
		description      string
	}{
		{
			name:             "TSO delay 300ms, timeout 1000ms - should not timeout",
			tsoDelayMs:       300,
			maxExecutionTime: 1000,
			expectTimeout:    false,
			description:      "TSO wait time (300ms) should be included, total < 1000ms",
		},
		{
			name:             "TSO delay 800ms, timeout 1000ms - should not timeout",
			tsoDelayMs:       800,
			maxExecutionTime: 1000,
			expectTimeout:    false,
			description:      "TSO wait time (800ms) should be included, total < 1000ms",
		},
		{
			name:             "TSO delay 1200ms, timeout 500ms - should timeout",
			tsoDelayMs:       1200,
			maxExecutionTime: 500,
			expectTimeout:    true,
			description:      "TSO wait time (1200ms) exceeds timeout (500ms)",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// Enable failpoint to inject delay in TSO Wait()
			failpointName := "github.com/pingcap/tidb/pkg/sessiontxn/isolation/injectTSOWaitDelay"
			require.NoError(t, failpoint.Enable(failpointName, `return(`+fmt.Sprintf("%d", tc.tsoDelayMs)+`)`))
			defer func() {
				require.NoError(t, failpoint.Disable(failpointName))
			}()
			// Set max_execution_time
			tk.MustExec("set @@max_execution_time = ?", tc.maxExecutionTime)

			// Execute a SELECT statement that will trigger TSO wait
			// Use range scan instead of point get to avoid optimization
			startTime := time.Now()
			if tc.expectTimeout {
				err := tk.QueryToErr("select * from t where a >= 1")
				if err != nil {
					require.Contains(t, err.Error(), "maximum statement execution time exceeded")
				} else {
					pi := tk.Session().ShowProcess()
					require.NotNil(t, pi)
					processElapsed := time.Since(pi.Time)
					require.GreaterOrEqual(t, processElapsed, time.Duration(tc.maxExecutionTime)*time.Millisecond,
						"ProcessInfo elapsed time should exceed max_execution_time. Got %v", processElapsed)
				}

Review comment (performance):
The test may be flaky in CI due to:
1. Long execution time: Total sleep time is 300+800+1200 = 2.3s, which could be slower under CI load.
2. Tight margins: The case {tsoDelayMs: 800, maxExecutionTime: 1000} has only 200ms headroom, which may not be enough when CI is under heavy load.

Suggestion: Reduce sleep times and increase the gap between delay and timeout:
```
testCases := []struct {
    // ...
}{
    {
        name:             "no timeout - TSO delay within limit",
        tsoDelayMs:       50,
        maxExecutionTime: 500,  // 450ms headroom
        expectTimeout:    false,
    },
    {
        name:             "timeout - TSO delay exceeds limit", 
        tsoDelayMs:       200,
        maxExecutionTime: 50,   // clear 150ms gap
        expectTimeout:    true,
    },
}
```


Code after:
		maxExecutionTime uint64 // in milliseconds
		expectTimeout    bool
		description      string
	}{
		{
			name:             "TSO delay 50ms, timeout 500ms - should not timeout",
			tsoDelayMs:       50,
			maxExecutionTime: 500,
			expectTimeout:    false,
			description:      "TSO wait time (50ms) should be included, total << 500ms",
		},
		{
			name:             "TSO delay 150ms, timeout 500ms - should not timeout",
			tsoDelayMs:       150,
			maxExecutionTime: 500,
			expectTimeout:    false,
			description:      "TSO wait time (150ms) should be included, total << 500ms",
		},
		{
			name:             "TSO delay 300ms, timeout 50ms - should timeout",
			tsoDelayMs:       300,
			maxExecutionTime: 50,
			expectTimeout:    true,
			description:      "TSO wait time (300ms) exceeds timeout (50ms) clearly",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// Enable failpoint to inject delay in TSO Wait()
			failpointName := "github.com/pingcap/tidb/pkg/sessiontxn/isolation/injectTSOWaitDelay"
			require.NoError(t, failpoint.Enable(failpointName, `return(`+fmt.Sprintf("%d", tc.tsoDelayMs)+`)`))
			defer func() {
				require.NoError(t, failpoint.Disable(failpointName))
			}()
			// Set max_execution_time
			tk.MustExec("set @@max_execution_time = ?", tc.maxExecutionTime)

			// Execute a SELECT statement that will trigger TSO wait
			// Use range scan instead of point get to avoid optimization
			startTime := time.Now()
			if tc.expectTimeout {
				err := tk.QueryToErr("select * from t where a >= 1")
				if err != nil {
					require.Contains(t, err.Error(), "maximum statement execution time exceeded")
				} else {
					pi := tk.Session().ShowProcess()
					require.NotNil(t, pi)
					processElapsed := time.Since(pi.Time)
					require.GreaterOrEqual(t, processElapsed, time.Duration(tc.maxExecutionTime)*time.Millisecond,
						"ProcessInfo elapsed time should exceed max_execution_time. Got %v", processElapsed)