AutoTest: Cancel possible running tasks on shutdown

If tasks are running while shutting down we might end up in a crash,
so cancel all tasks and handle possible invalid accesses of the
current running processing.

Change-Id: I69f7cac5f44390e322fa301af6d6794270c95c2a
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Christian Stenger
2016-07-08 12:53:57 +02:00
parent e70adf820e
commit 48b2af5e77
6 changed files with 32 additions and 4 deletions

View File

@@ -154,6 +154,7 @@ void AutotestPlugin::extensionsInitialized()
ExtensionSystem::IPlugin::ShutdownFlag AutotestPlugin::aboutToShutdown() ExtensionSystem::IPlugin::ShutdownFlag AutotestPlugin::aboutToShutdown()
{ {
TestTreeModel::instance()->parser()->aboutToShutdown();
return SynchronousShutdown; return SynchronousShutdown;
} }

View File

@@ -90,6 +90,8 @@ static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
const QList<CppTools::ProjectPart::Ptr> &ppList = modelManager->projectPart(filePath); const QList<CppTools::ProjectPart::Ptr> &ppList = modelManager->projectPart(filePath);
if (ppList.size()) if (ppList.size())
proFile = ppList.first()->projectFile; proFile = ppList.first()->projectFile;
else
return false; // happens if shutting down while parsing
foreach (const GTestCaseSpec &testSpec, result.keys()) { foreach (const GTestCaseSpec &testSpec, result.keys()) {
GTestParseResult *parseResult = new GTestParseResult(id); GTestParseResult *parseResult = new GTestParseResult(id);

View File

@@ -199,7 +199,10 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
parseResult->displayName = testCaseName; parseResult->displayName = testCaseName;
parseResult->line = line; parseResult->line = line;
parseResult->column = column; parseResult->column = column;
parseResult->proFile = modelManager->projectPart(fileName).first()->projectFile; QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(fileName);
if (projectParts.isEmpty()) // happens if shutting down while parsing
return false;
parseResult->proFile = projectParts.first()->projectFile;
QMap<QString, TestCodeLocationAndType>::ConstIterator it = testFunctions.begin(); QMap<QString, TestCodeLocationAndType>::ConstIterator it = testFunctions.begin();
const QMap<QString, TestCodeLocationAndType>::ConstIterator end = testFunctions.end(); const QMap<QString, TestCodeLocationAndType>::ConstIterator end = testFunctions.end();
for ( ; it != end; ++it) { for ( ; it != end; ++it) {

View File

@@ -202,7 +202,8 @@ static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterfa
const QString cppFileName = document->fileName(); const QString cppFileName = document->fileName();
QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(cppFileName); QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(cppFileName);
QTC_ASSERT(!ppList.isEmpty(), return false); if (ppList.isEmpty()) // happens if shutting down while parsing
return false;
const QString &proFile = ppList.at(0)->projectFile; const QString &proFile = ppList.at(0)->projectFile;
const QString srcDir = quickTestSrcDir(modelManager, cppFileName); const QString srcDir = quickTestSrcDir(modelManager, cppFileName);

View File

@@ -85,6 +85,8 @@ TestCodeParser::~TestCodeParser()
void TestCodeParser::setState(State state) void TestCodeParser::setState(State state)
{ {
if (m_parserState == Shutdown)
return;
qCDebug(LOG) << "setState(" << state << "), currentState:" << m_parserState; qCDebug(LOG) << "setState(" << state << "), currentState:" << m_parserState;
// avoid triggering parse before code model parsing has finished, but mark as dirty // avoid triggering parse before code model parsing has finished, but mark as dirty
if (m_codeModelParsing) { if (m_codeModelParsing) {
@@ -175,6 +177,8 @@ static bool checkDocumentForTestCode(QFutureInterface<TestParseResultPtr> &futur
const QVector<ITestParser *> &parsers) const QVector<ITestParser *> &parsers)
{ {
foreach (ITestParser *currentParser, parsers) { foreach (ITestParser *currentParser, parsers) {
if (futureInterface.isCanceled())
return false;
if (currentParser->processDocument(futureInterface, fileName)) if (currentParser->processDocument(futureInterface, fileName))
return true; return true;
} }
@@ -253,6 +257,17 @@ void TestCodeParser::onProjectPartsUpdated(ProjectExplorer::Project *project)
emitUpdateTestTree(); emitUpdateTestTree();
} }
void TestCodeParser::aboutToShutdown()
{
qCDebug(LOG) << "Disabling (immediately) - shutting down";
State oldState = m_parserState;
m_parserState = Shutdown;
if (oldState == PartialParse || oldState == FullParse) {
m_futureWatcher.cancel();
m_futureWatcher.waitForFinished();
}
}
bool TestCodeParser::postponed(const QStringList &fileList) bool TestCodeParser::postponed(const QStringList &fileList)
{ {
switch (m_parserState) { switch (m_parserState) {
@@ -278,6 +293,7 @@ bool TestCodeParser::postponed(const QStringList &fileList)
} }
return true; return true;
case Disabled: case Disabled:
case Shutdown:
break; break;
} }
QTC_ASSERT(false, return false); // should not happen at all QTC_ASSERT(false, return false); // should not happen at all
@@ -285,7 +301,7 @@ bool TestCodeParser::postponed(const QStringList &fileList)
void TestCodeParser::scanForTests(const QStringList &fileList) void TestCodeParser::scanForTests(const QStringList &fileList)
{ {
if (m_parserState == Disabled) { if (m_parserState == Disabled || m_parserState == Shutdown) {
m_dirty = true; m_dirty = true;
if (fileList.isEmpty()) { if (fileList.isEmpty()) {
m_fullUpdatePostponed = true; m_fullUpdatePostponed = true;
@@ -390,6 +406,9 @@ void TestCodeParser::onFinished()
qCDebug(LOG) << "emitting parsingFinished (onFinished, Disabled)"; qCDebug(LOG) << "emitting parsingFinished (onFinished, Disabled)";
emit parsingFinished(); emit parsingFinished();
break; break;
case Shutdown:
qCDebug(LOG) << "Shutdown complete - not emitting parsingFinished (onFinished)";
break;
default: default:
qWarning("I should not be here... State: %d", m_parserState); qWarning("I should not be here... State: %d", m_parserState);
break; break;

View File

@@ -48,7 +48,8 @@ public:
Idle, Idle,
PartialParse, PartialParse,
FullParse, FullParse,
Disabled Disabled,
Shutdown
}; };
explicit TestCodeParser(TestTreeModel *parent = 0); explicit TestCodeParser(TestTreeModel *parent = 0);
@@ -77,6 +78,7 @@ public:
void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document); void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document);
void onStartupProjectChanged(ProjectExplorer::Project *project); void onStartupProjectChanged(ProjectExplorer::Project *project);
void onProjectPartsUpdated(ProjectExplorer::Project *project); void onProjectPartsUpdated(ProjectExplorer::Project *project);
void aboutToShutdown();
private: private:
bool postponed(const QStringList &fileList); bool postponed(const QStringList &fileList);