1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30
31// When using WinSock2 on Windows, it's the first thing that can be included
32// (except qglobal.h), or else you'll get tons of compile errors
33#include <qglobal.h>
34
35// To prevent windows system header files from re-defining min/max
36#define NOMINMAX 1
37
38#if defined(Q_OS_WIN)
39# include <winsock2.h>
40# include <ws2tcpip.h>
41#endif
42
43#include <QtTest/QtTest>
44#include <qcoreapplication.h>
45#include <QDebug>
46#include <QTcpSocket>
47#include <private/qthread_p.h>
48#include <QTcpServer>
49
50#ifndef QT_NO_BEARERMANAGEMENT
51#include <QtNetwork/qnetworkconfigmanager.h>
52#include <QtNetwork/qnetworkconfiguration.h>
53#include <QtNetwork/qnetworksession.h>
54#endif
55
56#include <time.h>
57#if defined(Q_OS_WIN)
58#include <windows.h>
59#else
60#include <unistd.h>
61#include <signal.h>
62#endif
63
64#include <qhostinfo.h>
65#include "private/qhostinfo_p.h"
66
67#include <sys/types.h>
68#if defined(Q_OS_UNIX)
69# include <sys/socket.h>
70# include <netdb.h>
71#endif
72
73#include "../../../network-settings.h"
74
75#define TEST_DOMAIN ".test.qt-project.org"
76
77
78class tst_QHostInfo : public QObject
79{
80 Q_OBJECT
81
82private slots:
83 void init();
84 void initTestCase();
85 void swapFunction();
86 void moveOperator();
87 void getSetCheck();
88 void staticInformation();
89 void lookupIPv4_data();
90 void lookupIPv4();
91 void lookupIPv6_data();
92 void lookupIPv6();
93 void lookupConnectToFunctionPointer_data();
94 void lookupConnectToFunctionPointer();
95 void lookupConnectToFunctionPointerDeleted();
96 void lookupConnectToLambda_data();
97 void lookupConnectToLambda();
98 void reverseLookup_data();
99 void reverseLookup();
100
101 void blockingLookup_data();
102 void blockingLookup();
103
104 void raceCondition();
105 void threadSafety();
106 void threadSafetyAsynchronousAPI();
107
108 void multipleSameLookups();
109 void multipleDifferentLookups_data();
110 void multipleDifferentLookups();
111
112 void cache();
113
114 void abortHostLookup();
115protected slots:
116 void resultsReady(const QHostInfo &);
117
118private:
119 bool ipv6LookupsAvailable;
120 bool ipv6Available;
121 bool lookupDone;
122 int lookupsDoneCounter;
123 QHostInfo lookupResults;
124#ifndef QT_NO_BEARERMANAGEMENT
125 QNetworkConfigurationManager *netConfMan;
126 QNetworkConfiguration networkConfiguration;
127 QScopedPointer<QNetworkSession> networkSession;
128#endif
129};
130
131void tst_QHostInfo::swapFunction()
132{
133 QHostInfo obj1, obj2;
134 obj1.setError(QHostInfo::HostInfoError(0));
135 obj2.setError(QHostInfo::HostInfoError(1));
136 obj1.swap(other&: obj2);
137 QCOMPARE(QHostInfo::HostInfoError(0), obj2.error());
138 QCOMPARE(QHostInfo::HostInfoError(1), obj1.error());
139}
140
141void tst_QHostInfo::moveOperator()
142{
143 QHostInfo obj1, obj2, obj3(1);
144 obj1.setError(QHostInfo::HostInfoError(0));
145 obj2.setError(QHostInfo::HostInfoError(1));
146 obj1 = std::move(obj2);
147 obj2 = obj3;
148 QCOMPARE(QHostInfo::HostInfoError(1), obj1.error());
149 QCOMPARE(obj3.lookupId(), obj2.lookupId());
150}
151
152
153
154// Testing get/set functions
155void tst_QHostInfo::getSetCheck()
156{
157 QHostInfo obj1;
158 // HostInfoError QHostInfo::error()
159 // void QHostInfo::setError(HostInfoError)
160 obj1.setError(QHostInfo::HostInfoError(0));
161 QCOMPARE(QHostInfo::HostInfoError(0), obj1.error());
162 obj1.setError(QHostInfo::HostInfoError(1));
163 QCOMPARE(QHostInfo::HostInfoError(1), obj1.error());
164
165 // int QHostInfo::lookupId()
166 // void QHostInfo::setLookupId(int)
167 obj1.setLookupId(0);
168 QCOMPARE(0, obj1.lookupId());
169 obj1.setLookupId(INT_MIN);
170 QCOMPARE(INT_MIN, obj1.lookupId());
171 obj1.setLookupId(INT_MAX);
172 QCOMPARE(INT_MAX, obj1.lookupId());
173}
174
175void tst_QHostInfo::staticInformation()
176{
177 qDebug() << "Hostname:" << QHostInfo::localHostName();
178 qDebug() << "Domain name:" << QHostInfo::localDomainName();
179}
180
181void tst_QHostInfo::initTestCase()
182{
183#ifndef QT_NO_BEARERMANAGEMENT
184 //start the default network
185 netConfMan = new QNetworkConfigurationManager(this);
186 networkConfiguration = netConfMan->defaultConfiguration();
187 networkSession.reset(other: new QNetworkSession(networkConfiguration));
188 if (!networkSession->isOpen()) {
189 networkSession->open();
190 networkSession->waitForOpened(msecs: 30000);
191 }
192#endif
193
194 ipv6Available = false;
195 ipv6LookupsAvailable = false;
196
197 QTcpServer server;
198 if (server.listen(address: QHostAddress("::1"))) {
199 // We have IPv6 support
200 ipv6Available = true;
201 }
202
203 // check if the system getaddrinfo can do IPv6 lookups
204 struct addrinfo hint, *result = 0;
205 memset(s: &hint, c: 0, n: sizeof hint);
206 hint.ai_family = AF_UNSPEC;
207#ifdef AI_ADDRCONFIG
208 hint.ai_flags = AI_ADDRCONFIG;
209#endif
210
211 int res = getaddrinfo(name: "::1", service: "80", req: &hint, pai: &result);
212 if (res == 0) {
213 // this test worked
214 freeaddrinfo(ai: result);
215 res = getaddrinfo(name: "aaaa-single" TEST_DOMAIN, service: "80", req: &hint, pai: &result);
216 if (res == 0 && result != 0 && result->ai_family != AF_INET) {
217 freeaddrinfo(ai: result);
218 ipv6LookupsAvailable = true;
219 }
220 }
221
222 // run each testcase with and without test enabled
223 QTest::addColumn<bool>(name: "cache");
224 QTest::newRow(dataTag: "WithCache") << true;
225 QTest::newRow(dataTag: "WithoutCache") << false;
226}
227
228void tst_QHostInfo::init()
229{
230 // delete the cache so inidividual testcase results are independent from each other
231 qt_qhostinfo_clear_cache();
232
233 QFETCH_GLOBAL(bool, cache);
234 qt_qhostinfo_enable_cache(e: cache);
235}
236
237void tst_QHostInfo::lookupIPv4_data()
238{
239 QTest::addColumn<QString>(name: "hostname");
240 QTest::addColumn<QString>(name: "addresses");
241 QTest::addColumn<int>(name: "err");
242
243 QTest::newRow(dataTag: "empty") << "" << "" << int(QHostInfo::HostNotFound);
244
245 QTest::newRow(dataTag: "single_ip4") << "a-single" TEST_DOMAIN << "192.0.2.1" << int(QHostInfo::NoError);
246 QTest::newRow(dataTag: "multiple_ip4") << "a-multi" TEST_DOMAIN << "192.0.2.1 192.0.2.2 192.0.2.3" << int(QHostInfo::NoError);
247 QTest::newRow(dataTag: "literal_ip4") << "192.0.2.1" << "192.0.2.1" << int(QHostInfo::NoError);
248
249 QTest::newRow(dataTag: "notfound") << "invalid" TEST_DOMAIN << "" << int(QHostInfo::HostNotFound);
250
251 QTest::newRow(dataTag: "idn-ace") << "a-single.xn--alqualond-34a" TEST_DOMAIN << "192.0.2.1" << int(QHostInfo::NoError);
252 QTest::newRow(dataTag: "idn-unicode") << QString::fromLatin1(str: "a-single.alqualond\353" TEST_DOMAIN) << "192.0.2.1" << int(QHostInfo::NoError);
253}
254
255void tst_QHostInfo::lookupIPv4()
256{
257 QFETCH(QString, hostname);
258 QFETCH(int, err);
259 QFETCH(QString, addresses);
260
261 lookupDone = false;
262 QHostInfo::lookupHost(name: hostname, receiver: this, SLOT(resultsReady(QHostInfo)));
263
264 QTestEventLoop::instance().enterLoop(secs: 10);
265 QVERIFY(!QTestEventLoop::instance().timeout());
266 QVERIFY(lookupDone);
267
268 if ((int)lookupResults.error() != (int)err) {
269 qWarning() << hostname << "=>" << lookupResults.errorString();
270 }
271 QCOMPARE((int)lookupResults.error(), (int)err);
272
273 QStringList tmp;
274 for (int i = 0; i < lookupResults.addresses().count(); ++i)
275 tmp.append(t: lookupResults.addresses().at(i).toString());
276 tmp.sort();
277
278 QStringList expected = addresses.split(sep: ' ');
279 expected.sort();
280
281 QCOMPARE(tmp.join(' '), expected.join(' '));
282}
283
284void tst_QHostInfo::lookupIPv6_data()
285{
286 QTest::addColumn<QString>(name: "hostname");
287 QTest::addColumn<QString>(name: "addresses");
288 QTest::addColumn<int>(name: "err");
289
290 QTest::newRow(dataTag: "aaaa-single") << "aaaa-single" TEST_DOMAIN << "2001:db8::1" << int(QHostInfo::NoError);
291 QTest::newRow(dataTag: "aaaa-multi") << "aaaa-multi" TEST_DOMAIN << "2001:db8::1 2001:db8::2 2001:db8::3" << int(QHostInfo::NoError);
292 QTest::newRow(dataTag: "a-plus-aaaa") << "a-plus-aaaa" TEST_DOMAIN << "198.51.100.1 2001:db8::1:1" << int(QHostInfo::NoError);
293
294 // avoid using real IPv6 addresses here because this will do a DNS query
295 // real addresses are between 2000:: and 3fff:ffff:ffff:ffff:ffff:ffff:ffff
296 QTest::newRow(dataTag: "literal_ip6") << "f001:6b0:1:ea:202:a5ff:fecd:13a6" << "f001:6b0:1:ea:202:a5ff:fecd:13a6" << int(QHostInfo::NoError);
297 QTest::newRow(dataTag: "literal_shortip6") << "f001:618:1401::4" << "f001:618:1401::4" << int(QHostInfo::NoError);
298}
299
300void tst_QHostInfo::lookupIPv6()
301{
302 QFETCH(QString, hostname);
303 QFETCH(int, err);
304 QFETCH(QString, addresses);
305
306 if (!ipv6LookupsAvailable)
307 QSKIP("This platform does not support IPv6 lookups");
308
309 lookupDone = false;
310 QHostInfo::lookupHost(name: hostname, receiver: this, SLOT(resultsReady(QHostInfo)));
311
312 QTestEventLoop::instance().enterLoop(secs: 10);
313 QVERIFY(!QTestEventLoop::instance().timeout());
314 QVERIFY(lookupDone);
315
316 QCOMPARE((int)lookupResults.error(), (int)err);
317
318 QStringList tmp;
319 for (int i = 0; i < lookupResults.addresses().count(); ++i)
320 tmp.append(t: lookupResults.addresses().at(i).toString());
321 tmp.sort();
322
323 QStringList expected = addresses.split(sep: ' ');
324 expected.sort();
325
326 QCOMPARE(tmp.join(' ').toLower(), expected.join(' ').toLower());
327}
328
329void tst_QHostInfo::lookupConnectToFunctionPointer_data()
330{
331 lookupIPv4_data();
332}
333
334void tst_QHostInfo::lookupConnectToFunctionPointer()
335{
336 QFETCH(QString, hostname);
337 QFETCH(int, err);
338 QFETCH(QString, addresses);
339
340 lookupDone = false;
341 QHostInfo::lookupHost(name: hostname, receiver: this, slot: &tst_QHostInfo::resultsReady);
342
343 QTestEventLoop::instance().enterLoop(secs: 10);
344 QVERIFY(!QTestEventLoop::instance().timeout());
345 QVERIFY(lookupDone);
346
347 if (int(lookupResults.error()) != int(err))
348 qWarning() << hostname << "=>" << lookupResults.errorString();
349 QCOMPARE(int(lookupResults.error()), int(err));
350
351 QStringList tmp;
352 for (const auto &result : lookupResults.addresses())
353 tmp.append(t: result.toString());
354 tmp.sort();
355
356 QStringList expected = addresses.split(sep: ' ');
357 expected.sort();
358
359 QCOMPARE(tmp.join(' '), expected.join(' '));
360}
361
362void tst_QHostInfo::lookupConnectToFunctionPointerDeleted()
363{
364 {
365 QObject contextObject;
366 QHostInfo::lookupHost(name: "localhost", context: &contextObject, slot: [](const QHostInfo){
367 QFAIL("This should never be called!");
368 });
369 }
370 QTestEventLoop::instance().enterLoop(secs: 3);
371}
372
373void tst_QHostInfo::lookupConnectToLambda_data()
374{
375 lookupIPv4_data();
376}
377
378void tst_QHostInfo::lookupConnectToLambda()
379{
380 QFETCH(QString, hostname);
381 QFETCH(int, err);
382 QFETCH(QString, addresses);
383
384 lookupDone = false;
385 QHostInfo::lookupHost(name: hostname, slot: [=](const QHostInfo &hostInfo) {
386 resultsReady(hostInfo);
387 });
388
389 QTestEventLoop::instance().enterLoop(secs: 10);
390 QVERIFY(!QTestEventLoop::instance().timeout());
391 QVERIFY(lookupDone);
392
393 if (int(lookupResults.error()) != int(err))
394 qWarning() << hostname << "=>" << lookupResults.errorString();
395 QCOMPARE(int(lookupResults.error()), int(err));
396
397 QStringList tmp;
398 for (int i = 0; i < lookupResults.addresses().count(); ++i)
399 tmp.append(t: lookupResults.addresses().at(i).toString());
400 tmp.sort();
401
402 QStringList expected = addresses.split(sep: ' ');
403 expected.sort();
404
405 QCOMPARE(tmp.join(' '), expected.join(' '));
406}
407
408static QStringList reverseLookupHelper(const QString &ip)
409{
410 QStringList results;
411
412 const QString pythonCode =
413 "import socket;"
414 "import sys;"
415 "print (socket.getnameinfo((sys.argv[1], 0), 0)[0]);";
416
417 QList<QByteArray> lines;
418 QProcess python;
419 python.setProcessChannelMode(QProcess::ForwardedErrorChannel);
420 python.start(program: "python", arguments: QStringList() << QString("-c") << pythonCode << ip);
421 if (python.waitForFinished()) {
422 if (python.exitStatus() == QProcess::NormalExit && python.exitCode() == 0)
423 lines = python.readAllStandardOutput().split(sep: '\n');
424 for (QByteArray line : lines) {
425 if (!line.isEmpty())
426 results << line.trimmed();
427 }
428 if (!results.isEmpty())
429 return results;
430 }
431
432 qDebug() << "Python failed, falling back to nslookup";
433 QProcess lookup;
434 lookup.setProcessChannelMode(QProcess::ForwardedErrorChannel);
435 lookup.start(program: "nslookup", arguments: QStringList(ip));
436 if (!lookup.waitForFinished()) {
437 results << "nslookup failure";
438 qDebug() << "nslookup failure";
439 return results;
440 }
441 lines = lookup.readAllStandardOutput().split(sep: '\n');
442
443 QByteArray name;
444
445 const QByteArray nameMarkerNix("name =");
446 const QByteArray nameMarkerWin("Name:");
447 const QByteArray addressMarkerWin("Address:");
448
449 for (QByteArray line : lines) {
450 int index = -1;
451 if ((index = line.indexOf(a: nameMarkerNix)) != -1) { // Linux and macOS
452 name = line.mid(index: index + nameMarkerNix.length()).chopped(len: 1).trimmed();
453 results << name;
454 } else if (line.startsWith(a: nameMarkerWin)) { // Windows formatting
455 name = line.mid(index: line.lastIndexOf(c: " ")).trimmed();
456 } else if (line.startsWith(a: addressMarkerWin)) {
457 QByteArray address = line.mid(index: addressMarkerWin.length()).trimmed();
458 if (address == ip.toUtf8()) {
459 results << name;
460 }
461 }
462 }
463
464 if (results.isEmpty()) {
465 qDebug() << "Failure to parse nslookup output: " << lines;
466 }
467 return results;
468}
469
470void tst_QHostInfo::reverseLookup_data()
471{
472 QTest::addColumn<QString>(name: "address");
473 QTest::addColumn<QStringList>(name: "hostNames");
474 QTest::addColumn<int>(name: "err");
475 QTest::addColumn<bool>(name: "ipv6");
476
477 QTest::newRow(dataTag: "dns.google") << QString("8.8.8.8") << reverseLookupHelper(ip: "8.8.8.8") << 0 << false;
478 QTest::newRow(dataTag: "one.one.one.one") << QString("1.1.1.1") << reverseLookupHelper(ip: "1.1.1.1") << 0 << false;
479 QTest::newRow(dataTag: "dns.google IPv6") << QString("2001:4860:4860::8888") << reverseLookupHelper(ip: "2001:4860:4860::8888") << 0 << true;
480 QTest::newRow(dataTag: "cloudflare IPv6") << QString("2606:4700:4700::1111") << reverseLookupHelper(ip: "2606:4700:4700::1111") << 0 << true;
481 QTest::newRow(dataTag: "bogus-name IPv6") << QString("1::2::3::4") << QStringList() << 1 << true;
482}
483
484void tst_QHostInfo::reverseLookup()
485{
486 QFETCH(QString, address);
487 QFETCH(QStringList, hostNames);
488 QFETCH(int, err);
489 QFETCH(bool, ipv6);
490
491 if (ipv6 && !ipv6LookupsAvailable) {
492 QSKIP("IPv6 reverse lookups are not supported on this platform");
493 }
494
495 QHostInfo info = QHostInfo::fromName(name: address);
496
497 if (err == 0) {
498 if (!hostNames.contains(str: info.hostName()))
499 qDebug() << "Failure: expecting" << hostNames << ",got " << info.hostName();
500 QVERIFY(hostNames.contains(info.hostName()));
501 QCOMPARE(info.addresses().first(), QHostAddress(address));
502 } else {
503 QCOMPARE(info.hostName(), address);
504 QCOMPARE(info.error(), QHostInfo::HostNotFound);
505 }
506
507}
508
509void tst_QHostInfo::blockingLookup_data()
510{
511 lookupIPv4_data();
512 if (ipv6LookupsAvailable)
513 lookupIPv6_data();
514}
515
516void tst_QHostInfo::blockingLookup()
517{
518 QFETCH(QString, hostname);
519 QFETCH(int, err);
520 QFETCH(QString, addresses);
521
522 QHostInfo hostInfo = QHostInfo::fromName(name: hostname);
523 QStringList tmp;
524 for (int i = 0; i < hostInfo.addresses().count(); ++i)
525 tmp.append(t: hostInfo.addresses().at(i).toString());
526 tmp.sort();
527
528 if ((int)hostInfo.error() != (int)err) {
529 qWarning() << hostname << "=>" << lookupResults.errorString();
530 }
531 QCOMPARE((int)hostInfo.error(), (int)err);
532
533 QStringList expected = addresses.split(sep: ' ');
534 expected.sort();
535
536 QCOMPARE(tmp.join(' ').toUpper(), expected.join(' ').toUpper());
537}
538
539void tst_QHostInfo::raceCondition()
540{
541 for (int i = 0; i < 1000; ++i) {
542 QTcpSocket socket;
543 socket.connectToHost(hostName: "invalid" TEST_DOMAIN, port: 80);
544 }
545}
546
547class LookupThread : public QThread
548{
549protected:
550 inline void run()
551 {
552 QHostInfo info = QHostInfo::fromName(name: "a-single" TEST_DOMAIN);
553 QCOMPARE(info.error(), QHostInfo::NoError);
554 QVERIFY(info.addresses().count() > 0);
555 QCOMPARE(info.addresses().at(0).toString(), QString("192.0.2.1"));
556 }
557};
558
559void tst_QHostInfo::threadSafety()
560{
561 const int nattempts = 5;
562 const int runs = 100;
563 LookupThread thr[nattempts];
564 for (int j = 0; j < runs; ++j) {
565 for (int i = 0; i < nattempts; ++i)
566 thr[i].start();
567 for (int k = nattempts - 1; k >= 0; --k)
568 thr[k].wait();
569 }
570}
571
572class LookupReceiver : public QObject
573{
574 Q_OBJECT
575public slots:
576 void start();
577 void resultsReady(const QHostInfo&);
578public:
579 QHostInfo result;
580 int numrequests;
581};
582
583void LookupReceiver::start()
584{
585 for (int i=0;i<numrequests;i++)
586 QHostInfo::lookupHost(name: QString("a-single" TEST_DOMAIN), receiver: this, SLOT(resultsReady(QHostInfo)));
587}
588
589void LookupReceiver::resultsReady(const QHostInfo &info)
590{
591 result = info;
592 numrequests--;
593 if (numrequests == 0 || info.error() != QHostInfo::NoError)
594 QThread::currentThread()->quit();
595}
596
597void tst_QHostInfo::threadSafetyAsynchronousAPI()
598{
599 const int nattempts = 10;
600 const int lookupsperthread = 10;
601 QList<QThread*> threads;
602 QList<LookupReceiver*> receivers;
603 for (int i = 0; i < nattempts; ++i) {
604 QThread* thread = new QThread;
605 LookupReceiver* receiver = new LookupReceiver;
606 receiver->numrequests = lookupsperthread;
607 receivers.append(t: receiver);
608 receiver->moveToThread(thread);
609 connect(sender: thread, SIGNAL(started()), receiver, SLOT(start()));
610 thread->start();
611 threads.append(t: thread);
612 }
613 for (int k = threads.count() - 1; k >= 0; --k)
614 QVERIFY(threads.at(k)->wait(60000));
615 foreach (LookupReceiver* receiver, receivers) {
616 QCOMPARE(receiver->result.error(), QHostInfo::NoError);
617 QCOMPARE(receiver->result.addresses().at(0).toString(), QString("192.0.2.1"));
618 QCOMPARE(receiver->numrequests, 0);
619 }
620}
621
622// this test is for the multi-threaded QHostInfo rewrite. It is about getting results at all,
623// not about getting correct IPs
624void tst_QHostInfo::multipleSameLookups()
625{
626 const int COUNT = 10;
627 lookupsDoneCounter = 0;
628
629 for (int i = 0; i < COUNT; i++)
630 QHostInfo::lookupHost(name: "localhost", receiver: this, SLOT(resultsReady(QHostInfo)));
631
632 QElapsedTimer timer;
633 timer.start();
634 while (timer.elapsed() < 10000 && lookupsDoneCounter < COUNT) {
635 QTestEventLoop::instance().enterLoop(secs: 2);
636 }
637 QCOMPARE(lookupsDoneCounter, COUNT);
638}
639
640// this test is for the multi-threaded QHostInfo rewrite. It is about getting results at all,
641// not about getting correct IPs
642void tst_QHostInfo::multipleDifferentLookups_data()
643{
644 QTest::addColumn<int>(name: "repeats");
645 QTest::newRow(dataTag: "1") << 1;
646 QTest::newRow(dataTag: "2") << 2;
647 QTest::newRow(dataTag: "5") << 5;
648 QTest::newRow(dataTag: "10") << 10;
649}
650
651void tst_QHostInfo::multipleDifferentLookups()
652{
653 QStringList hostnameList;
654 hostnameList << "a-single" TEST_DOMAIN
655 << "a-multi" TEST_DOMAIN
656 << "aaaa-single" TEST_DOMAIN
657 << "aaaa-multi" TEST_DOMAIN
658 << "a-plus-aaaa" TEST_DOMAIN
659 << "multi" TEST_DOMAIN
660 << "localhost" TEST_DOMAIN
661 << "cname" TEST_DOMAIN
662 << "127.0.0.1" << "----";
663
664 QFETCH(int, repeats);
665 const int COUNT = hostnameList.size();
666 lookupsDoneCounter = 0;
667
668 for (int i = 0; i < hostnameList.size(); i++)
669 for (int j = 0; j < repeats; ++j)
670 QHostInfo::lookupHost(name: hostnameList.at(i), receiver: this, SLOT(resultsReady(QHostInfo)));
671
672 QElapsedTimer timer;
673 timer.start();
674 while (timer.elapsed() < 60000 && lookupsDoneCounter < repeats*COUNT) {
675 QTestEventLoop::instance().enterLoop(secs: 2);
676 //qDebug() << "t:" << timer.elapsed();
677 }
678 QCOMPARE(lookupsDoneCounter, repeats*COUNT);
679}
680
681void tst_QHostInfo::cache()
682{
683 QFETCH_GLOBAL(bool, cache);
684 if (!cache)
685 return; // test makes only sense when cache enabled
686
687 // reset slot counter
688 lookupsDoneCounter = 0;
689
690 // lookup once, wait in event loop, result should not come directly.
691 bool valid = true;
692 int id = -1;
693 QHostInfo result = qt_qhostinfo_lookup(name: "localhost", receiver: this, SLOT(resultsReady(QHostInfo)), valid: &valid, id: &id);
694 QTestEventLoop::instance().enterLoop(secs: 5);
695 QVERIFY(!QTestEventLoop::instance().timeout());
696 QVERIFY(!valid);
697 QVERIFY(result.addresses().isEmpty());
698
699 // loopkup second time, result should come directly
700 valid = false;
701 result = qt_qhostinfo_lookup(name: "localhost", receiver: this, SLOT(resultsReady(QHostInfo)), valid: &valid, id: &id);
702 QVERIFY(valid);
703 QVERIFY(!result.addresses().isEmpty());
704
705 // clear the cache
706 qt_qhostinfo_clear_cache();
707
708 // lookup third time, result should not come directly.
709 valid = true;
710 result = qt_qhostinfo_lookup(name: "localhost", receiver: this, SLOT(resultsReady(QHostInfo)), valid: &valid, id: &id);
711 QTestEventLoop::instance().enterLoop(secs: 5);
712 QVERIFY(!QTestEventLoop::instance().timeout());
713 QVERIFY(!valid);
714 QVERIFY(result.addresses().isEmpty());
715
716 // the slot should have been called 2 times.
717 QCOMPARE(lookupsDoneCounter, 2);
718}
719
720void tst_QHostInfo::resultsReady(const QHostInfo &hi)
721{
722 QVERIFY(QThread::currentThread() == thread());
723 lookupDone = true;
724 lookupResults = hi;
725 lookupsDoneCounter++;
726 QTestEventLoop::instance().exitLoop();
727}
728
729void tst_QHostInfo::abortHostLookup()
730{
731 //reset counter
732 lookupsDoneCounter = 0;
733 bool valid = false;
734 int id = -1;
735 QHostInfo result = qt_qhostinfo_lookup(name: "a-single" TEST_DOMAIN, receiver: this, SLOT(resultsReady(QHostInfo)), valid: &valid, id: &id);
736 QVERIFY(!valid);
737 //it is assumed that the DNS request/response in the backend is slower than it takes to call abort
738 QHostInfo::abortHostLookup(lookupId: id);
739 QTestEventLoop::instance().enterLoop(secs: 5);
740 QCOMPARE(lookupsDoneCounter, 0);
741}
742
743class LookupAborter : public QObject
744{
745 Q_OBJECT
746public slots:
747 void abort()
748 {
749 QHostInfo::abortHostLookup(lookupId: id);
750 QThread::currentThread()->quit();
751 }
752public:
753 int id;
754};
755
756QTEST_MAIN(tst_QHostInfo)
757#include "tst_qhostinfo.moc"
758

source code of qtbase/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp