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
30#include <QtTest/QtTest>
31#include <qcoreapplication.h>
32#include <qsqldatabase.h>
33#include <qsqlerror.h>
34#include <qsqlquery.h>
35#include <qsqlrecord.h>
36#include <qsqlresult.h>
37#include <qsqldriver.h>
38#include <qdebug.h>
39#include <private/qsqlnulldriver_p.h>
40
41#include "../qsqldatabase/tst_databases.h"
42
43class tst_QSql : public QObject
44{
45 Q_OBJECT
46
47public:
48 tst_QSql();
49 virtual ~tst_QSql();
50
51
52public slots:
53 void initTestCase();
54 void cleanupTestCase();
55 void init();
56 void cleanup();
57private slots:
58 void open();
59 void openInvalid();
60 void registerSqlDriver();
61
62 // problem specific tests
63 void openErrorRecovery();
64 void concurrentAccess();
65 void basicDriverTest();
66};
67
68/****************** General Qt SQL Module tests *****************/
69
70tst_QSql::tst_QSql()
71{
72}
73
74tst_QSql::~tst_QSql()
75{
76}
77
78void tst_QSql::initTestCase()
79{
80}
81
82void tst_QSql::cleanupTestCase()
83{
84}
85
86void tst_QSql::init()
87{
88}
89
90void tst_QSql::cleanup()
91{
92}
93
94// this is a very basic test for drivers that cannot create/delete tables
95// it can be used while developing new drivers,
96// it's original purpose is to test ODBC Text datasources that are basically
97// to stupid to do anything more advanced than SELECT/INSERT/UPDATE/DELETE
98// the datasource has to have a table called "qtest_basictest" consisting
99// of a field "id"(integer) and "name"(char/varchar).
100void tst_QSql::basicDriverTest()
101{
102 int argc = 1;
103 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
104 QCoreApplication app(argc, argv, false);
105 tst_Databases dbs;
106 QVERIFY(dbs.open());
107
108 foreach (const QString& dbName, dbs.dbNames) {
109 QSqlDatabase db = QSqlDatabase::database(connectionName: dbName);
110 QVERIFY_SQL(db, isValid());
111
112 QStringList tables = db.tables();
113 QString tableName;
114
115 if (tables.contains(str: "qtest_basictest.txt"))
116 tableName = "qtest_basictest.txt";
117 else if (tables.contains(str: "qtest_basictest"))
118 tableName = "qtest_basictest";
119 else if (tables.contains(str: "QTEST_BASICTEST"))
120 tableName = "QTEST_BASICTEST";
121 else {
122 QVERIFY(1);
123 continue;
124 }
125
126 qDebug(msg: "Testing: %s", qPrintable(tst_Databases::dbToString(db)));
127
128 QSqlRecord rInf = db.record(tablename: tableName);
129 QCOMPARE(rInf.count(), 2);
130 QCOMPARE(rInf.fieldName(0).toLower(), QString("id"));
131 QCOMPARE(rInf.fieldName(1).toLower(), QString("name"));
132 }
133
134 dbs.close();
135 QVERIFY(1); // make sure the test doesn't fail if no database drivers are there
136}
137
138// make sure that the static stuff will be deleted
139// when using multiple QCoreApplication objects
140void tst_QSql::open()
141{
142 int i;
143 int argc = 1;
144 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
145 int count = -1;
146 for (i = 0; i < 10; ++i) {
147 QCoreApplication app(argc, argv, false);
148 tst_Databases dbs;
149
150 QVERIFY(dbs.open());
151 if (count == -1)
152 // first iteration: see how many dbs are open
153 count = (int) dbs.dbNames.count();
154 else
155 // next iterations: make sure all are opened again
156 QCOMPARE(count, (int)dbs.dbNames.count());
157 dbs.close();
158 }
159}
160
161void tst_QSql::openInvalid()
162{
163 QSqlDatabase db;
164 QVERIFY(!db.open());
165
166 QSqlDatabase db2 = QSqlDatabase::addDatabase(type: "doesnt_exist_will_never_exist", connectionName: "blah");
167 QFAIL_SQL(db2, open());
168}
169
170void tst_QSql::concurrentAccess()
171{
172 int argc = 1;
173 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
174 QCoreApplication app(argc, argv, false);
175 tst_Databases dbs;
176
177 QVERIFY(dbs.open());
178 foreach (const QString& dbName, dbs.dbNames) {
179 QSqlDatabase db = QSqlDatabase::database(connectionName: dbName);
180 QVERIFY(db.isValid());
181 if (tst_Databases::isMSAccess(db))
182 continue;
183
184 QSqlDatabase ndb = QSqlDatabase::addDatabase(type: db.driverName(), connectionName: "tst_QSql::concurrentAccess");
185 ndb.setDatabaseName(db.databaseName());
186 ndb.setHostName(db.hostName());
187 ndb.setPort(db.port());
188 ndb.setUserName(db.userName());
189 ndb.setPassword(db.password());
190 QVERIFY_SQL(ndb, open());
191
192 QCOMPARE(db.tables(), ndb.tables());
193 ndb.close();
194 }
195 // no database servers installed - don't fail
196 QVERIFY(1);
197 dbs.close();
198}
199
200void tst_QSql::openErrorRecovery()
201{
202 int argc = 1;
203 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
204 QCoreApplication app(argc, argv, false);
205 tst_Databases dbs;
206
207 QVERIFY(dbs.addDbs());
208 if (dbs.dbNames.isEmpty())
209 QSKIP("No database drivers installed");
210 foreach (const QString& dbName, dbs.dbNames) {
211 QSqlDatabase db = QSqlDatabase::database(connectionName: dbName, open: false);
212 CHECK_DATABASE(db);
213
214 QString userName = db.userName();
215 QString password = db.password();
216
217 // force an open error
218 if (db.open(user: "dummy130977", password: "doesnt_exist")) {
219 qDebug(msg: "Promiscuous database server without access control - test skipped for %s",
220 qPrintable(tst_Databases::dbToString(db)));
221 QVERIFY(1);
222 continue;
223 }
224
225 QFAIL_SQL(db, isOpen());
226 QVERIFY_SQL(db, isOpenError());
227
228 // now open it
229 if (!db.open(user: userName, password)) {
230 qDebug() << "Could not open Database " << tst_Databases::dbToString(db) <<
231 ". Assuming DB is down, skipping... (Error: " <<
232 tst_Databases::printError(err: db.lastError()) << ")";
233 continue;
234 }
235 QVERIFY_SQL(db, open(userName, password));
236 QVERIFY_SQL(db, isOpen());
237 QFAIL_SQL(db, isOpenError());
238 db.close();
239 QFAIL_SQL(db, isOpen());
240
241 // force another open error
242 QFAIL_SQL(db, open("dummy130977", "doesnt_exist"));
243 QFAIL_SQL(db, isOpen());
244 QVERIFY_SQL(db, isOpenError());
245 }
246}
247
248void tst_QSql::registerSqlDriver()
249{
250 int argc = 1;
251 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
252 QCoreApplication app(argc, argv, false);
253
254 QSqlDatabase::registerSqlDriver(name: "QSQLTESTDRIVER", creator: new QSqlDriverCreator<QSqlNullDriver>);
255 QVERIFY(QSqlDatabase::drivers().contains("QSQLTESTDRIVER"));
256
257 QSqlDatabase db = QSqlDatabase::addDatabase(type: "QSQLTESTDRIVER");
258 QVERIFY(db.isValid());
259
260 QCOMPARE(db.tables(), QStringList());
261}
262
263QTEST_APPLESS_MAIN(tst_QSql)
264#include "tst_qsql.moc"
265

source code of qtbase/tests/auto/sql/kernel/qsql/tst_qsql.cpp