Skip to content

Commit 21f90ca

Browse files
committed
Reuse passed test from previous pipeline
Signed-off-by: Yiqing Yan <[email protected]>
1 parent 5cd8c0f commit 21f90ca

File tree

3 files changed

+141
-4
lines changed

3 files changed

+141
-4
lines changed

jenkins/L0_MergeRequest.groovy

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ def launchStages(pipeline, reuseBuild, testFilter, enableFailFast, globalVars)
10391039
'wheelDockerImagePy312': globalVars["LLM_ROCKYLINUX8_PY312_DOCKER_IMAGE"],
10401040
]
10411041

1042-
launchJob("L0_Test-x86_64-Single-GPU", false, enableFailFast, globalVars, "x86_64", additionalParameters)
1042+
launchJob("L0_Test-x86_64-Single-GPU", reuseBuild, enableFailFast, globalVars, "x86_64", additionalParameters)
10431043
} catch (InterruptedException e) {
10441044
throw e
10451045
} catch (Exception e) {
@@ -1095,7 +1095,7 @@ def launchStages(pipeline, reuseBuild, testFilter, enableFailFast, globalVars)
10951095
'wheelDockerImagePy312': globalVars["LLM_ROCKYLINUX8_PY312_DOCKER_IMAGE"],
10961096
]
10971097

1098-
launchJob("L0_Test-x86_64-Multi-GPU", false, enableFailFast, globalVars, "x86_64", additionalParameters)
1098+
launchJob("L0_Test-x86_64-Multi-GPU", reuseBuild, enableFailFast, globalVars, "x86_64", additionalParameters)
10991099

11001100
} catch (InterruptedException e) {
11011101
throw e
@@ -1143,7 +1143,7 @@ def launchStages(pipeline, reuseBuild, testFilter, enableFailFast, globalVars)
11431143
"dockerImage": globalVars["LLM_SBSA_DOCKER_IMAGE"],
11441144
]
11451145

1146-
launchJob("L0_Test-SBSA-Single-GPU", false, enableFailFast, globalVars, "SBSA", additionalParameters)
1146+
launchJob("L0_Test-SBSA-Single-GPU", reuseBuild, enableFailFast, globalVars, "SBSA", additionalParameters)
11471147
} catch (InterruptedException e) {
11481148
throw e
11491149
} catch (Exception e) {
@@ -1197,7 +1197,7 @@ def launchStages(pipeline, reuseBuild, testFilter, enableFailFast, globalVars)
11971197
"dockerImage": globalVars["LLM_SBSA_DOCKER_IMAGE"],
11981198
]
11991199

1200-
launchJob("L0_Test-SBSA-Multi-GPU", false, enableFailFast, globalVars, "SBSA", additionalParameters)
1200+
launchJob("L0_Test-SBSA-Multi-GPU", reuseBuild, enableFailFast, globalVars, "SBSA", additionalParameters)
12011201

12021202
} catch (InterruptedException e) {
12031203
throw e

jenkins/L0_Test.groovy

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ LLM_ROOT = "llm"
2525
ARTIFACT_PATH = env.artifactPath ? env.artifactPath : "sw-tensorrt-generic/llm-artifacts/${JOB_NAME}/${BUILD_NUMBER}"
2626
UPLOAD_PATH = env.uploadPath ? env.uploadPath : "sw-tensorrt-generic/llm-artifacts/${JOB_NAME}/${BUILD_NUMBER}"
2727

28+
REUSE_ARITIFACT_PATH = env.reuseArtifactPath
29+
2830
X86_64_TRIPLE = "x86_64-linux-gnu"
2931
AARCH64_TRIPLE = "aarch64-linux-gnu"
3032

@@ -349,6 +351,10 @@ def runLLMTestlistOnSlurm_MultiNodes(pipeline, platform, testList, config=VANILL
349351
// if the line cannot be split by "=", just ignore that line.
350352
def makoOptsJson = transformMakoArgsToJson(["Mako options:"] + makoArgs)
351353
def testListPath = renderTestDB(testList, llmSrcLocal, stageName, makoOptsJson)
354+
// Reuse passed tests
355+
if (REUSE_ARITIFACT_PATH) {
356+
reusePassedTests(REUSE_ARITIFACT_PATH, stageName, testListPath)
357+
}
352358
Utils.exec(pipeline, script: "sshpass -p '${remote.passwd}' scp -r -p -oStrictHostKeyChecking=no ${testListPath} ${remote.user}@${remote.host}:${testListPathNode}",)
353359

354360
// Generate Multi Node Job Launch Script
@@ -1063,6 +1069,40 @@ def renderTestDB(testContext, llmSrc, stageName, preDefinedMakoOpts=null) {
10631069
return testList
10641070
}
10651071

1072+
def reusePassedTests(reusedArtifactPath, stageName, testListFile) {
1073+
def reusedPath = "${WORKSPACE}/reused"
1074+
sh "mkdir -p ${reusedPath}"
1075+
def resultsFileName = "results-${stageName}"
1076+
def passedTestsFile = "${reusedPath}/${stageName}/passed_tests.txt"
1077+
try {
1078+
trtllm_utils.llmExecStepWithRetry(pipeline, script: "cd ${reusedPath} && wget -nv ${reusedArtifactPath}/test-results/${resultsFileName}.tar.gz")
1079+
sh "cd ${reusedPath} && tar -zxf ${resultsFileName}.tar.gz"
1080+
// Get passed tests
1081+
sh """
1082+
python3 ${llmSrc}/jenkins/scripts/delete_passed_tests.py \
1083+
get_passed_tests \
1084+
--input-file=${reusedPath}/${stageName}/results.xml \
1085+
--output-file=${passedTestsFile}
1086+
"""
1087+
sh "The passed tests are: $(cat ${passedTestsFile})"
1088+
1089+
// Copy the original test file to a new file
1090+
sh "cp ${testListFile} original_${testListFile}"
1091+
// Remove passed tests from original test file
1092+
sh """
1093+
python3 ${llmSrc}/jenkins/scripts/delete_passed_tests.py \
1094+
remove_passed_tests \
1095+
--input-file=${testListFile} \
1096+
--passed-tests-file=${passedTestsFile}
1097+
"""
1098+
sh "The test list after removing passed tests is: $(cat ${testListFile})"
1099+
} catch (InterruptedException e) {
1100+
throw e
1101+
} catch (Exception e) {
1102+
echo "Failed to get passed tests: ${e.message}"
1103+
}
1104+
}
1105+
10661106
def getSSHConnectionPorts(portConfigFile, stageName)
10671107
{
10681108
def type = stageName.split('-')[0]
@@ -1409,6 +1449,11 @@ def runLLMTestlistOnPlatformImpl(pipeline, platform, testList, config=VANILLA_CO
14091449
extraInternalEnv += " CPP_TEST_TIMEOUT_OVERRIDDEN=${pytestTestTimeout}"
14101450

14111451
def testDBList = renderTestDB(testList, llmSrc, stageName)
1452+
// Reuse passed tests
1453+
if (REUSE_ARITIFACT_PATH) {
1454+
reusePassedTests(REUSE_ARITIFACT_PATH, stageName, testDBList)
1455+
}
1456+
14121457
testList = "${testList}_${splitId}"
14131458
def testCmdLine = [
14141459
"LLM_ROOT=${llmSrc}",
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import os
2+
import sys
3+
import argparse
4+
import xml.etree.ElementTree as ET
5+
from test_rerun import parse_name
6+
7+
def get_passed_tests(input_file, output_file):
8+
if not os.path.exists(input_file):
9+
print(f"Input file {input_file} does not exist")
10+
return
11+
12+
# Parse the JUnit XML file and extract passed test names
13+
passed_tests = []
14+
try:
15+
tree = ET.parse(input_file)
16+
root = tree.getroot()
17+
suite = root.find('testsuite')
18+
for testcase in suite.iter('testcase'):
19+
# Check test status
20+
has_failure = testcase.find('failure') is not None
21+
has_error = testcase.find('error') is not None
22+
has_skipped = testcase.find('skipped') is not None
23+
if not has_failure and not has_error and not has_skipped:
24+
# Parse the test name
25+
classname = testcase.attrib.get('classname', '')
26+
name = testcase.attrib.get('name', '')
27+
filename = testcase.attrib.get('file', '')
28+
testName = parse_name(classname, name, filename)
29+
passed_tests.append(testName)
30+
except Exception as e:
31+
print(f"Failed to parse {input_file}: {e}")
32+
return
33+
34+
# Write passed test names to output file, one per line
35+
with open(output_file, 'w') as f:
36+
for test in passed_tests:
37+
f.write(test + '\n')
38+
39+
40+
def remove_passed_tests(input_file, passed_tests_file):
41+
if not os.path.exists(input_file):
42+
print(f"Input file {input_file} does not exist")
43+
return
44+
if not os.path.exists(passed_tests_file):
45+
print(f"Passed tests file {passed_tests_file} does not exist")
46+
return
47+
48+
passed_tests = []
49+
# Read passed tests from file
50+
with open(passed_tests_file, 'r') as f:
51+
for line in f:
52+
passed_tests.append(line.strip())
53+
54+
tests_to_keep = []
55+
# Remove passed tests from input file
56+
with open(input_file, 'r') as f:
57+
for line in f:
58+
if line.strip() not in passed_tests:
59+
tests_to_keep.append(line.strip())
60+
61+
# Delete input file
62+
try:
63+
os.remove(input_file)
64+
except Exception as e:
65+
print(f"Failed to delete {input_file}: {e}")
66+
# Write tests to keep to input file
67+
with open(input_file, 'w') as f:
68+
for test in tests_to_keep:
69+
f.write(test + '\n')
70+
71+
72+
if __name__ == '__main__':
73+
if (sys.argv[1] == "get_passed_tests"):
74+
parser = argparse.ArgumentParser()
75+
parser.add_argument('--input-file',
76+
required=True,
77+
help='Input XML file containing test results')
78+
parser.add_argument('--output-file',
79+
required=True,
80+
help='Output file to write passed tests')
81+
args = parser.parse_args(sys.argv[2:])
82+
get_passed_tests(args.input_file, args.output_file)
83+
elif (sys.argv[1] == "remove_passed_tests"):
84+
parser = argparse.ArgumentParser()
85+
parser.add_argument('--input-file',
86+
required=True,
87+
help='Input XML file containing test results')
88+
parser.add_argument('--passed-tests-file',
89+
required=True,
90+
help='File containing passed tests')
91+
args = parser.parse_args(sys.argv[2:])
92+
remove_passed_tests(args.input_file, args.passed_tests_file)

0 commit comments

Comments
 (0)