Skip to content

Commit 466fb5b

Browse files
authored
slang-test: retry failed test at the end. (shader-slang#5255)
1 parent 80c1851 commit 466fb5b

File tree

3 files changed

+87
-29
lines changed

3 files changed

+87
-29
lines changed

tools/slang-test/slang-test-main.cpp

+51-1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ struct TestOptions
103103
bool isSynthesized = false;
104104
};
105105

106+
struct FileTestInfoImpl : public FileTestInfo
107+
{
108+
String testName;
109+
String filePath;
110+
String outputStem;
111+
TestOptions options;
112+
};
113+
106114
struct TestDetails
107115
{
108116
TestDetails() {}
@@ -4042,13 +4050,29 @@ static SlangResult _runTestsOnFile(
40424050
if (_canIgnore(context, testDetails))
40434051
{
40444052
testResult = TestResult::Ignored;
4053+
context->getTestReporter()->addResult(testResult);
40454054
}
40464055
else
40474056
{
40484057
testResult = runTest(context, filePath, outputStem, testName, testDetails.options);
4058+
if (testResult == TestResult::Fail
4059+
&& !context->getTestReporter()->m_expectedFailureList.contains(testName))
4060+
{
4061+
RefPtr<FileTestInfoImpl> fileTestInfo = new FileTestInfoImpl();
4062+
fileTestInfo->filePath = filePath;
4063+
fileTestInfo->testName = testName;
4064+
fileTestInfo->outputStem = outputStem;
4065+
fileTestInfo->options = testDetails.options;
4066+
4067+
std::lock_guard lock(context->mutexFailedFileTests);
4068+
context->failedFileTests.add(fileTestInfo);
4069+
}
4070+
else
4071+
{
4072+
context->getTestReporter()->addResult(testResult);
4073+
}
40494074
}
40504075

4051-
context->getTestReporter()->addResult(testResult);
40524076

40534077
// Could determine if to continue or not here... based on result
40544078
}
@@ -4615,6 +4639,32 @@ SlangResult innerMain(int argc, char** argv)
46154639
TestReporter::set(nullptr);
46164640
}
46174641

4642+
// If we have a couple failed tests, they maybe intermittent failures due to parallel
4643+
// excution or driver instability. We can try running them again.
4644+
static constexpr int kFailedTestLimitForRetry = 16;
4645+
if (context.failedFileTests.getCount() <= kFailedTestLimitForRetry)
4646+
{
4647+
printf("Retrying %d failed tests...\n", (int)context.failedFileTests.getCount());
4648+
for (auto& test : context.failedFileTests)
4649+
{
4650+
FileTestInfoImpl* fileTestInfo = static_cast<FileTestInfoImpl*>(test.Ptr());
4651+
TestReporter::SuiteScope suiteScope(&reporter, "tests");
4652+
TestReporter::TestScope scope(&reporter, fileTestInfo->testName);
4653+
auto newResult = runTest(&context, fileTestInfo->filePath, fileTestInfo->outputStem, fileTestInfo->testName, fileTestInfo->options);
4654+
reporter.addResult(newResult);
4655+
}
4656+
}
4657+
else
4658+
{
4659+
// If there are too many failed tests, don't bother retrying.
4660+
for (auto& test : context.failedFileTests)
4661+
{
4662+
FileTestInfoImpl* fileTestInfo = static_cast<FileTestInfoImpl*>(test.Ptr());
4663+
TestReporter::TestScope scope(&reporter, fileTestInfo->testName);
4664+
reporter.addResult(TestResult::Fail);
4665+
}
4666+
}
4667+
46184668
reporter.outputSummary();
46194669
return reporter.didAllSucceed() ? SLANG_OK : SLANG_FAIL;
46204670
}

tools/slang-test/test-context.h

+35-27
Original file line numberDiff line numberDiff line change
@@ -85,62 +85,66 @@ struct TestRequirements
8585
Slang::RenderApiFlags usedRenderApiFlags = 0; ///< Used render api flags (some might be implied)
8686
};
8787

88+
struct FileTestInfo : public Slang::RefObject
89+
{
90+
};
91+
8892
class TestContext
8993
{
90-
public:
94+
public:
9195

9296
typedef Slang::TestToolUtil::InnerMainFunc InnerMainFunc;
9397

94-
/// Get the slang session
95-
SlangSession* getSession() const { return m_session; }
98+
/// Get the slang session
99+
SlangSession* getSession() const { return m_session; }
96100

97101
SlangResult init(const char* exePath);
98102

99-
/// Get the inner main function (from shared library)
103+
/// Get the inner main function (from shared library)
100104
InnerMainFunc getInnerMainFunc(const Slang::String& dirPath, const Slang::String& name);
101-
/// Set the function for the shared library
105+
/// Set the function for the shared library
102106
void setInnerMainFunc(const Slang::String& name, InnerMainFunc func);
103107

104108
void setTestRequirements(TestRequirements* req);
105109

106110
TestRequirements* getTestRequirements() const;
107111

108-
/// If true tests aren't being run just the information on testing is being accumulated
112+
/// If true tests aren't being run just the information on testing is being accumulated
109113
bool isCollectingRequirements() const { return getTestRequirements() != nullptr; }
110-
/// If set, then tests are executed
114+
/// If set, then tests are executed
111115
bool isExecuting() const { return getTestRequirements() == nullptr; }
112116

113-
/// True if a render API filter is enabled
117+
/// True if a render API filter is enabled
114118
bool isRenderApiFilterEnabled() const { return options.enabledApis != Slang::RenderApiFlag::AllOf && options.enabledApis != 0; }
115119

116-
/// True if a test with the requiredFlags can in principal run (it may not be possible if the API is not available though)
120+
/// True if a test with the requiredFlags can in principal run (it may not be possible if the API is not available though)
117121
bool canRunTestWithRenderApiFlags(Slang::RenderApiFlags requiredFlags);
118122

119-
/// True if can run unit tests
123+
/// True if can run unit tests
120124
bool canRunUnitTests() const { return options.apiOnly == false; }
121125

122-
/// Given a spawn type, return the final spawn type.
123-
/// In particular we want 'Default' spawn type to vary by the environment (for example running on test server on CI)
126+
/// Given a spawn type, return the final spawn type.
127+
/// In particular we want 'Default' spawn type to vary by the environment (for example running on test server on CI)
124128
SpawnType getFinalSpawnType(SpawnType spawnType);
125129

126130
SpawnType getFinalSpawnType();
127131

128-
/// Get compiler set
132+
/// Get compiler set
129133
Slang::DownstreamCompilerSet* getCompilerSet();
130134
Slang::IDownstreamCompiler* getDefaultCompiler(SlangSourceLanguage sourceLanguage);
131135

132136
Slang::JSONRPCConnection* getOrCreateJSONRPCConnection();
133137
void destroyRPCConnection();
134138

135-
/// Ctor
139+
/// Ctor
136140
TestContext();
137-
/// Dtor
141+
/// Dtor
138142
~TestContext();
139143

140144
Options options;
141145
TestCategorySet categorySet;
142146

143-
/// If set then tests are not run, but their requirements are set
147+
/// If set then tests are not run, but their requirements are set
144148

145149
PassThroughFlags availableBackendFlags = 0;
146150
Slang::RenderApiFlags availableRenderApiFlags = 0;
@@ -152,17 +156,17 @@ class TestContext
152156
Slang::String dllDirectoryPath;
153157
Slang::String exePath;
154158

155-
/// Timeout time for communication over connection.
156-
/// NOTE! If the timeout is hit, the connection will be destroyed, and then recreated.
157-
/// For tests that compile the stdlib, if that takes this time, the stdlib will be
158-
/// repeatedly compiled and each time fail.
159-
/// NOTE! This timeout may be altered in the ctor for a specific target, the initializatoin
160-
/// value is just the default.
161-
///
162-
/// TODO(JS): We could split the stdlib compilation from other actions, and have timeout specific for
163-
/// that. To do this we could have a 'compileStdLib' RPC method.
164-
///
165-
/// Current default is 60 seconds.
159+
/// Timeout time for communication over connection.
160+
/// NOTE! If the timeout is hit, the connection will be destroyed, and then recreated.
161+
/// For tests that compile the stdlib, if that takes this time, the stdlib will be
162+
/// repeatedly compiled and each time fail.
163+
/// NOTE! This timeout may be altered in the ctor for a specific target, the initializatoin
164+
/// value is just the default.
165+
///
166+
/// TODO(JS): We could split the stdlib compilation from other actions, and have timeout specific for
167+
/// that. To do this we could have a 'compileStdLib' RPC method.
168+
///
169+
/// Current default is 60 seconds.
166170
Slang::Int connectionTimeOutInMs = 60 * 1000;
167171

168172
void setThreadIndex(int index);
@@ -175,6 +179,10 @@ class TestContext
175179
std::mutex mutex;
176180
Slang::RefPtr<Slang::JSONRPCConnection> m_languageServerConnection;
177181

182+
183+
std::mutex mutexFailedFileTests;
184+
Slang::List<Slang::RefPtr<FileTestInfo>> failedFileTests;
185+
178186
Slang::IFileCheck* getFileCheck() { return m_fileCheck; };
179187

180188
protected:

tools/slang-test/test-reporter.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ enum class TestOutputMode
2323

2424
class TestReporter : public ITestReporter
2525
{
26-
public:
26+
public:
2727

2828
struct TestInfo
2929
{

0 commit comments

Comments
 (0)