From ac2b452616796c9dd9c0f0bb63dccbefeb8bacbc Mon Sep 17 00:00:00 2001 From: David Faure Date: Sat, 14 Jul 2012 00:53:38 +0200 Subject: 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 --- tests/auto/corelib/io/qurl/qurl.pro | 2 +- tests/auto/corelib/io/qurl/tst_qurl.cpp | 91 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/auto/corelib/io/qurl/qurl.pro b/tests/auto/corelib/io/qurl/qurl.pro index 97e607c552..a5e7130505 100644 --- a/tests/auto/corelib/io/qurl/qurl.pro +++ b/tests/auto/corelib/io/qurl/qurl.pro @@ -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 diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 12e6e4a01d..2612fc8ce6 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -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 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 +#include + +void tst_QUrl::testThreading() +{ + s_urlStorage = new UrlStorage; + QThreadPool::globalInstance()->setMaxThreadCount(100); + QFutureSynchronizer 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" -- cgit v1.2.3