From f48f02cd014a6cdb952ec6138413aa1ba2f796f4 Mon Sep 17 00:00:00 2001 From: Raine Makelainen Date: Thu, 23 Oct 2014 18:54:11 +0300 Subject: [PATCH] [sailfish-browser] Add unit test cases for suffling tabs Aim is to automate a test where a WebPage stops responding. Added cases do not reproduce that error yet. --- src/webpages.cpp | 28 +++++ src/webpages.h | 4 + tests/auto/common/testobject.cpp | 2 +- tests/auto/tests.xml | 2 +- tests/auto/tst_webview/tst_webview.cpp | 166 ++++++++++++++++++++++++- tests/auto/tst_webview/tst_webview.qml | 7 ++ 6 files changed, 206 insertions(+), 3 deletions(-) diff --git a/src/webpages.cpp b/src/webpages.cpp index a343a96617b4..cd40b348bb13 100644 --- a/src/webpages.cpp +++ b/src/webpages.cpp @@ -240,6 +240,34 @@ void WebPages::dumpPages() const qDebug() << "---- end ------"; } +QList WebPages::liveTabs() +{ + QList pages = m_activePages.values(); + QList tabIds; + int count = pages.count(); + for (int i = 0; i < count; ++i) { + WebPageEntry *pageEntry = pages.at(i); + if (pageEntry->webPage) { + tabIds << pageEntry->webPage->tabId(); + } + } + return tabIds; +} + +QList WebPages::zombifiedTabs() +{ + QMapIterator pages(m_activePages); + QList tabIds; + + while (pages.hasNext()) { + pages.next(); + if (!pages.value()->webPage) { + tabIds << pages.key(); + } + } + return tabIds; +} + WebPages::WebPageEntry::WebPageEntry(DeclarativeWebPage *webPage, QRectF *cssContentRect) : webPage(webPage) , cssContentRect(cssContentRect) diff --git a/src/webpages.h b/src/webpages.h index 00f6d756571e..db105169f417 100644 --- a/src/webpages.h +++ b/src/webpages.h @@ -48,6 +48,10 @@ class WebPages : public QObject int parentTabId(int tabId) const; void dumpPages() const; + // Testability helpers + QList liveTabs(); + QList zombifiedTabs(); + private: struct WebPageEntry { WebPageEntry(DeclarativeWebPage *webPage, QRectF *cssContentRect); diff --git a/tests/auto/common/testobject.cpp b/tests/auto/common/testobject.cpp index f97c73599fbf..e48b5a79d218 100644 --- a/tests/auto/common/testobject.cpp +++ b/tests/auto/common/testobject.cpp @@ -48,7 +48,7 @@ void TestObject::init(const QUrl &url) void TestObject::waitSignals(QSignalSpy &spy, int expectedSignalCount) const { int i = 0; - int maxWaits = 10; + int maxWaits = qMax(10, expectedSignalCount); while (spy.count() < expectedSignalCount && i < maxWaits) { spy.wait(); ++i; diff --git a/tests/auto/tests.xml b/tests/auto/tests.xml index bf819b5fddd2..e07fea0c815c 100644 --- a/tests/auto/tests.xml +++ b/tests/auto/tests.xml @@ -23,7 +23,7 @@ cd /opt/tests/sailfish-browser/auto/ && ./tst_dbmanager -platform wayland-egl -iterations 10 - cd /opt/tests/sailfish-browser/auto/ && ./tst_webview -platform wayland-egl + cd /opt/tests/sailfish-browser/auto/ && BROWSER_OFFLINE=1 ./tst_webview cd /opt/tests/sailfish-browser/auto/ && ./tst_desktopbookmarkwriter diff --git a/tests/auto/tst_webview/tst_webview.cpp b/tests/auto/tst_webview/tst_webview.cpp index 9942580edcef..d9daa94b2136 100644 --- a/tests/auto/tst_webview/tst_webview.cpp +++ b/tests/auto/tst_webview/tst_webview.cpp @@ -27,7 +27,6 @@ class tst_webview : public TestObject public: tst_webview(); - private slots: void initTestCase(); void testNewTab_data(); @@ -42,9 +41,14 @@ private slots: void clear(); void restart(); void changeTabAndLoad(); + void insertOnlinePages_data(); + void insertOnlinePages(); + void suffleTabsWaitLoaded(); + void suffleTabsSwitchImmediately(); void cleanupTestCase(); private: + void activeTabAndLoad(int i); QString formatUrl(QString fileName) const; void verifyHistory(QList &historyOrder); @@ -52,6 +56,7 @@ private slots: DeclarativeTabModel *tabModel; DeclarativeWebContainer *webContainer; QString baseUrl; + bool offline; }; tst_webview::tst_webview() @@ -59,6 +64,7 @@ tst_webview::tst_webview() , historyModel(0) , tabModel(0) , webContainer(0) + , offline(getenv("BROWSER_OFFLINE")) { } @@ -674,6 +680,130 @@ void tst_webview::changeTabAndLoad() QCOMPARE(webContainer->m_webPages->m_activePages.count(), 2); } +void tst_webview::insertOnlinePages_data() +{ + QSignalSpy tabsCleared(tabModel, SIGNAL(tabsCleared())); + tabModel->clear(); + QTest::qWait(1000); + waitSignals(tabsCleared, 1); + QVERIFY(tabModel->count() == 0); + + webContainer->setProperty("maxLiveTabCount", 3); + QTest::addColumn("newUrl"); + QTest::addColumn("liveTabCount"); + + QTest::newRow("google.com") << "http://www.google.com" << 1; + QTest::newRow("m.engadget.com") << "http://m.engadget.com" << 2; + QTest::newRow("yahoo.com") << "http://www.yahoo.com" << 3; + QTest::newRow("facebook.com") << "http://m.facebook.com" << 3; +} + +void tst_webview::insertOnlinePages() +{ + if (offline) { + QEXPECT_FAIL("", "This cannot be executed without network", Abort); + QCOMPARE(false, true); + } + + QFETCH(QString, newUrl); + QFETCH(int, liveTabCount); + + QSignalSpy urlChangedSpy(webContainer, SIGNAL(urlChanged())); + QSignalSpy tabCountSpy(tabModel, SIGNAL(countChanged())); + QSignalSpy activeTabChangedSpy(tabModel, SIGNAL(activeTabChanged(int,int))); + QSignalSpy tabAddedSpy(tabModel, SIGNAL(tabAdded(int))); + QSignalSpy contentItemSpy(webContainer, SIGNAL(contentItemChanged())); + QSignalSpy loadingChanged(webContainer, SIGNAL(loadingChanged())); + + tabModel->newTab(newUrl, ""); + + // Wait for MozView instance change. + waitSignals(contentItemSpy, 1); + QCOMPARE(contentItemSpy.count(), 1); + + // Load started and ended + waitSignals(loadingChanged, 2); + + // ~last in the sequence of adding a new tab. + waitSignals(tabAddedSpy, 1); + + // Ignore possible redirection by checking that at least one url and one title change were emitted. + QVERIFY(urlChangedSpy.count() > 0); + QCOMPARE(tabCountSpy.count(), 1); + + QCOMPARE(webContainer->m_webPages->liveTabs().count(), liveTabCount); + QCOMPARE(activeTabChangedSpy.count(), 1); +} + +void tst_webview::suffleTabsWaitLoaded() +{ + if (offline) { + QEXPECT_FAIL("", "This cannot be executed without network", Abort); + QCOMPARE(false, true); + } + + // Loops through 4 tabs so that in every 2nd round we pick inactive tab and after which we + // pick zombified tab. + for (int i = 0; i < 4; ++i) { + QSignalSpy loadingChanged(webContainer, SIGNAL(loadingChanged())); + QSignalSpy activeTabChangedSpy(tabModel, SIGNAL(activeTabChanged(int,int,bool))); + + activeTabAndLoad(i); + + QCOMPARE(activeTabChangedSpy.count(), 1); + waitSignals(loadingChanged, 2); + QVERIFY(webContainer->webPage()); + QVERIFY(!webContainer->webPage()->loading()); + QVERIFY(webContainer->webPage()->property("loaded").toBool()); + } +} + +void tst_webview::suffleTabsSwitchImmediately() +{ + if (offline) { + QEXPECT_FAIL("", "This cannot be executed without network", Abort); + QCOMPARE(false, true); + } + + // Loops through 4 tabs so that in every 2nd round we pick inactive tab and after which we + // pick zombified tab. + for (int i = 0; i < 4; ++i) { + QSignalSpy activeTabChangedSpy(tabModel, SIGNAL(activeTabChanged(int,int,bool))); + QSignalSpy loadProgressSpy(webContainer, SIGNAL(loadProgressChanged())); + + activeTabAndLoad(i); + QCOMPARE(activeTabChangedSpy.count(), 1); + QVERIFY(webContainer->webPage()); + + // Let loading to proceed to 90% + int i = 0; + while (i < 90 && webContainer->loadProgress() < 90) { + loadProgressSpy.wait(); + ++i; + } + + QVERIFY(webContainer->loadProgress() >= 90); + } + + // Go through all zombie tabs so that each of them get fully loaded. + for (int i = 0; i < 4; ++i) { + QSignalSpy activeTabChangedSpy(tabModel, SIGNAL(activeTabChanged(int,int,bool))); + + QList zombifiedTabs = webContainer->m_webPages->zombifiedTabs(); + QCOMPARE(zombifiedTabs.count(), 1); + int tabId = zombifiedTabs.at(0); + tabModel->activateTabById(tabId); + QSignalSpy loadingChanged(webContainer, SIGNAL(loadingChanged())); + QCOMPARE(activeTabChangedSpy.count(), 1); + + // 60secs of timeout per loading change. + waitSignals(loadingChanged, 2, 60000); + QVERIFY(webContainer->webPage()); + QVERIFY(!webContainer->webPage()->loading()); + QVERIFY(webContainer->webPage()->property("loaded").toBool()); + } +} + void tst_webview::cleanupTestCase() { QTest::qWait(1000); @@ -715,6 +845,40 @@ void tst_webview::verifyHistory(QList &historyOrder) } } +// Used with suffleTabsWaitLoaded and suffleTabsSwitchImmediately (4 tabs) +void tst_webview::activeTabAndLoad(int i) +{ + int tabId = -1; + bool reload = false; + if (i % 2 == 0) { + // Inactive and not current tab + QList liveTabs = webContainer->m_webPages->liveTabs(); + QCOMPARE(liveTabs.count(), 3); + tabId = liveTabs.at(random(0, 2)); + + while (tabId == webContainer->tabId()) { + tabId = liveTabs.at(random(0, 2)); + } + reload = true; + } else { + // First and last zombified tab. + QList zombifiedTabs = webContainer->m_webPages->zombifiedTabs(); + QCOMPARE(zombifiedTabs.count(), 1); + tabId = zombifiedTabs.at(0); + } + + tabModel->activateTabById(tabId); + + QVERIFY(webContainer->webPage()); + QSignalSpy loadingSpy(webContainer->webPage(), SIGNAL(loadingChanged())); + + // Reload inactive tab. + if (reload) { + webContainer->webPage()->reload(); + } + waitSignals(loadingSpy, 1); +} + int main(int argc, char *argv[]) { setenv("USE_ASYNC", "1", 1); diff --git a/tests/auto/tst_webview/tst_webview.qml b/tests/auto/tst_webview/tst_webview.qml index 6032f9ddcc77..02c9be5ec228 100644 --- a/tests/auto/tst_webview/tst_webview.qml +++ b/tests/auto/tst_webview/tst_webview.qml @@ -31,6 +31,13 @@ ApplicationWindow { active: true toolbarHeight: 50 portrait: true + width: parent.width + height: parent.height + + onLoadProgressChanged: console.log("progress:", loadProgress, url, tabId) + onLoadingChanged: console.log(loading, url, tabId) + onUrlChanged: console.log(url, tabId) + onContentItemChanged: console.log(contentItem, "url:", (contentItem ? contentItem.url : "no url" ), "tabId:", (contentItem ? contentItem.tabId : -1 )) HistoryModel { id: historyModel