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 <QtCore/QSystemSemaphore>
31#include <QtCore/QVector>
32#include <QtCore/QTemporaryDir>
33
34#define EXISTING_SHARE "existing"
35#define HELPERWAITTIME 10000
36
37class tst_QSystemSemaphore : public QObject
38{
39 Q_OBJECT
40
41public:
42 tst_QSystemSemaphore();
43
44public Q_SLOTS:
45 void init();
46 void cleanup();
47
48private slots:
49 void key_data();
50 void key();
51
52 void basicacquire();
53 void complexacquire();
54 void release();
55
56 void basicProcesses();
57
58 void processes_data();
59 void processes();
60
61#if !defined(Q_OS_WIN) && !defined(QT_POSIX_IPC)
62 void undo();
63#endif
64 void initialValue();
65
66private:
67 QSystemSemaphore *existingLock;
68
69 const QString m_helperBinary;
70};
71
72tst_QSystemSemaphore::tst_QSystemSemaphore()
73 :
74#ifdef Q_OS_WIN
75 // On windows the CWD is not the same as the test binary, so we cannot use the ./ path.
76 m_helperBinary("acquirerelease_helper")
77#else
78 // But on Unix we *must*
79 m_helperBinary("./acquirerelease_helper")
80#endif
81{
82}
83
84void tst_QSystemSemaphore::init()
85{
86 existingLock = new QSystemSemaphore(EXISTING_SHARE, 1, QSystemSemaphore::Create);
87}
88
89void tst_QSystemSemaphore::cleanup()
90{
91 delete existingLock;
92}
93
94void tst_QSystemSemaphore::key_data()
95{
96 QTest::addColumn<QString>(name: "constructorKey");
97 QTest::addColumn<QString>(name: "setKey");
98
99 QTest::newRow(dataTag: "null, null") << QString() << QString();
100 QTest::newRow(dataTag: "null, one") << QString() << QString("one");
101 QTest::newRow(dataTag: "one, two") << QString("one") << QString("two");
102}
103
104/*!
105 Basic key testing
106 */
107void tst_QSystemSemaphore::key()
108{
109 QFETCH(QString, constructorKey);
110 QFETCH(QString, setKey);
111
112 QSystemSemaphore sem(constructorKey);
113 QCOMPARE(sem.key(), constructorKey);
114 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
115 QCOMPARE(sem.errorString(), QString());
116
117 sem.setKey(key: setKey);
118 QCOMPARE(sem.key(), setKey);
119 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
120 QCOMPARE(sem.errorString(), QString());
121}
122
123void tst_QSystemSemaphore::basicacquire()
124{
125 QSystemSemaphore sem("QSystemSemaphore_basicacquire", 1, QSystemSemaphore::Create);
126 QVERIFY(sem.acquire());
127 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
128 QVERIFY(sem.release());
129 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
130 QCOMPARE(sem.errorString(), QString());
131}
132
133void tst_QSystemSemaphore::complexacquire()
134{
135 QSystemSemaphore sem("QSystemSemaphore_complexacquire", 2, QSystemSemaphore::Create);
136 QVERIFY(sem.acquire());
137 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
138 QVERIFY(sem.release());
139 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
140 QVERIFY(sem.acquire());
141 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
142 QVERIFY(sem.release());
143 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
144 QVERIFY(sem.acquire());
145 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
146 QVERIFY(sem.acquire());
147 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
148 QVERIFY(sem.release());
149 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
150 QVERIFY(sem.release());
151 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
152 QCOMPARE(sem.errorString(), QString());
153}
154
155void tst_QSystemSemaphore::release()
156{
157 QSystemSemaphore sem("QSystemSemaphore_release", 0, QSystemSemaphore::Create);
158 QVERIFY(sem.release());
159 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
160 QVERIFY(sem.release());
161 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
162 QVERIFY(sem.acquire());
163 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
164 QVERIFY(sem.acquire());
165 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
166 QVERIFY(sem.release());
167 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
168 QVERIFY(sem.release());
169 QCOMPARE(sem.error(), QSystemSemaphore::NoError);
170 QCOMPARE(sem.errorString(), QString());
171}
172
173void tst_QSystemSemaphore::basicProcesses()
174{
175#if !QT_CONFIG(process)
176 QSKIP("No qprocess support", SkipAll);
177#else
178 QSystemSemaphore sem("store", 0, QSystemSemaphore::Create);
179
180 QProcess acquire;
181 acquire.setProcessChannelMode(QProcess::ForwardedChannels);
182
183 QProcess release;
184 release.setProcessChannelMode(QProcess::ForwardedChannels);
185
186 acquire.start(program: m_helperBinary, arguments: QStringList("acquire"));
187 QVERIFY2(acquire.waitForStarted(), "Could not start helper binary");
188 acquire.waitForFinished(HELPERWAITTIME);
189 QCOMPARE(acquire.state(), QProcess::Running);
190 acquire.kill();
191 release.start(program: m_helperBinary, arguments: QStringList("release"));
192 QVERIFY2(release.waitForStarted(), "Could not start helper binary");
193 acquire.waitForFinished(HELPERWAITTIME);
194 release.waitForFinished(HELPERWAITTIME);
195 QCOMPARE(acquire.state(), QProcess::NotRunning);
196#endif
197}
198
199void tst_QSystemSemaphore::processes_data()
200{
201 QTest::addColumn<int>(name: "processes");
202 for (int i = 0; i < 5; ++i) {
203 QTest::newRow(dataTag: "1 process") << 1;
204 QTest::newRow(dataTag: "3 process") << 3;
205 QTest::newRow(dataTag: "10 process") << 10;
206 }
207}
208
209void tst_QSystemSemaphore::processes()
210{
211#if !QT_CONFIG(process)
212 QSKIP("No qprocess support", SkipAll);
213#else
214 QSystemSemaphore sem("store", 1, QSystemSemaphore::Create);
215
216 QFETCH(int, processes);
217 QVector<QString> scripts(processes, "acquirerelease");
218
219 QList<QProcess*> consumers;
220 for (int i = 0; i < scripts.count(); ++i) {
221 QProcess *p = new QProcess;
222 p->setProcessChannelMode(QProcess::ForwardedChannels);
223 consumers.append(t: p);
224 p->start(program: m_helperBinary, arguments: QStringList(scripts.at(i)));
225 }
226
227 while (!consumers.isEmpty()) {
228 consumers.first()->waitForFinished();
229 QCOMPARE(consumers.first()->exitStatus(), QProcess::NormalExit);
230 QCOMPARE(consumers.first()->exitCode(), 0);
231 delete consumers.takeFirst();
232 }
233#endif
234}
235
236// This test only checks a system v unix behavior.
237#if !defined(Q_OS_WIN) && !defined(QT_POSIX_IPC)
238void tst_QSystemSemaphore::undo()
239{
240#if !QT_CONFIG(process)
241 QSKIP("No qprocess support", SkipAll);
242#else
243 QSystemSemaphore sem("store", 1, QSystemSemaphore::Create);
244
245 QStringList acquireArguments = QStringList("acquire");
246 QProcess acquire;
247 acquire.setProcessChannelMode(QProcess::ForwardedChannels);
248 acquire.start(program: m_helperBinary, arguments: acquireArguments);
249 QVERIFY2(acquire.waitForStarted(), "Could not start helper binary");
250 acquire.waitForFinished(HELPERWAITTIME);
251 QVERIFY(acquire.state()== QProcess::NotRunning);
252
253 // At process exit the kernel should auto undo
254
255 acquire.start(program: m_helperBinary, arguments: acquireArguments);
256 QVERIFY2(acquire.waitForStarted(), "Could not start helper binary");
257 acquire.waitForFinished(HELPERWAITTIME);
258 QVERIFY(acquire.state()== QProcess::NotRunning);
259#endif
260}
261#endif
262
263void tst_QSystemSemaphore::initialValue()
264{
265#if !QT_CONFIG(process)
266 QSKIP("No qprocess support", SkipAll);
267#else
268 QSystemSemaphore sem("store", 1, QSystemSemaphore::Create);
269
270 QStringList acquireArguments = QStringList("acquire");
271 QStringList releaseArguments = QStringList("release");
272 QProcess acquire;
273 acquire.setProcessChannelMode(QProcess::ForwardedChannels);
274
275 QProcess release;
276 release.setProcessChannelMode(QProcess::ForwardedChannels);
277
278 acquire.start(program: m_helperBinary, arguments: acquireArguments);
279 QVERIFY2(acquire.waitForStarted(), "Could not start helper binary");
280 acquire.waitForFinished(HELPERWAITTIME);
281 QVERIFY(acquire.state()== QProcess::NotRunning);
282
283 acquire.start(program: m_helperBinary, arguments: acquireArguments << QLatin1String("2"));
284 QVERIFY2(acquire.waitForStarted(), "Could not start helper binary");
285 acquire.waitForFinished(HELPERWAITTIME);
286 QVERIFY(acquire.state()== QProcess::Running);
287 acquire.kill();
288
289 release.start(program: m_helperBinary, arguments: releaseArguments);
290 QVERIFY2(release.waitForStarted(), "Could not start helper binary");
291 acquire.waitForFinished(HELPERWAITTIME);
292 release.waitForFinished(HELPERWAITTIME);
293 QVERIFY(acquire.state()== QProcess::NotRunning);
294#endif
295}
296
297QTEST_MAIN(tst_QSystemSemaphore)
298#include "tst_qsystemsemaphore.moc"
299
300

source code of qtbase/tests/auto/corelib/kernel/qsystemsemaphore/tst_qsystemsemaphore.cpp