1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30#include <QLocalServer>
31#include <QLocalSocket>
32#include <QTimer>
33#include "../../qbearertestcommon.h"
34
35#ifndef QT_NO_BEARERMANAGEMENT
36#include <QtNetwork/qnetworkconfigmanager.h>
37#include <QtNetwork/qnetworksession.h>
38#include <private/qnetworksession_p.h>
39#endif
40
41QT_USE_NAMESPACE
42
43// Can be used to configure tests that require manual attention (such as roaming)
44//#define QNETWORKSESSION_MANUAL_TESTS 1
45
46#ifndef QT_NO_BEARERMANAGEMENT
47Q_DECLARE_METATYPE(QNetworkConfiguration::Type)
48#endif
49
50class tst_QNetworkSession : public QObject
51{
52 Q_OBJECT
53
54#ifndef QT_NO_BEARERMANAGEMENT
55public slots:
56 void initTestCase();
57 void cleanupTestCase();
58
59private slots:
60 void robustnessBombing();
61
62 void sessionClosing_data();
63 void sessionClosing();
64
65 void outOfProcessSession();
66 void invalidSession();
67
68 void repeatedOpenClose_data();
69 void repeatedOpenClose();
70
71 void sessionProperties_data();
72 void sessionProperties();
73
74 void userChoiceSession_data();
75 void userChoiceSession();
76
77 void sessionOpenCloseStop_data();
78 void sessionOpenCloseStop();
79
80 void sessionAutoClose_data();
81 void sessionAutoClose();
82
83 void usagePolicies();
84
85private:
86 QNetworkConfigurationManager manager;
87 int inProcessSessionManagementCount;
88 QString lackeyDir;
89#endif
90};
91
92#ifndef QT_NO_BEARERMANAGEMENT
93// Helper functions
94bool openSession(QNetworkSession *session);
95bool closeSession(QNetworkSession *session, bool lastSessionOnConfiguration = true);
96void updateConfigurations();
97void printConfigurations();
98QNetworkConfiguration suitableConfiguration(QString bearerType, QNetworkConfiguration::Type configType);
99
100void tst_QNetworkSession::initTestCase()
101{
102 qRegisterMetaType<QNetworkConfiguration>(typeName: "QNetworkConfiguration");
103 qRegisterMetaType<QNetworkConfiguration::Type>(typeName: "QNetworkConfiguration::Type");
104
105 inProcessSessionManagementCount = -1;
106
107 QSignalSpy spy(&manager, SIGNAL(updateCompleted()));
108 manager.updateConfigurations();
109 QTRY_VERIFY_WITH_TIMEOUT(spy.count() >= 1, TestTimeOut);
110
111 lackeyDir = QFINDTESTDATA("lackey");
112 QVERIFY2(!lackeyDir.isEmpty(), qPrintable(
113 QString::fromLatin1("Couldn't find lackey dir starting from %1.").arg(QDir::currentPath())));
114}
115
116void tst_QNetworkSession::cleanupTestCase()
117{
118 if (!(manager.capabilities() & QNetworkConfigurationManager::SystemSessionSupport) &&
119 (manager.capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces) &&
120 inProcessSessionManagementCount == 0) {
121 qWarning(msg: "No usable configurations found to complete all possible tests in "
122 "inProcessSessionManagement()");
123 }
124}
125
126// Robustness test for calling interfaces in nonsense order / with nonsense parameters
127void tst_QNetworkSession::robustnessBombing()
128{
129 QNetworkConfigurationManager mgr;
130 QNetworkSession testSession(mgr.defaultConfiguration());
131 // Should not reset even session is not opened
132 testSession.migrate();
133 testSession.accept();
134 testSession.ignore();
135 testSession.reject();
136}
137
138void tst_QNetworkSession::sessionClosing_data() {
139 QTest::addColumn<QString>(name: "bearerType");
140 QTest::addColumn<QNetworkConfiguration::Type>(name: "configurationType");
141
142 QTest::newRow(dataTag: "WLAN_IAP") << "WLAN" << QNetworkConfiguration::InternetAccessPoint;
143 QTest::newRow(dataTag: "Cellular_IAP") << "cellular" << QNetworkConfiguration::InternetAccessPoint;
144 QTest::newRow(dataTag: "SNAP") << "bearer_type_not_relevant_with_SNAPs" << QNetworkConfiguration::ServiceNetwork;
145}
146
147// Testcase for closing the session at unexpected times
148void tst_QNetworkSession::sessionClosing()
149{
150 QFETCH(QString, bearerType);
151 QFETCH(QNetworkConfiguration::Type, configurationType);
152
153 // Update configurations so that WLANs are discovered too.
154 updateConfigurations();
155
156 // First check that opening once succeeds and determine if test is doable
157 QNetworkConfiguration config = suitableConfiguration(bearerType, configType: configurationType);
158 if (!config.isValid())
159 QSKIP("No suitable configurations, skipping this round of repeated open-close test.");
160 qDebug() << "Using following configuration to bomb with close(): " << config.name();
161 QNetworkSession session(config);
162 if (!openSession(session: &session) || !closeSession(session: &session))
163 QSKIP("Unable to open/close session, skipping this round of close() bombing.");
164
165 qDebug() << "Closing without issuing open()";
166 session.close();
167
168 for (int i = 0; i < 25; i++) {
169 qDebug() << "Opening and then waiting: " << i * 100 << " ms before closing.";
170 session.open();
171 QTest::qWait(ms: i*100);
172 session.close();
173 // Sooner or later session must end in Disconnected state,
174 // no matter what the phase was.
175 QTRY_VERIFY_WITH_TIMEOUT(session.state() == QNetworkSession::Disconnected, TestTimeOut);
176 QTest::qWait(ms: 200); // Give platform a breathe, otherwise we'll be catching other errors
177 }
178}
179
180void tst_QNetworkSession::invalidSession()
181{
182 // 1. Verify that session created with invalid configuration remains in invalid state
183 QNetworkSession session(QNetworkConfiguration(), 0);
184 QVERIFY(!session.isOpen());
185 QCOMPARE(session.state(), QNetworkSession::Invalid);
186 QCOMPARE(session.error(), QNetworkSession::InvalidConfigurationError);
187
188 // 2. Verify that opening session with invalid configuration both 1) emits invalidconfigurationerror and 2) sets session's state as invalid.
189 QSignalSpy errorSpy(&session, SIGNAL(error(QNetworkSession::SessionError)));
190 session.open();
191 session.waitForOpened(msecs: 1000); // Should bail out right away
192 QCOMPARE(errorSpy.count(), 1);
193 QNetworkSession::SessionError error =
194 qvariant_cast<QNetworkSession::SessionError> (v: errorSpy.first().at(i: 0));
195 QCOMPARE(error, QNetworkSession::InvalidConfigurationError);
196 QCOMPARE(session.error(), QNetworkSession::InvalidConfigurationError);
197 QCOMPARE(session.state(), QNetworkSession::Invalid);
198
199#ifdef QNETWORKSESSION_MANUAL_TESTS
200
201 QNetworkConfiguration invalidatedConfig = suitableConfiguration("WLAN",QNetworkConfiguration::InternetAccessPoint);
202 if (invalidatedConfig.isValid()) {
203 // 3. Verify that invalidating a session after its successfully configured works
204 QNetworkSession invalidatedSession(invalidatedConfig);
205 qDebug() << "Delete the WLAN IAP from phone now (waiting 60 seconds): " << invalidatedConfig.name();
206 QTest::qWait(60000);
207 QVERIFY(!invalidatedConfig.isValid());
208 QCOMPARE(invalidatedSession.state(), QNetworkSession::Invalid);
209 qDebug() << "Add the WLAN IAP back (waiting 60 seconds): " << invalidatedConfig.name();
210 QTest::qWait(60000);
211 }
212
213 QNetworkConfiguration definedConfig = suitableConfiguration("WLAN",QNetworkConfiguration::InternetAccessPoint);
214 if (definedConfig.isValid()) {
215 // 4. Verify that opening a session with defined configuration emits error and enters notavailable-state
216 // TODO these timer waits should be changed to waiting appropriate signals, now these wait excessively
217 qDebug() << "Shutdown WLAN IAP (waiting 60 seconds): " << definedConfig.name();
218 QTest::qWait(60000);
219 // Shutting down WLAN should bring back to defined -state.
220 QVERIFY((definedConfig.state() & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined);
221 QNetworkSession definedSession(definedConfig);
222 QSignalSpy errorSpy(&definedSession, SIGNAL(error(QNetworkSession::SessionError)));
223 QNetworkSession::SessionError sessionError;
224 updateConfigurations();
225
226 definedSession.open();
227 updateConfigurations();
228
229 QVERIFY(definedConfig.isValid()); // Session remains valid
230 QVERIFY(definedSession.state() == QNetworkSession::NotAvailable); // State is not available because WLAN is not in coverage
231 QVERIFY(!errorSpy.isEmpty()); // Session tells with error about invalidated configuration
232 sessionError = qvariant_cast<QNetworkSession::SessionError> (errorSpy.first().at(0));
233 QCOMPARE(sessionError, QNetworkSession::InvalidConfigurationError);
234 qDebug() << "Turn the WLAN IAP back on (waiting 60 seconds): " << definedConfig.name();
235 QTest::qWait(60000);
236 updateConfigurations();
237 QCOMPARE(definedConfig.state(), QNetworkConfiguration::Discovered);
238 }
239#endif
240}
241
242void tst_QNetworkSession::sessionProperties_data()
243{
244 QTest::addColumn<QNetworkConfiguration>(name: "configuration");
245
246 QTest::newRow(dataTag: "invalid configuration") << QNetworkConfiguration();
247
248 foreach (const QNetworkConfiguration &config, manager.allConfigurations()) {
249 const QString name = config.name().isEmpty() ? QString("<Hidden>") : config.name();
250 QTest::newRow(dataTag: name.toLocal8Bit().constData()) << config;
251 }
252}
253
254void tst_QNetworkSession::sessionProperties()
255{
256 QFETCH(QNetworkConfiguration, configuration);
257 QNetworkSession session(configuration);
258 QCOMPARE(session.configuration(), configuration);
259 QStringList validBearerNames = QStringList() << QLatin1String("Unknown")
260 << QLatin1String("Ethernet")
261 << QLatin1String("WLAN")
262 << QLatin1String("2G")
263 << QLatin1String("CDMA2000")
264 << QLatin1String("WCDMA")
265 << QLatin1String("HSPA")
266 << QLatin1String("Bluetooth")
267 << QLatin1String("WiMAX")
268 << QLatin1String("BearerEVDO")
269 << QLatin1String("BearerLTE")
270 << QLatin1String("Bearer3G")
271 << QLatin1String("Bearer4G");
272
273 if (!configuration.isValid()) {
274 QVERIFY(configuration.bearerTypeName().isEmpty());
275 } else {
276 switch (configuration.type())
277 {
278 case QNetworkConfiguration::ServiceNetwork:
279 case QNetworkConfiguration::UserChoice:
280 default:
281 QVERIFY(configuration.bearerTypeName().isEmpty());
282 break;
283 case QNetworkConfiguration::InternetAccessPoint:
284 QVERIFY(validBearerNames.contains(configuration.bearerTypeName()));
285 break;
286 }
287 }
288
289 // QNetworkSession::interface() should return an invalid interface unless
290 // session is in the connected state.
291#ifndef QT_NO_NETWORKINTERFACE
292 QCOMPARE(session.state() == QNetworkSession::Connected, session.interface().isValid());
293#endif
294
295 if (!configuration.isValid()) {
296 QVERIFY(configuration.state() == QNetworkConfiguration::Undefined &&
297 session.state() == QNetworkSession::Invalid);
298 } else {
299 switch (configuration.state()) {
300 case QNetworkConfiguration::Undefined:
301 QCOMPARE(session.state(), QNetworkSession::NotAvailable);
302 break;
303 case QNetworkConfiguration::Defined:
304 QCOMPARE(session.state(), QNetworkSession::NotAvailable);
305 break;
306 case QNetworkConfiguration::Discovered:
307 QVERIFY(session.state() == QNetworkSession::Connecting ||
308 session.state() == QNetworkSession::Disconnected);
309 break;
310 case QNetworkConfiguration::Active:
311 QVERIFY(session.state() == QNetworkSession::Connected ||
312 session.state() == QNetworkSession::Closing ||
313 session.state() == QNetworkSession::Roaming);
314 break;
315 default:
316 QFAIL("Invalid configuration state");
317 };
318 }
319}
320
321void tst_QNetworkSession::repeatedOpenClose_data() {
322 QTest::addColumn<QString>(name: "bearerType");
323 QTest::addColumn<QNetworkConfiguration::Type>(name: "configurationType");
324 QTest::addColumn<int>(name: "repeatTimes");
325
326 QTest::newRow(dataTag: "WLAN_IAP") << "WLAN" << QNetworkConfiguration::InternetAccessPoint << 3;
327 // QTest::newRow("Cellular_IAP") << "cellular" << QNetworkConfiguration::InternetAccessPoint << 3;
328 // QTest::newRow("SNAP") << "bearer_type_not_relevant_with_SNAPs" << QNetworkConfiguration::ServiceNetwork << 3;
329}
330
331// Tests repeated-open close.
332void tst_QNetworkSession::repeatedOpenClose()
333{
334 QFETCH(QString, bearerType);
335 QFETCH(QNetworkConfiguration::Type, configurationType);
336 QFETCH(int, repeatTimes);
337
338 // First check that opening once succeeds and determine if repeatable testing is doable
339 QNetworkConfiguration config = suitableConfiguration(bearerType, configType: configurationType);
340 if (!config.isValid())
341 QSKIP("No suitable configurations, skipping this round of repeated open-close test.");
342 qDebug() << "Using following configuratio to repeatedly open and close: " << config.name();
343 QNetworkSession permanentSession(config);
344 if (!openSession(session: &permanentSession) || !closeSession(session: &permanentSession))
345 QSKIP("Unable to open/close session, skipping this round of repeated open-close test.");
346 for (int i = 0; i < repeatTimes; i++) {
347 qDebug() << "Opening, loop number " << i;
348 QVERIFY(openSession(&permanentSession));
349 qDebug() << "Closing, loop number, then waiting 5 seconds: " << i;
350 QVERIFY(closeSession(&permanentSession));
351 QTest::qWait(ms: 5000);
352 }
353}
354
355void tst_QNetworkSession::userChoiceSession_data()
356{
357 QTest::addColumn<QNetworkConfiguration>(name: "configuration");
358
359 QNetworkConfiguration config = manager.defaultConfiguration();
360 if (config.type() == QNetworkConfiguration::UserChoice)
361 QTest::newRow(dataTag: "UserChoice") << config;
362 else
363 QSKIP("Default configuration is not a UserChoice configuration.");
364}
365
366void tst_QNetworkSession::userChoiceSession()
367{
368 QFETCH(QNetworkConfiguration, configuration);
369
370 QCOMPARE(configuration.type(), QNetworkConfiguration::UserChoice);
371
372 QNetworkSession session(configuration);
373
374 // Check that configuration was really set
375 QCOMPARE(session.configuration(), configuration);
376
377 QVERIFY(!session.isOpen());
378
379 // Check that session is not active
380 QVERIFY(session.sessionProperty("ActiveConfiguration").toString().isEmpty());
381
382 // The remaining tests require the session to be not NotAvailable.
383 if (session.state() == QNetworkSession::NotAvailable)
384 QSKIP("Network is not available.");
385
386 QSignalSpy sessionOpenedSpy(&session, SIGNAL(opened()));
387 QSignalSpy sessionClosedSpy(&session, SIGNAL(closed()));
388 QSignalSpy stateChangedSpy(&session, SIGNAL(stateChanged(QNetworkSession::State)));
389 QSignalSpy errorSpy(&session, SIGNAL(error(QNetworkSession::SessionError)));
390
391 // Test opening the session.
392 {
393 bool expectStateChange = session.state() != QNetworkSession::Connected;
394
395 session.open();
396 session.waitForOpened();
397
398 if (session.isOpen())
399 QVERIFY(!sessionOpenedSpy.isEmpty() || !errorSpy.isEmpty());
400 if (!errorSpy.isEmpty()) {
401 QNetworkSession::SessionError error =
402 qvariant_cast<QNetworkSession::SessionError>(v: errorSpy.first().at(i: 0));
403 if (error == QNetworkSession::OperationNotSupportedError) {
404 // The session needed to bring up the interface,
405 // but the operation is not supported.
406 QSKIP("Configuration does not support open().");
407 } else if (error == QNetworkSession::InvalidConfigurationError) {
408 // The session needed to bring up the interface, but it is not possible for the
409 // specified configuration.
410 if ((session.configuration().state() & QNetworkConfiguration::Discovered) ==
411 QNetworkConfiguration::Discovered) {
412 QFAIL("Failed to open session for Discovered configuration.");
413 } else {
414 QSKIP("Cannot test session for non-Discovered configuration.");
415 }
416 } else if (error == QNetworkSession::UnknownSessionError) {
417 QSKIP("Unknown session error.");
418 } else {
419 QFAIL("Error opening session.");
420 }
421 } else if (!sessionOpenedSpy.isEmpty()) {
422 QCOMPARE(sessionOpenedSpy.count(), 1);
423 QVERIFY(sessionClosedSpy.isEmpty());
424 QVERIFY(errorSpy.isEmpty());
425
426 if (expectStateChange)
427 QTRY_VERIFY_WITH_TIMEOUT(!stateChangedSpy.isEmpty(), TestTimeOut);
428
429 QCOMPARE(session.state(), QNetworkSession::Connected);
430#ifndef QT_NO_NETWORKINTERFACE
431 QVERIFY(session.interface().isValid());
432#endif
433 const QString userChoiceIdentifier =
434 session.sessionProperty(key: "UserChoiceConfiguration").toString();
435
436 QVERIFY(!userChoiceIdentifier.isEmpty());
437 QVERIFY(userChoiceIdentifier != configuration.identifier());
438
439 QNetworkConfiguration userChoiceConfiguration =
440 manager.configurationFromIdentifier(identifier: userChoiceIdentifier);
441
442 QVERIFY(userChoiceConfiguration.isValid());
443 QVERIFY(userChoiceConfiguration.type() != QNetworkConfiguration::UserChoice);
444
445 const QString testIdentifier("abc");
446 //resetting UserChoiceConfiguration is ignored (read only property)
447 session.setSessionProperty(key: "UserChoiceConfiguration", value: testIdentifier);
448 QVERIFY(session.sessionProperty("UserChoiceConfiguration").toString() != testIdentifier);
449
450 const QString activeIdentifier =
451 session.sessionProperty(key: "ActiveConfiguration").toString();
452
453 QVERIFY(!activeIdentifier.isEmpty());
454 QVERIFY(activeIdentifier != configuration.identifier());
455
456 QNetworkConfiguration activeConfiguration =
457 manager.configurationFromIdentifier(identifier: activeIdentifier);
458
459 QVERIFY(activeConfiguration.isValid());
460 QCOMPARE(activeConfiguration.type(), QNetworkConfiguration::InternetAccessPoint);
461
462 //resetting ActiveConfiguration is ignored (read only property)
463 session.setSessionProperty(key: "ActiveConfiguration", value: testIdentifier);
464 QVERIFY(session.sessionProperty("ActiveConfiguration").toString() != testIdentifier);
465
466 if (userChoiceConfiguration.type() == QNetworkConfiguration::InternetAccessPoint) {
467 QCOMPARE(userChoiceConfiguration, activeConfiguration);
468 } else {
469 QCOMPARE(userChoiceConfiguration.type(), QNetworkConfiguration::ServiceNetwork);
470 QVERIFY(userChoiceConfiguration.children().contains(activeConfiguration));
471 }
472 } else {
473 QFAIL("Timeout waiting for session to open.");
474 }
475 }
476}
477
478void tst_QNetworkSession::sessionOpenCloseStop_data()
479{
480 QTest::addColumn<QNetworkConfiguration>(name: "configuration");
481 QTest::addColumn<bool>(name: "forceSessionStop");
482
483 foreach (const QNetworkConfiguration &config, manager.allConfigurations()) {
484 const QString name = config.name().isEmpty() ? QString("<Hidden>") : config.name();
485 QTest::newRow(dataTag: (name + QLatin1String(" close")).toLocal8Bit().constData())
486 << config << false;
487 QTest::newRow(dataTag: (name + QLatin1String(" stop")).toLocal8Bit().constData())
488 << config << true;
489 }
490
491 inProcessSessionManagementCount = 0;
492}
493
494void tst_QNetworkSession::sessionOpenCloseStop()
495{
496 QFETCH(QNetworkConfiguration, configuration);
497 QFETCH(bool, forceSessionStop);
498#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
499 QSKIP("Deadlocks on Linux due to QTBUG-45655");
500#endif
501
502 QNetworkSession session(configuration);
503
504 // Test initial state of the session.
505 {
506 QCOMPARE(session.configuration(), configuration);
507 QVERIFY(!session.isOpen());
508 // session may be invalid if configuration is removed between when
509 // sessionOpenCloseStop_data() is called and here.
510 QVERIFY((configuration.isValid() && (session.state() != QNetworkSession::Invalid)) ||
511 (!configuration.isValid() && (session.state() == QNetworkSession::Invalid)));
512 QCOMPARE(session.error(), QNetworkSession::UnknownSessionError);
513 }
514
515 // The remaining tests require the session to be not NotAvailable.
516 if (session.state() == QNetworkSession::NotAvailable)
517 QSKIP("Network is not available.");
518
519 QSignalSpy sessionOpenedSpy(&session, SIGNAL(opened()));
520 QSignalSpy sessionClosedSpy(&session, SIGNAL(closed()));
521 QSignalSpy stateChangedSpy(&session, SIGNAL(stateChanged(QNetworkSession::State)));
522 QSignalSpy errorSpy(&session, SIGNAL(error(QNetworkSession::SessionError)));
523
524 // Test opening the session.
525 {
526 QNetworkSession::State previousState = session.state();
527 bool expectStateChange = previousState != QNetworkSession::Connected;
528
529 session.open();
530 session.waitForOpened();
531
532 // Wait until the configuration is uptodate as well, it may be signaled 'connected'
533 // bit later than the session
534 QTRY_VERIFY_WITH_TIMEOUT(configuration.state() == QNetworkConfiguration::Active, TestTimeOut);
535
536 if (session.isOpen())
537 QVERIFY(!sessionOpenedSpy.isEmpty() || !errorSpy.isEmpty());
538 if (!errorSpy.isEmpty()) {
539 QNetworkSession::SessionError error =
540 qvariant_cast<QNetworkSession::SessionError>(v: errorSpy.first().at(i: 0));
541
542 QCOMPARE(session.state(), previousState);
543
544 if (error == QNetworkSession::OperationNotSupportedError) {
545 // The session needed to bring up the interface,
546 // but the operation is not supported.
547 QSKIP("Configuration does not support open().");
548 } else if (error == QNetworkSession::InvalidConfigurationError) {
549 // The session needed to bring up the interface, but it is not possible for the
550 // specified configuration.
551 if ((session.configuration().state() & QNetworkConfiguration::Discovered) ==
552 QNetworkConfiguration::Discovered) {
553 QFAIL("Failed to open session for Discovered configuration.");
554 } else {
555 QSKIP("Cannot test session for non-Discovered configuration.");
556 }
557 } else if (error == QNetworkSession::UnknownSessionError) {
558 QSKIP("Unknown Session error.");
559 } else {
560 QFAIL("Error opening session.");
561 }
562 } else if (!sessionOpenedSpy.isEmpty()) {
563 QCOMPARE(sessionOpenedSpy.count(), 1);
564 QVERIFY(sessionClosedSpy.isEmpty());
565 QVERIFY(errorSpy.isEmpty());
566
567 if (expectStateChange) {
568 QTRY_VERIFY_WITH_TIMEOUT(stateChangedSpy.count() >= 2, TestTimeOut);
569
570 QNetworkSession::State state =
571 qvariant_cast<QNetworkSession::State>(v: stateChangedSpy.at(i: 0).at(i: 0));
572 QCOMPARE(state, QNetworkSession::Connecting);
573
574 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy.at(i: 1).at(i: 0));
575 QCOMPARE(state, QNetworkSession::Connected);
576 }
577
578 QCOMPARE(session.state(), QNetworkSession::Connected);
579#ifndef QT_NO_NETWORKINTERFACE
580 QVERIFY(session.interface().isValid());
581#endif
582 } else {
583 QFAIL("Timeout waiting for session to open.");
584 }
585 }
586
587 sessionOpenedSpy.clear();
588 sessionClosedSpy.clear();
589 stateChangedSpy.clear();
590 errorSpy.clear();
591
592 QNetworkSession session2(configuration);
593
594 QSignalSpy sessionOpenedSpy2(&session2, SIGNAL(opened()));
595 QSignalSpy sessionClosedSpy2(&session2, SIGNAL(closed()));
596 QSignalSpy stateChangedSpy2(&session2, SIGNAL(stateChanged(QNetworkSession::State)));
597 QSignalSpy errorSpy2(&session2, SIGNAL(error(QNetworkSession::SessionError)));
598
599 // Test opening a second session.
600 {
601 QCOMPARE(session2.configuration(), configuration);
602 QVERIFY(!session2.isOpen());
603 QCOMPARE(session2.state(), QNetworkSession::Connected);
604 QCOMPARE(session.error(), QNetworkSession::UnknownSessionError);
605
606 session2.open();
607
608 QTRY_VERIFY_WITH_TIMEOUT(!sessionOpenedSpy2.isEmpty() || !errorSpy2.isEmpty(), TestTimeOut);
609
610 if (errorSpy2.isEmpty()) {
611 QVERIFY(session2.isOpen());
612 QCOMPARE(session2.state(), QNetworkSession::Connected);
613 }
614 QVERIFY(session.isOpen());
615 QCOMPARE(session.state(), QNetworkSession::Connected);
616#ifndef QT_NO_NETWORKINTERFACE
617 QVERIFY(session.interface().isValid());
618 if (errorSpy2.isEmpty()) {
619 QCOMPARE(session.interface().hardwareAddress(), session2.interface().hardwareAddress());
620 QCOMPARE(session.interface().index(), session2.interface().index());
621 }
622#endif
623 }
624
625 sessionOpenedSpy2.clear();
626
627 if (forceSessionStop && session2.isOpen()) {
628 // Test forcing the second session to stop the interface.
629 QNetworkSession::State previousState = session.state();
630 bool expectStateChange = previousState != QNetworkSession::Disconnected;
631 session2.stop();
632
633 // QNetworkSession::stop() must result either closed() signal
634 // or error() signal
635 QTRY_VERIFY_WITH_TIMEOUT(!sessionClosedSpy2.isEmpty() || !errorSpy2.isEmpty(), TestTimeOut);
636 QVERIFY(!session2.isOpen());
637
638 if (!errorSpy2.isEmpty()) {
639 // QNetworkSession::stop() resulted error() signal for session2
640 // => also session should emit error() signal
641 QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), TestTimeOut);
642
643 // check for SessionAbortedError
644 QNetworkSession::SessionError error =
645 qvariant_cast<QNetworkSession::SessionError>(v: errorSpy.first().at(i: 0));
646 QNetworkSession::SessionError error2 =
647 qvariant_cast<QNetworkSession::SessionError>(v: errorSpy2.first().at(i: 0));
648
649 QCOMPARE(error, QNetworkSession::SessionAbortedError);
650 QCOMPARE(error2, QNetworkSession::SessionAbortedError);
651
652 QCOMPARE(errorSpy.count(), 1);
653 QCOMPARE(errorSpy2.count(), 1);
654
655 errorSpy.clear();
656 errorSpy2.clear();
657 }
658
659 QVERIFY(errorSpy.isEmpty());
660 QVERIFY(errorSpy2.isEmpty());
661
662 // Wait for Disconnected state
663 QTRY_NOOP(session2.state() == QNetworkSession::Disconnected);
664
665 if (expectStateChange)
666 QTRY_VERIFY_WITH_TIMEOUT(stateChangedSpy2.count() >= 1 || !errorSpy2.isEmpty(), TestTimeOut);
667
668 if (!errorSpy2.isEmpty()) {
669 QCOMPARE(session2.state(), previousState);
670 QCOMPARE(session.state(), previousState);
671
672 QNetworkSession::SessionError error =
673 qvariant_cast<QNetworkSession::SessionError>(v: errorSpy2.first().at(i: 0));
674 if (error == QNetworkSession::OperationNotSupportedError) {
675 // The session needed to bring down the interface,
676 // but the operation is not supported.
677 QSKIP("Configuration does not support stop().");
678 } else if (error == QNetworkSession::InvalidConfigurationError) {
679 // The session needed to bring down the interface, but it is not possible for the
680 // specified configuration.
681 if ((session.configuration().state() & QNetworkConfiguration::Discovered) ==
682 QNetworkConfiguration::Discovered) {
683 QFAIL("Failed to stop session for Discovered configuration.");
684 } else {
685 QSKIP("Cannot test session for non-Discovered configuration.");
686 }
687 } else {
688 QFAIL("Error stopping session.");
689 }
690 } else if (!sessionClosedSpy2.isEmpty()) {
691 if (expectStateChange) {
692 if (configuration.type() == QNetworkConfiguration::ServiceNetwork) {
693 bool roamedSuccessfully = false;
694
695 QNetworkSession::State state;
696 if (stateChangedSpy2.count() == 4) {
697 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: 0).at(i: 0));
698 QCOMPARE(state, QNetworkSession::Connecting);
699
700 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: 1).at(i: 0));
701 QCOMPARE(state, QNetworkSession::Connected);
702
703 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: 2).at(i: 0));
704 QCOMPARE(state, QNetworkSession::Closing);
705
706 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: 3).at(i: 0));
707 QCOMPARE(state, QNetworkSession::Disconnected);
708 } else if (stateChangedSpy2.count() == 2) {
709 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: 0).at(i: 0));
710 QCOMPARE(state, QNetworkSession::Closing);
711
712 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: 1).at(i: 0));
713 QCOMPARE(state, QNetworkSession::Disconnected);
714 } else {
715 QFAIL("Unexpected amount of state changes when roaming.");
716 }
717
718 QTRY_VERIFY_WITH_TIMEOUT(session.state() == QNetworkSession::Roaming ||
719 session.state() == QNetworkSession::Connected ||
720 session.state() == QNetworkSession::Disconnected, TestTimeOut);
721
722 QTRY_VERIFY_WITH_TIMEOUT(stateChangedSpy.count() > 0, TestTimeOut);
723 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy.at(i: stateChangedSpy.count() - 1).at(i: 0));
724
725 for (int i = 0; i < stateChangedSpy.count(); i++) {
726 QNetworkSession::State state_temp =
727 qvariant_cast<QNetworkSession::State>(v: stateChangedSpy.at(i).at(i: 0));
728 // Extra debug because a fragile point in testcase because statuses vary.
729 qDebug() << "------- Statechange spy at: " << i << " is " << state_temp;
730 }
731
732 if (state == QNetworkSession::Roaming) {
733 QTRY_VERIFY_WITH_TIMEOUT(session.state() == QNetworkSession::Connected, TestTimeOut);
734 QTRY_VERIFY_WITH_TIMEOUT(session2.state() == QNetworkSession::Connected, TestTimeOut);
735 roamedSuccessfully = true;
736 } else if (state == QNetworkSession::Closing) {
737 QTRY_VERIFY_WITH_TIMEOUT(session2.state() == QNetworkSession::Disconnected, TestTimeOut);
738 QTRY_VERIFY_WITH_TIMEOUT(session.state() == QNetworkSession::Connected ||
739 session.state() == QNetworkSession::Disconnected, TestTimeOut );
740 roamedSuccessfully = false;
741 } else if (state == QNetworkSession::Disconnected) {
742 QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), TestTimeOut);
743 QTRY_VERIFY_WITH_TIMEOUT(session2.state() == QNetworkSession::Disconnected, TestTimeOut);
744 } else if (state == QNetworkSession::Connected) {
745 QTRY_VERIFY_WITH_TIMEOUT(errorSpy.isEmpty(),TestTimeOut);
746
747 if (stateChangedSpy.count() > 1) {
748 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy.at(i: stateChangedSpy.count() - 2).at(i: 0));
749 QCOMPARE(state, QNetworkSession::Roaming);
750 }
751 roamedSuccessfully = true;
752 }
753
754 if (roamedSuccessfully) {
755 // Verify that you can open session based on the disconnected configuration
756 QString configId = session.sessionProperty(key: "ActiveConfiguration").toString();
757 QNetworkConfiguration config = manager.configurationFromIdentifier(identifier: configId);
758 QNetworkSession session3(config);
759 QSignalSpy errorSpy3(&session3, SIGNAL(error(QNetworkSession::SessionError)));
760 QSignalSpy sessionOpenedSpy3(&session3, SIGNAL(opened()));
761 session3.open();
762 session3.waitForOpened();
763 QTest::qWait(ms: 1000); // Wait awhile to get all signals from platform
764 if (session.isOpen())
765 QVERIFY(!sessionOpenedSpy3.isEmpty() || !errorSpy3.isEmpty());
766 session.stop();
767 QTRY_VERIFY_WITH_TIMEOUT(session.state() == QNetworkSession::Disconnected, TestTimeOut);
768 }
769 if (!roamedSuccessfully)
770 QVERIFY(!errorSpy.isEmpty());
771 } else {
772 QTest::qWait(ms: 2000); // Wait awhile to get all signals from platform
773
774 if (stateChangedSpy2.count() == 2) {
775 QNetworkSession::State state =
776 qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: 0).at(i: 0));
777 QCOMPARE(state, QNetworkSession::Closing);
778 state = qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: 1).at(i: 0));
779 QCOMPARE(state, QNetworkSession::Disconnected);
780 } else {
781 QVERIFY(stateChangedSpy2.count() >= 1);
782
783 for (int i = 0; i < stateChangedSpy2.count(); i++) {
784 QNetworkSession::State state_temp =
785 qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i).at(i: 0));
786 // Extra debug because a fragile point in testcase.
787 qDebug() << "+++++ Statechange spy at: " << i << " is " << state_temp;
788 }
789
790 QNetworkSession::State state =
791 qvariant_cast<QNetworkSession::State>(v: stateChangedSpy2.at(i: stateChangedSpy2.count() - 1).at(i: 0));
792 QCOMPARE(state, QNetworkSession::Disconnected);
793 }
794 }
795
796 QTRY_VERIFY_WITH_TIMEOUT(!sessionClosedSpy.isEmpty(), TestTimeOut);
797 QTRY_VERIFY_WITH_TIMEOUT(session.state() == QNetworkSession::Disconnected, TestTimeOut);
798 }
799
800 QVERIFY(errorSpy2.isEmpty());
801
802 ++inProcessSessionManagementCount;
803 } else {
804 QFAIL("Timeout waiting for session to stop.");
805 }
806
807 QVERIFY(!sessionClosedSpy.isEmpty());
808 QVERIFY(!sessionClosedSpy2.isEmpty());
809
810 QVERIFY(!session.isOpen());
811 QVERIFY(!session2.isOpen());
812 } else if (session2.isOpen()) {
813 // Test closing the second session.
814 {
815 int stateChangedCountBeforeClose = stateChangedSpy2.count();
816 session2.close();
817
818 QTRY_VERIFY_WITH_TIMEOUT(!sessionClosedSpy2.isEmpty(), TestTimeOut);
819 QCOMPARE(stateChangedSpy2.count(), stateChangedCountBeforeClose);
820
821 QVERIFY(sessionClosedSpy.isEmpty());
822
823 QVERIFY(session.isOpen());
824 QVERIFY(!session2.isOpen());
825 QCOMPARE(session.state(), QNetworkSession::Connected);
826 QCOMPARE(session2.state(), QNetworkSession::Connected);
827#ifndef QT_NO_NETWORKINTERFACE
828 QVERIFY(session.interface().isValid());
829 QCOMPARE(session.interface().hardwareAddress(), session2.interface().hardwareAddress());
830 QCOMPARE(session.interface().index(), session2.interface().index());
831#endif
832 }
833
834 sessionClosedSpy2.clear();
835
836 // Test closing the first session.
837 {
838 bool expectStateChange = session.state() != QNetworkSession::Disconnected &&
839 manager.capabilities() & QNetworkConfigurationManager::SystemSessionSupport;
840
841 session.close();
842
843 QTRY_VERIFY_WITH_TIMEOUT(!sessionClosedSpy.isEmpty() || !errorSpy.isEmpty(), TestTimeOut);
844
845 QVERIFY(!session.isOpen());
846
847 if (expectStateChange)
848 QTRY_VERIFY_WITH_TIMEOUT(!stateChangedSpy.isEmpty() || !errorSpy.isEmpty(), TestTimeOut);
849
850 if (!errorSpy.isEmpty()) {
851 QNetworkSession::SessionError error =
852 qvariant_cast<QNetworkSession::SessionError>(v: errorSpy.first().at(i: 0));
853 if (error == QNetworkSession::OperationNotSupportedError) {
854 // The session needed to bring down the interface,
855 // but the operation is not supported.
856 QSKIP("Configuration does not support close().");
857 } else if (error == QNetworkSession::InvalidConfigurationError) {
858 // The session needed to bring down the interface, but it is not possible for the
859 // specified configuration.
860 if ((session.configuration().state() & QNetworkConfiguration::Discovered) ==
861 QNetworkConfiguration::Discovered) {
862 QFAIL("Failed to close session for Discovered configuration.");
863 } else {
864 QSKIP("Cannot test session for non-Discovered configuration.");
865 }
866 } else {
867 QFAIL("Error closing session.");
868 }
869 } else if (!sessionClosedSpy.isEmpty()) {
870 QVERIFY(sessionOpenedSpy.isEmpty());
871 QCOMPARE(sessionClosedSpy.count(), 1);
872 if (expectStateChange)
873 QVERIFY(!stateChangedSpy.isEmpty());
874 QVERIFY(errorSpy.isEmpty());
875
876 if (expectStateChange)
877 QTRY_VERIFY_WITH_TIMEOUT(session.state() == QNetworkSession::Disconnected, TestTimeOut);
878
879 ++inProcessSessionManagementCount;
880 } else {
881 QFAIL("Timeout waiting for session to close.");
882 }
883 }
884 }
885}
886
887QDebug operator<<(QDebug debug, const QList<QNetworkConfiguration> &list)
888{
889 debug.nospace() << "( ";
890 foreach (const QNetworkConfiguration &config, list)
891 debug.nospace() << config.identifier() << ", ";
892 debug.nospace() << ")\n";
893 return debug;
894}
895
896// Note: outOfProcessSession requires that at least one configuration is
897// at Discovered -state.
898void tst_QNetworkSession::outOfProcessSession()
899{
900#if !QT_CONFIG(process)
901 QSKIP("No qprocess support", SkipAll);
902#else
903 updateConfigurations();
904 QTest::qWait(ms: 2000);
905
906 QNetworkConfigurationManager manager;
907 // Create a QNetworkConfigurationManager to detect configuration changes made in Lackey. This
908 // is actually the essence of this testcase - to check that platform mediates/reflects changes
909 // regardless of process boundaries. The interprocess communication is more like a way to get
910 // this test-case act correctly and timely.
911 QList<QNetworkConfiguration> before = manager.allConfigurations(flags: QNetworkConfiguration::Active);
912 QSignalSpy spy(&manager, SIGNAL(configurationChanged(QNetworkConfiguration)));
913
914 // Cannot read/write to processes on WinCE.
915 // Easiest alternative is to use sockets for IPC.
916 QLocalServer oopServer;
917 // First remove possible earlier listening address which would cause listen to fail
918 // (e.g. previously abruptly ended unit test might cause this)
919 QLocalServer::removeServer(name: "tst_qnetworksession");
920 oopServer.listen(name: "tst_qnetworksession");
921
922 QProcess lackey;
923 QString lackeyExe = lackeyDir + "/lackey";
924 lackey.start(command: lackeyExe);
925 QVERIFY2(lackey.waitForStarted(), qPrintable(
926 QString::fromLatin1("Could not start %1: %2").arg(lackeyExe, lackey.errorString())));
927
928 QVERIFY(oopServer.waitForNewConnection(-1));
929 QLocalSocket *oopSocket = oopServer.nextPendingConnection();
930
931 do {
932 QByteArray output;
933
934 if (oopSocket->waitForReadyRead())
935 output = oopSocket->readLine().trimmed();
936
937 if (output.startsWith(c: "Started session ")) {
938 QString identifier = QString::fromLocal8Bit(str: output.mid(index: 20).constData());
939 QNetworkConfiguration changed;
940
941 do {
942 QTRY_VERIFY_WITH_TIMEOUT(!spy.isEmpty(), TestTimeOut);
943 changed = qvariant_cast<QNetworkConfiguration>(v: spy.takeFirst().at(i: 0));
944 } while (changed.identifier() != identifier);
945
946 QVERIFY((changed.state() & QNetworkConfiguration::Active) ==
947 QNetworkConfiguration::Active);
948
949 QVERIFY(!before.contains(changed));
950
951 QList<QNetworkConfiguration> after =
952 manager.allConfigurations(flags: QNetworkConfiguration::Active);
953
954 QVERIFY(after.contains(changed));
955
956 spy.clear();
957
958 oopSocket->write(data: "stop\n");
959 oopSocket->waitForBytesWritten();
960
961 do {
962 QTRY_VERIFY_WITH_TIMEOUT(!spy.isEmpty(), TestTimeOut);
963
964 changed = qvariant_cast<QNetworkConfiguration>(v: spy.takeFirst().at(i: 0));
965 } while (changed.identifier() != identifier);
966
967 QVERIFY((changed.state() & QNetworkConfiguration::Active) !=
968 QNetworkConfiguration::Active);
969
970 QList<QNetworkConfiguration> afterStop =
971 manager.allConfigurations(flags: QNetworkConfiguration::Active);
972
973 QVERIFY(!afterStop.contains(changed));
974
975 oopSocket->disconnectFromServer();
976 oopSocket->waitForDisconnected(msecs: -1);
977
978 lackey.waitForFinished();
979 }
980 // This is effected by QTBUG-4903, process will always report as running
981 //} while (lackey.state() == QProcess::Running);
982
983 // Workaround: the socket in the lackey will disconnect on exit
984 } while (oopSocket->state() == QLocalSocket::ConnectedState);
985
986 switch (lackey.exitCode()) {
987 case 0:
988 qDebug(msg: "Lackey returned exit success (0)");
989 break;
990 case 1:
991 QSKIP("No discovered configurations found.");
992 case 2:
993 QSKIP("Lackey could not start session.");
994 default:
995 QSKIP("Lackey failed");
996 }
997#endif
998}
999
1000// A convenience / helper function for testcases. Return the first matching configuration.
1001// Ignores configurations in other than 'discovered' -state. Returns invalid (QNetworkConfiguration())
1002// if none found.
1003QNetworkConfiguration suitableConfiguration(QString bearerType, QNetworkConfiguration::Type configType) {
1004
1005 // Refresh configurations and derive configurations matching given parameters.
1006 QNetworkConfigurationManager mgr;
1007 QSignalSpy updateSpy(&mgr, SIGNAL(updateCompleted()));
1008
1009 mgr.updateConfigurations();
1010 QTRY_NOOP(updateSpy.count() >= 1);
1011 if (updateSpy.count() != 1) {
1012 qDebug(msg: "tst_QNetworkSession::suitableConfiguration() failure: unable to update configurations");
1013 return QNetworkConfiguration();
1014 }
1015 QList<QNetworkConfiguration> discoveredConfigs = mgr.allConfigurations(flags: QNetworkConfiguration::Discovered);
1016 foreach(QNetworkConfiguration config, discoveredConfigs) {
1017 if ((config.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
1018 discoveredConfigs.removeOne(t: config);
1019 } else if (config.type() != configType) {
1020 // qDebug() << "Dumping config because type (IAP/SNAP) mismatches: " << config.name();
1021 discoveredConfigs.removeOne(t: config);
1022 } else if ((config.type() == QNetworkConfiguration::InternetAccessPoint) &&
1023 bearerType == "cellular") { // 'cellular' bearertype is for convenience
1024 if (config.bearerTypeName() != "2G" &&
1025 config.bearerTypeName() != "CDMA2000" &&
1026 config.bearerTypeName() != "WCDMA" &&
1027 config.bearerTypeName() != "HSPA" &&
1028 config.bearerTypeName() != "EVDO" &&
1029 config.bearerTypeName() != "LTE" &&
1030 config.bearerTypeName() != "3G" &&
1031 config.bearerTypeName() != "4G") {
1032 // qDebug() << "Dumping config because bearer mismatches (cellular): " << config.name();
1033 discoveredConfigs.removeOne(t: config);
1034 }
1035 } else if ((config.type() == QNetworkConfiguration::InternetAccessPoint) &&
1036 bearerType != config.bearerTypeName()) {
1037 // qDebug() << "Dumping config because bearer mismatches (WLAN): " << config.name();
1038 discoveredConfigs.removeOne(t: config);
1039 }
1040 }
1041 if (discoveredConfigs.isEmpty()) {
1042 qDebug(msg: "tst_QNetworkSession::suitableConfiguration() failure: no suitable configurations present.");
1043 return QNetworkConfiguration();
1044 } else {
1045 return discoveredConfigs.first();
1046 }
1047}
1048
1049// A convenience-function: updates configurations and waits that they are updated.
1050void updateConfigurations()
1051{
1052 QNetworkConfigurationManager mgr;
1053 QSignalSpy updateSpy(&mgr, SIGNAL(updateCompleted()));
1054 mgr.updateConfigurations();
1055 QTRY_NOOP(updateSpy.count() >= 1);
1056}
1057
1058// A convenience-function: updates and prints all available confiurations and their states
1059void printConfigurations()
1060{
1061 QNetworkConfigurationManager manager;
1062 QList<QNetworkConfiguration> allConfigs =
1063 manager.allConfigurations();
1064 qDebug(msg: "tst_QNetworkSession::printConfigurations QNetworkConfigurationManager gives following configurations: ");
1065 foreach(QNetworkConfiguration config, allConfigs) {
1066 qDebug() << "Name of the configuration: " << config.name();
1067 qDebug() << "State of the configuration: " << config.state();
1068 }
1069}
1070
1071// A convenience function for test-cases: opens the given configuration and return
1072// true if it was done gracefully.
1073bool openSession(QNetworkSession *session) {
1074 bool result = true;
1075 QNetworkConfigurationManager mgr;
1076 QSignalSpy openedSpy(session, SIGNAL(opened()));
1077 QSignalSpy stateChangeSpy(session, SIGNAL(stateChanged(QNetworkSession::State)));
1078 QSignalSpy errorSpy(session, SIGNAL(error(QNetworkSession::SessionError)));
1079 QSignalSpy configChangeSpy(&mgr, SIGNAL(configurationChanged(QNetworkConfiguration)));
1080 // Store some initial statuses, because expected signals differ if the config is already
1081 // active by some other session
1082 QNetworkConfiguration::StateFlags configInitState = session->configuration().state();
1083 QNetworkSession::State sessionInitState = session->state();
1084 qDebug() << "tst_QNetworkSession::openSession() name of the configuration to be opened: " << session->configuration().name();
1085 qDebug() << "tst_QNetworkSession::openSession() state of the configuration to be opened: " << session->configuration().state();
1086 qDebug() << "tst_QNetworkSession::openSession() state of the session to be opened: " << session->state();
1087
1088 if (session->isOpen() ||
1089 !session->sessionProperty(key: "ActiveConfiguration").toString().isEmpty()) {
1090 qDebug(msg: "tst_QNetworkSession::openSession() failure: session was already open / active.");
1091 result = false;
1092 } else {
1093 session->open();
1094 session->waitForOpened(msecs: 120000); // Bringing interfaces up and down may take time at platform
1095 }
1096 QTest::qWait(ms: 5000); // Wait a moment to ensure all signals are propagated
1097 // Check that connection opening went by the book. Add checks here if more strictness needed.
1098 if (!session->isOpen()) {
1099 qDebug(msg: "tst_QNetworkSession::openSession() failure: QNetworkSession::open() failed.");
1100 result = false;
1101 }
1102 if (openedSpy.count() != 1) {
1103 qDebug(msg: "tst_QNetworkSession::openSession() failure: QNetworkSession::opened() - signal not received.");
1104 result = false;
1105 }
1106 if (!errorSpy.isEmpty()) {
1107 qDebug(msg: "tst_QNetworkSession::openSession() failure: QNetworkSession::error() - signal was detected.");
1108 result = false;
1109 }
1110 if (sessionInitState != QNetworkSession::Connected &&
1111 stateChangeSpy.isEmpty()) {
1112 qDebug(msg: "tst_QNetworkSession::openSession() failure: QNetworkSession::stateChanged() - signals not detected.");
1113 result = false;
1114 }
1115 if (configInitState != QNetworkConfiguration::Active &&
1116 configChangeSpy.isEmpty()) {
1117 qDebug(msg: "tst_QNetworkSession::openSession() failure: QNetworkConfigurationManager::configurationChanged() - signals not detected.");
1118 result = false;
1119 }
1120 if (session->configuration().state() != QNetworkConfiguration::Active) {
1121 qDebug(msg: "tst_QNetworkSession::openSession() failure: session's configuration is not in 'Active' -state.");
1122 qDebug() << "tst_QNetworkSession::openSession() state is: " << session->configuration().state();
1123 result = false;
1124 }
1125 if (result == false) {
1126 qDebug() << "tst_QNetworkSession::openSession() opening session failed.";
1127 } else {
1128 qDebug() << "tst_QNetworkSession::openSession() opening session succeeded.";
1129 }
1130 qDebug() << "tst_QNetworkSession::openSession() name of the configuration is: " << session->configuration().name();
1131 qDebug() << "tst_QNetworkSession::openSession() configuration state is: " << session->configuration().state();
1132 qDebug() << "tst_QNetworkSession::openSession() session state is: " << session->state();
1133
1134 return result;
1135}
1136
1137// Helper function for closing opened session. Performs checks that
1138// session is closed gradefully (e.g. signals). Function does not delete
1139// the session. The lastSessionOnConfiguration (true by default) is used to
1140// tell if there are more sessions open, basing on same configuration. This
1141// impacts the checks made.
1142bool closeSession(QNetworkSession *session, bool lastSessionOnConfiguration) {
1143 if (!session) {
1144 qDebug(msg: "tst_QNetworkSession::closeSession() failure: NULL session given");
1145 return false;
1146 }
1147
1148 qDebug() << "tst_QNetworkSession::closeSession() name of the configuration to be closed: " << session->configuration().name();
1149 qDebug() << "tst_QNetworkSession::closeSession() state of the configuration to be closed: " << session->configuration().state();
1150 qDebug() << "tst_QNetworkSession::closeSession() state of the session to be closed: " << session->state();
1151
1152 if (session->state() != QNetworkSession::Connected ||
1153 !session->isOpen()) {
1154 qDebug(msg: "tst_QNetworkSession::closeSession() failure: session is not opened.");
1155 return false;
1156 }
1157 QNetworkConfigurationManager mgr;
1158 QSignalSpy sessionClosedSpy(session, SIGNAL(closed()));
1159 QSignalSpy sessionStateChangedSpy(session, SIGNAL(stateChanged(QNetworkSession::State)));
1160 QSignalSpy sessionErrorSpy(session, SIGNAL(error(QNetworkSession::SessionError)));
1161 QSignalSpy configChangeSpy(&mgr, SIGNAL(configurationChanged(QNetworkConfiguration)));
1162
1163 bool result = true;
1164 session->close();
1165 QTest::qWait(ms: 5000); // Wait a moment so that all signals are propagated
1166
1167 if (!sessionErrorSpy.isEmpty()) {
1168 qDebug(msg: "tst_QNetworkSession::closeSession() failure: QNetworkSession::error() received.");
1169 result = false;
1170 }
1171 if (sessionClosedSpy.count() != 1) {
1172 qDebug(msg: "tst_QNetworkSession::closeSession() failure: QNetworkSession::closed() signal not received.");
1173 result = false;
1174 }
1175 if (lastSessionOnConfiguration &&
1176 sessionStateChangedSpy.isEmpty()) {
1177 qDebug(msg: "tst_QNetworkSession::closeSession() failure: QNetworkSession::stateChanged() signals not received.");
1178 result = false;
1179 }
1180 if (lastSessionOnConfiguration &&
1181 session->state() != QNetworkSession::Disconnected) {
1182 qDebug(msg: "tst_QNetworkSession::closeSession() failure: QNetworkSession is not in Disconnected -state");
1183 result = false;
1184 }
1185 QTRY_NOOP(!configChangeSpy.isEmpty());
1186 if (lastSessionOnConfiguration &&
1187 configChangeSpy.isEmpty()) {
1188 qDebug(msg: "tst_QNetworkSession::closeSession() failure: QNetworkConfigurationManager::configurationChanged() - signal not detected.");
1189 result = false;
1190 }
1191 if (lastSessionOnConfiguration &&
1192 session->configuration().state() == QNetworkConfiguration::Active) {
1193 qDebug(msg: "tst_QNetworkSession::closeSession() failure: session's configuration is still in active state.");
1194 result = false;
1195 }
1196 if (result == false) {
1197 qDebug() << "tst_QNetworkSession::closeSession() closing session failed.";
1198 } else {
1199 qDebug() << "tst_QNetworkSession::closeSession() closing session succeeded.";
1200 }
1201 qDebug() << "tst_QNetworkSession::closeSession() name of the configuration is: " << session->configuration().name();
1202 qDebug() << "tst_QNetworkSession::closeSession() configuration state is: " << session->configuration().state();
1203 qDebug() << "tst_QNetworkSession::closeSession() session state is: " << session->state();
1204 return result;
1205}
1206
1207void tst_QNetworkSession::sessionAutoClose_data()
1208{
1209 QTest::addColumn<QNetworkConfiguration>(name: "configuration");
1210
1211 bool testData = false;
1212 foreach (const QNetworkConfiguration &config,
1213 manager.allConfigurations(QNetworkConfiguration::Discovered)) {
1214 QNetworkSession session(config);
1215 if (!session.sessionProperty(key: QLatin1String("AutoCloseSessionTimeout")).isValid())
1216 continue;
1217
1218 testData = true;
1219
1220 const QString name = config.name().isEmpty() ? QString("<Hidden>") : config.name();
1221 QTest::newRow(dataTag: name.toLocal8Bit().constData()) << config;
1222 }
1223
1224 if (!testData)
1225 QSKIP("No applicable configurations to test");
1226}
1227
1228void tst_QNetworkSession::sessionAutoClose()
1229{
1230 QFETCH(QNetworkConfiguration, configuration);
1231
1232 QNetworkSession session(configuration);
1233
1234 QCOMPARE(session.configuration(), configuration);
1235
1236 QVariant autoCloseSession = session.sessionProperty(key: QLatin1String("AutoCloseSessionTimeout"));
1237
1238 QVERIFY(autoCloseSession.isValid());
1239
1240 // property defaults to false
1241 QCOMPARE(autoCloseSession.toInt(), -1);
1242
1243 QSignalSpy closeSpy(&session, SIGNAL(closed()));
1244
1245 session.open();
1246 session.waitForOpened();
1247
1248 if (!session.isOpen())
1249 QSKIP("Session not open");
1250
1251 // set session to auto close at next polling interval.
1252 session.setSessionProperty(key: QLatin1String("AutoCloseSessionTimeout"), value: 0);
1253
1254 QTRY_VERIFY_WITH_TIMEOUT(!closeSpy.isEmpty(), TestTimeOut);
1255
1256 QCOMPARE(session.state(), QNetworkSession::Connected);
1257
1258 QVERIFY(!session.isOpen());
1259
1260 QCOMPARE(session.configuration(), configuration);
1261
1262 autoCloseSession = session.sessionProperty(key: QLatin1String("AutoCloseSessionTimeout"));
1263
1264 QVERIFY(autoCloseSession.isValid());
1265
1266 QCOMPARE(autoCloseSession.toInt(), -1);
1267}
1268
1269void tst_QNetworkSession::usagePolicies()
1270{
1271 QNetworkSession session(manager.defaultConfiguration());
1272 QNetworkSession::UsagePolicies initial;
1273 initial = session.usagePolicies();
1274 if (initial != 0)
1275 QNetworkSessionPrivate::setUsagePolicies(session, { });
1276 QSignalSpy spy(&session, SIGNAL(usagePoliciesChanged(QNetworkSession::UsagePolicies)));
1277 QNetworkSessionPrivate::setUsagePolicies(session, QNetworkSession::NoBackgroundTrafficPolicy);
1278 QCOMPARE(spy.count(), 1);
1279 QNetworkSession::UsagePolicies policies = qvariant_cast<QNetworkSession::UsagePolicies>(v: spy.at(i: 0).at(i: 0));
1280 QCOMPARE(policies, QNetworkSession::NoBackgroundTrafficPolicy);
1281 QCOMPARE(session.usagePolicies(), QNetworkSession::NoBackgroundTrafficPolicy);
1282 QNetworkSessionPrivate::setUsagePolicies(session, initial);
1283 spy.clear();
1284
1285 session.open();
1286 QVERIFY(session.waitForOpened());
1287
1288 //policies may be changed when session is opened, if so, signal should have been emitted
1289 if (session.usagePolicies() != initial)
1290 QCOMPARE(spy.count(), 1);
1291 else
1292 QCOMPARE(spy.count(), 0);
1293}
1294
1295
1296#endif
1297
1298QTEST_MAIN(tst_QNetworkSession)
1299#include "tst_qnetworksession.moc"
1300

source code of qtbase/tests/auto/network/bearer/qnetworksession/test/tst_qnetworksession.cpp