Fix flaky QTimer::remainingTime() test

Before, we used not so accurate QTest::qWait(50)
to measure the accuracy of more precise timer's interval.
In addition, the checked range for remainingTime (50, 200)
was probably wrong, since by definition it couldn't be more than 150,
as we started the timer with interval of 200 and waited at least 50.

In this fix we have additional "tester" timer to measure remainingTime
of "tested" timer. The "tester" is a singleShot timer with interval of
50, and is started together with "tested" timer. Whenever the "tested"
timer timeouts, it restarts the "tester" timer - this is done desired
number of times (2 by default, like in the original test).

The test itself lies now inside tester's lambda. We fix the tested
range (at least 1, no more than 150). The minimum value could in
theory be greater, but it's enough to test that it's not overdue.

Finally, we wait for expected number of test runs. We give it twice
as much time as is in theory needed.

Task-number: QTBUG-83419
Task-number: QTBUG-58519
Change-Id: I43836d787d804f22bb66515ebb215d040189c4f3
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
This commit is contained in:
Jarek Kobus 2020-09-04 10:47:40 +02:00
parent a1cbca44ef
commit db3d5a3097

View File

@ -135,24 +135,50 @@ void tst_QTimer::timeout()
void tst_QTimer::remainingTime()
{
QTimer timer;
QSignalSpy timeoutSpy(&timer, &QTimer::timeout);
timer.setTimerType(Qt::PreciseTimer);
timer.start(200);
QTimer tested;
tested.setTimerType(Qt::PreciseTimer);
QCOMPARE(timeoutSpy.count(), 0);
QTest::qWait(50);
QCOMPARE(timeoutSpy.count(), 0);
QTimer tester;
tester.setTimerType(Qt::PreciseTimer);
tester.setSingleShot(true);
int remainingTime = timer.remainingTime();
QVERIFY2(remainingTime >= 50 && remainingTime <= 200, qPrintable(QString::number(remainingTime)));
const int testedInterval = 200;
const int testerInterval = 50;
const int expectedRemainingTime = testedInterval - testerInterval;
QVERIFY(timeoutSpy.wait());
QCOMPARE(timeoutSpy.count(), 1);
int testIteration = 0;
const int desiredTestCount = 2;
// the timer is still active, so it should have a non-zero remaining time
remainingTime = timer.remainingTime();
QVERIFY2(remainingTime >= 50, qPrintable(QString::number(remainingTime)));
auto connection = QObject::connect(&tested, &QTimer::timeout, [&tester]() {
// We let tested (which isn't a single-shot) run repeatedly, to verify
// it *does* repeat, and check that the single-shot tester, starting
// at the same time, does finish first each time, by about the right duration.
tester.start(); // start tester again
});
QObject::connect(&tester, &QTimer::timeout, [&]() {
// we expect that remainingTime is at most 150
const int remainingTime = tested.remainingTime();
const bool remainingTimeInRange = remainingTime > 0
&& remainingTime <= expectedRemainingTime;
if (QTest::currentTestFailed() || !remainingTimeInRange)
testIteration = desiredTestCount; // to exit the QTRY_...() on failure
else
++testIteration;
if (testIteration == desiredTestCount)
QObject::disconnect(connection); // don't start tester again
QVERIFY2(remainingTimeInRange, qPrintable("Remaining time "
+ QByteArray::number(remainingTime) + "ms outside expected range (0ms, "
+ QByteArray::number(expectedRemainingTime) + "ms]"));
});
tested.start(testedInterval);
tester.start(testerInterval); // start tester for the 1st time
// Test it desiredTestCount times, give it reasonable amount of time
// (twice as much as needed)
QTRY_COMPARE_WITH_TIMEOUT(testIteration, desiredTestCount,
testedInterval * desiredTestCount * 2);
}
void tst_QTimer::remainingTimeInitial_data()