QUrl: port thread-safety autotest from Qt4.

This detected the same missing detach()s in QUrl::resolve.
Everything else works, no need for a mutex in Qt5's QUrl.

Change-Id: I0da51b7b0c6b810d314a26d4b638383cd17de12b
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
David Faure 2012-07-14 00:53:38 +02:00 committed by Qt by Nokia
parent 2b69159fd8
commit ac2b452616
3 changed files with 94 additions and 1 deletions

View File

@ -2743,9 +2743,11 @@ QUrl QUrl::resolved(const QUrl &relative) const
// be non strict and allow scheme in relative url
if (!relative.d->scheme.isEmpty() && relative.d->scheme != d->scheme) {
t = relative;
t.detach();
} else {
if (relative.d->hasAuthority()) {
t = relative;
t.detach();
} else {
t.d = new QUrlPrivate;

View File

@ -1,5 +1,5 @@
CONFIG += testcase parallel_test
TARGET = tst_qurl
QT = core testlib
QT = core testlib concurrent
SOURCES = tst_qurl.cpp
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0

View File

@ -167,6 +167,11 @@ private slots:
void setComponents();
void streaming_data();
void streaming();
void detach();
void testThreading();
private:
void testThreadingHelper();
};
// Testing get/set functions
@ -217,6 +222,8 @@ void tst_QUrl::constructing()
QVERIFY(url.isEmpty());
QCOMPARE(url.port(), -1);
QCOMPARE(url.toString(), QString());
QVERIFY(url == url);
QVERIFY(!(url < url));
QUrl justHost("qt.nokia.com");
QVERIFY(!justHost.isEmpty());
@ -280,6 +287,8 @@ void tst_QUrl::comparison()
QVERIFY(url2.isValid());
QVERIFY(url1 == url2);
QVERIFY(!(url1 < url2));
QVERIFY(!(url2 < url1));
// 6.2.2 Syntax-based Normalization
QUrl url3 = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D");
@ -294,6 +303,13 @@ void tst_QUrl::comparison()
QUrl url6;
url6.setEncodedQuery("a=%2A");
QVERIFY(url5 == url6);
QUrl url7;
url7.setEncodedQuery("a=C");
QUrl url8;
url8.setEncodedQuery("a=c");
QVERIFY(url7 != url8);
QVERIFY(url7 < url8);
}
void tst_QUrl::comparison2_data()
@ -3234,5 +3250,80 @@ void tst_QUrl::streaming()
QVERIFY(!restored.isValid());
}
void tst_QUrl::detach()
{
QUrl empty;
empty.detach();
QUrl foo("http://www.kde.org");
QUrl foo2 = foo;
foo2.detach(); // not that it's needed, given that setHost detaches, of course. But this increases coverage :)
foo2.setHost("www.gnome.org");
QCOMPARE(foo2.host(), QString("www.gnome.org"));
QCOMPARE(foo.host(), QString("www.kde.org"));
}
// Test accessing the same QUrl from multiple threads concurrently
// To maximize the chances of a race (and of a report from helgrind), we actually use
// 10 urls rather than one.
class UrlStorage
{
public:
UrlStorage() {
m_urls.resize(10);
for (int i = 0 ; i < m_urls.size(); ++i)
m_urls[i] = QUrl::fromEncoded("http://www.kde.org", QUrl::StrictMode);
}
QVector<QUrl> m_urls;
};
static const UrlStorage * s_urlStorage = 0;
void tst_QUrl::testThreadingHelper()
{
const UrlStorage* storage = s_urlStorage;
for (int i = 0 ; i < storage->m_urls.size(); ++i ) {
const QUrl& u = storage->m_urls.at(i);
// QVERIFY/QCOMPARE trigger race conditions in helgrind
if (!u.isValid())
qFatal("invalid url");
if (u.scheme() != QLatin1String("http"))
qFatal("invalid scheme");
if (!u.toString().startsWith('h'))
qFatal("invalid toString");
QUrl copy(u);
copy.setHost("www.new-host.com");
QUrl copy2(u);
copy2.setUserName("dfaure");
QUrl copy3(u);
copy3.setUrl("http://www.new-host.com");
QUrl copy4(u);
copy4.detach();
QUrl copy5(u);
QUrl resolved1 = u.resolved(QUrl("index.html"));
Q_UNUSED(resolved1);
QUrl resolved2 = QUrl("http://www.kde.org").resolved(u);
Q_UNUSED(resolved2);
QString local = u.toLocalFile();
Q_UNUSED(local);
QTest::qWait(10); // give time for the other threads to start
}
}
#include <QThreadPool>
#include <QtConcurrent>
void tst_QUrl::testThreading()
{
s_urlStorage = new UrlStorage;
QThreadPool::globalInstance()->setMaxThreadCount(100);
QFutureSynchronizer<void> sync;
for (int i = 0; i < 100; ++i)
sync.addFuture(QtConcurrent::run(this, &tst_QUrl::testThreadingHelper));
sync.waitForFinished();
delete s_urlStorage;
}
QTEST_MAIN(tst_QUrl)
#include "tst_qurl.moc"