on xenial help sign in
Wait for libqofono to finish initializing before we decide whether to skip the wizard's SIM page or not.

libqofono became asynchronous on its last upload (about a month ago), which the wizard was not prepared for. We didn't notice because our mocks continued their synchronous behavior, and in manual testing, it's easy to miss (you'd have to not have a SIM in, and then notice that you *didn't* get a screen). I've updated our mock to be asynchronous (to get the desired signal timing behavior, I switched one of our mock classes to C++ from qml). And I've added support for artificially extending the delays in the async flow. This lets us test those delays specifically. And obviously, I added a couple tests to do so. Fixes: #1423565 Approved by: Albert Astals Cid

commit90d88fe50274891d97a4b89139625721bcf55dfc authorMichael Terry <michael.terry@canonical.com> dateTue 24 Feb 2015, 10:16 (12 years ago) parent51a7e7ff5acba4
11 files changed+237−41
qml/Wizard/Pages/20-sim.qml+5−1 tests/mocks/MeeGo/QOfono/CMakeLists.txt+1 tests/mocks/MeeGo/QOfono/MockOfonoManager.qml−23 tests/mocks/MeeGo/QOfono/MockOfonoSimManager.qml+12−2 tests/mocks/MeeGo/QOfono/MockQOfono.cpp+41−5 tests/mocks/MeeGo/QOfono/MockQOfono.h+12−3 tests/mocks/MeeGo/QOfono/MockQOfonoManager.cpp+66 tests/mocks/MeeGo/QOfono/MockQOfonoManager.h+49 tests/mocks/MeeGo/QOfono/plugin.cpp+3−1 tests/mocks/MeeGo/QOfono/qmldir−1 tests/qmltests/Wizard/tst_Wizard.qml+48−5
qml/Wizard/Pages/20-sim.qml+5−1
@@ -25,11 +25,15 @@ LocalComponents.Page {
2525 title: i18n.tr("Add a SIM card and restart your device")
2626 forwardButtonSourceComponent: forwardButton
2727
28− // No need for skipValid, since OfonoManager does everything synchronously
28+ skipValid: !manager.available ||
29+ (manager.ready && (manager.modems.length < 1 || simManager0.ready)
30+ && (manager.modems.length < 2 || simManager1.ready))
2931 skip: !manager.available || manager.modems.length === 0 || simManager0.present || simManager1.present
3032
3133 OfonoManager {
3234 id: manager
35+ property bool ready: false
36+ onModemsChanged: ready = true
3337 }
3438
3539 // Ideally we would query the system more cleverly than hardcoding two
tests/mocks/MeeGo/QOfono/CMakeLists.txt+1
@@ -1,6 +1,7 @@
11set(MOCK_QOFONO_SOURCES
22 plugin.cpp
33 MockQOfono.cpp
4+ MockQOfonoManager.cpp
45)
56
67add_library(MockQOfono MODULE ${MOCK_QOFONO_SOURCES})
tests/mocks/MeeGo/QOfono/MockOfonoManager.qmldeleted−23
@@ -1,23 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.3
18−import MeeGo.QOfono 0.2
19−
20−Item {
21− readonly property var modems: MockQOfono.modems
22− readonly property bool available: MockQOfono.available
23−}
tests/mocks/MeeGo/QOfono/MockOfonoSimManager.qml+12−2
@@ -22,21 +22,31 @@ Item {
2222
2323 property string modemPath
2424 readonly property alias present: d.present
25+ readonly property alias ready: d.ready
2526
2627 QtObject {
2728 id: d
2829
2930 property bool present: false
31+ property bool ready: false
3032
3133 function updatePresence() {
3234 d.present = MockQOfono.isModemPresent(simManager.modemPath)
35+ d.ready = MockQOfono.isModemReady(simManager.modemPath);
3336 }
3437 }
3538
36− onModemPathChanged: d.updatePresence()
39+ // Simulate QOfono's asynchronous initialization
40+ Timer {
41+ id: asyncTimer
42+ interval: 1
43+ onTriggered: d.updatePresence()
44+ }
45+
46+ onModemPathChanged: asyncTimer.start()
3747
3848 Connections {
3949 target: MockQOfono
40− onModemsChanged: d.updatePresence()
50+ onModemsChanged: asyncTimer.start()
4151 }
4252}
tests/mocks/MeeGo/QOfono/MockQOfono.cpp+41−5
@@ -16,13 +16,31 @@
1616
1717#include "MockQOfono.h"
1818
19−MockQOfono::MockQOfono(QObject *parent)
20− : QObject(parent),
19+static MockQOfono *m_instance = nullptr;
20+
21+MockQOfono *MockQOfono::instance()
22+{
23+ if (!m_instance) {
24+ m_instance = new MockQOfono();
25+ }
26+ return m_instance;
27+}
28+
29+MockQOfono::MockQOfono()
30+ : QObject(),
2131 m_available(false),
32+ m_ready(false),
2233 m_modems()
2334{
2435}
2536
37+MockQOfono::~MockQOfono()
38+{
39+ if (m_instance == this) {
40+ m_instance = nullptr;
41+ }
42+}
43+
2644bool MockQOfono::available() const
2745{
2846 return m_available;
@@ -34,21 +52,39 @@ void MockQOfono::setAvailable(bool available)
3452 Q_EMIT availableChanged();
3553}
3654
55+bool MockQOfono::ready() const
56+{
57+ return m_ready;
58+}
59+
60+void MockQOfono::setReady(bool ready)
61+{
62+ m_ready = ready;
63+ Q_EMIT readyChanged();
64+}
65+
3766QStringList MockQOfono::modems() const
3867{
3968 return m_modems.keys();
4069}
4170
42−void MockQOfono::setModems(const QStringList &modems, const QList<bool> &present)
71+void MockQOfono::setModems(const QStringList &modems, const QList<bool> &present, const QList<bool> &ready)
4372{
4473 m_modems.clear();
4574 for (int i = 0; i < modems.length(); i++) {
46− m_modems[modems[i]] = present[i];
75+ QList<bool> props;
76+ props << present.value(i, true) << ready.value(i, true);
77+ m_modems[modems[i]] = props;
4778 }
4879 Q_EMIT modemsChanged();
4980}
5081
5182bool MockQOfono::isModemPresent(const QString &modem)
5283{
53− return m_modems.value(modem, false);
84+ return m_modems.value(modem).value(0, false);
85+}
86+
87+bool MockQOfono::isModemReady(const QString &modem)
88+{
89+ return m_modems.value(modem).value(1, false);
5490}
tests/mocks/MeeGo/QOfono/MockQOfono.h+12−3
@@ -28,25 +28,34 @@ class MockQOfono : public QObject
2828{
2929 Q_OBJECT
3030 Q_PROPERTY(bool available READ available WRITE setAvailable NOTIFY availableChanged)
31+ Q_PROPERTY(bool ready READ ready WRITE setReady NOTIFY readyChanged)
3132 Q_PROPERTY(QStringList modems READ modems NOTIFY modemsChanged)
3233
3334public:
34− explicit MockQOfono(QObject *parent = 0);
35+ static MockQOfono *instance();
36+ ~MockQOfono();
3537
3638 bool available() const;
3739 void setAvailable(bool available);
40+ bool ready() const;
41+ void setReady(bool ready);
3842 QStringList modems() const;
3943
40− Q_INVOKABLE void setModems(const QStringList &modems, const QList<bool> &present);
44+ Q_INVOKABLE void setModems(const QStringList &modems, const QList<bool> &present, const QList<bool> &ready);
4145 Q_INVOKABLE bool isModemPresent(const QString &modem);
46+ Q_INVOKABLE bool isModemReady(const QString &modem);
4247
4348Q_SIGNALS:
4449 void availableChanged();
50+ void readyChanged();
4551 void modemsChanged();
4652
4753private:
54+ explicit MockQOfono();
55+
4856 bool m_available;
49− QMap<QString, bool> m_modems;
57+ bool m_ready;
58+ QMap<QString, QList<bool>> m_modems;
5059};
5160
5261#endif // MOCK_QOFONO_H
tests/mocks/MeeGo/QOfono/MockQOfonoManager.cppnew file+66
@@ -0,0 +1,66 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "MockQOfono.h"
18+#include "MockQOfonoManager.h"
19+#include <QTimer>
20+
21+MockQOfonoManager::MockQOfonoManager(QObject *parent)
22+ : QObject(parent),
23+ m_modemsSet(false),
24+ m_startedSet(false)
25+{
26+ connect(MockQOfono::instance(), SIGNAL(availableChanged()),
27+ this, SIGNAL(availableChanged()));
28+ connect(MockQOfono::instance(), SIGNAL(readyChanged()),
29+ this, SLOT(checkReady()));
30+ connect(MockQOfono::instance(), SIGNAL(modemsChanged()),
31+ this, SLOT(maybeModemsChanged()));
32+
33+ checkReady();
34+}
35+
36+bool MockQOfonoManager::available() const
37+{
38+ return MockQOfono::instance()->available();
39+}
40+
41+QStringList MockQOfonoManager::modems() const
42+{
43+ return m_modemsSet ? MockQOfono::instance()->modems() : QStringList();
44+}
45+
46+void MockQOfonoManager::maybeModemsChanged()
47+{
48+ if (m_modemsSet) {
49+ Q_EMIT modemsChanged();
50+ }
51+}
52+
53+void MockQOfonoManager::checkReady()
54+{
55+ if (!m_startedSet && MockQOfono::instance()->ready()) {
56+ m_startedSet = true;
57+ // Simulate QOfono's asynchronous initialization
58+ QTimer::singleShot(1, this, SLOT(setModems()));
59+ }
60+}
61+
62+void MockQOfonoManager::setModems()
63+{
64+ m_modemsSet = true;
65+ Q_EMIT modemsChanged(); // always emitted, even if new modem list is empty too
66+}
tests/mocks/MeeGo/QOfono/MockQOfonoManager.hnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef MOCK_QOFONO_MANAGER_H
18+#define MOCK_QOFONO_MANAGER_H
19+
20+#include <QObject>
21+#include <QStringList>
22+
23+class MockQOfonoManager : public QObject
24+{
25+ Q_OBJECT
26+ Q_PROPERTY(bool available READ available NOTIFY availableChanged)
27+ Q_PROPERTY(QStringList modems READ modems NOTIFY modemsChanged)
28+
29+public:
30+ explicit MockQOfonoManager(QObject *parent = 0);
31+
32+ bool available() const;
33+ QStringList modems() const;
34+
35+Q_SIGNALS:
36+ void availableChanged();
37+ void modemsChanged();
38+
39+private Q_SLOTS:
40+ void maybeModemsChanged();
41+ void checkReady();
42+ void setModems();
43+
44+private:
45+ bool m_modemsSet;
46+ bool m_startedSet;
47+};
48+
49+#endif // MOCK_QOFONO_MANAGER_H
tests/mocks/MeeGo/QOfono/plugin.cpp+3−1
@@ -16,6 +16,7 @@
1616
1717#include "plugin.h"
1818#include "MockQOfono.h"
19+#include "MockQOfonoManager.h"
1920
2021#include <QtQml>
2122
@@ -23,11 +24,12 @@ static QObject *mock_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
2324{
2425 Q_UNUSED(engine)
2526 Q_UNUSED(scriptEngine)
26− return new MockQOfono();
27+ return MockQOfono::instance();
2728}
2829
2930void BackendPlugin::registerTypes(const char *uri)
3031{
3132 Q_ASSERT(uri == QLatin1String("MeeGo.QOfono"));
3233 qmlRegisterSingletonType<MockQOfono>(uri, 0, 2, "MockQOfono", mock_provider); // just for mock
34+ qmlRegisterType<MockQOfonoManager>(uri, 0, 2, "OfonoManager");
3335}
tests/mocks/MeeGo/QOfono/qmldir−1
@@ -1,4 +1,3 @@
11module MeeGo.QOfono
22plugin MockQOfono
3−OfonoManager 0.2 MockOfonoManager.qml
43OfonoSimManager 0.2 MockOfonoSimManager.qml
tests/qmltests/Wizard/tst_Wizard.qml+48−5
@@ -73,8 +73,9 @@ Item {
7373 AccountsService.hereEnabled = false;
7474 AccountsService.hereLicensePath = Qt.resolvedUrl("licenses");
7575 i18n.language = "en";
76− MockQOfono.setModems(["sim1"], [false]);
76+ MockQOfono.setModems(["sim1"], [false], []);
7777 MockQOfono.available = true;
78+ MockQOfono.ready = true;
7879 System.wizardEnabled = true;
7980
8081 updateSessionLanguageSpy.clear();
@@ -140,6 +141,19 @@ Item {
140141 tryCompareFunction(function() { return stack.currentPage.objectName; }, name);
141142 tryCompare(stack.currentPage, "opacity", 1.0);
142143 tryCompare(stack.currentPage, "enabled", true);
144+ tryCompare(stack.currentPage, "skipValid", true);
145+ tryCompare(stack.currentPage, "skip", false);
146+ waitForRendering(stack.currentPage);
147+ return stack.currentPage;
148+ }
149+
150+ function verifyPageIsBlocked(name) {
151+ var pages = findChild(wizard, "wizardPages");
152+ var stack = findChild(pages, "pageStack");
153+ // don't simply call tryCompare here, because stack.currentPage will be swapped out itself
154+ tryCompareFunction(function() { return stack.currentPage.objectName; }, name);
155+ tryCompare(stack.currentPage, "enabled", false);
156+ tryCompare(stack.currentPage, "skipValid", false);
143157 waitForRendering(stack.currentPage);
144158 return stack.currentPage;
145159 }
@@ -223,25 +237,54 @@ Item {
223237 }
224238
225239 function test_simNoModemsSkip() {
226− MockQOfono.setModems([], []);
240+ MockQOfono.setModems([], [], []);
227241 goToPage("passwdPage", true);
228242 }
229243
230244 function test_simFirstSkip() {
231− MockQOfono.setModems(["a", "b"], [true, false]);
245+ MockQOfono.setModems(["a", "b"], [true, false], []);
232246 goToPage("passwdPage", true);
233247 }
234248
235249 function test_simSecondSkip() {
236− MockQOfono.setModems(["a", "b"], [false, true]);
250+ MockQOfono.setModems(["a", "b"], [false, true], []);
237251 goToPage("passwdPage", true);
238252 }
239253
240254 function test_simBothSkip() {
241− MockQOfono.setModems(["a", "b"], [true, true]);
255+ MockQOfono.setModems(["a", "b"], [true, true], []);
242256 goToPage("passwdPage", true);
243257 }
244258
259+ function test_simWaitOnManagerAsync() {
260+ MockQOfono.ready = false;
261+ MockQOfono.setModems(["a"], [false], []);
262+
263+ // Go to SIM page, which will be waiting for skip to be valid
264+ var page = goToPage("languagePage");
265+ tap(findChild(page, "forwardButton"));
266+ verifyPageIsBlocked("simPage");
267+
268+ // Now release QOfono from blocking the page
269+ MockQOfono.ready = true;
270+
271+ waitForPage("simPage");
272+ }
273+
274+ function test_simWaitOnCardAsync() {
275+ MockQOfono.setModems(["a"], [false], [false]);
276+
277+ // Go to SIM page, which will be waiting for skip to be valid
278+ var page = goToPage("languagePage");
279+ tap(findChild(page, "forwardButton"));
280+ verifyPageIsBlocked("simPage");
281+
282+ // Now release QOfono from blocking the page
283+ MockQOfono.setModems(["a"], [false], [true]);
284+
285+ waitForPage("simPage");
286+ }
287+
245288 function enterPasscode(passcode) {
246289 for (var i = 0; i < passcode.length; ++i) {
247290 var character = passcode.charAt(i);