-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
test_qgsappstartup.py
179 lines (148 loc) · 5.87 KB
/
test_qgsappstartup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
"""QGIS Unit tests for QgsApplication.
From build dir: ctest -R PyQgsAppStartup -V
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Hugo Mercier (hugo.mercier@oslandia.com)'
__date__ = '17/07/2013'
__copyright__ = 'Copyright 2013, The QGIS Project'
import errno
import glob
import os
import re
import shutil
import subprocess
import sys
import tempfile
import time
from qgis.testing import unittest
from utilities import unitTestDataPath
print('CTEST_FULL_OUTPUT')
TEST_DATA_DIR = unitTestDataPath()
class TestPyQgsAppStartup(unittest.TestCase):
TMP_DIR = ''
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.TMP_DIR = tempfile.mkdtemp()
# print('TMP_DIR: ' + cls.TMP_DIR)
# subprocess.call(['open', cls.TMP_DIR])
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls.TMP_DIR, ignore_errors=True)
super().tearDownClass()
# TODO: refactor parameters to **kwargs to handle all startup combinations
def doTestStartup(self, option='', testDir='', testFile='',
loadPlugins=False, customization=False,
timeOut=360, env=None, additionalArguments=[]):
"""Run QGIS with the given option. Wait for testFile to be created.
If time runs out, fail.
"""
myTestFile = testFile
# from unicode to local
if testDir:
if not os.path.exists(testDir):
os.mkdir(testDir)
myTestFile = os.path.join(testDir, testFile)
if os.path.exists(myTestFile):
os.remove(myTestFile)
# whether to load plugins
plugins = '' if loadPlugins else '--noplugins'
# whether to enable GUI customization
customize = '' if customization else '--nocustomization'
# environment variables = system variables + provided 'env'
myenv = os.environ.copy()
if env is not None:
myenv.update(env)
call = [QGIS_BIN, "--nologo", plugins, customize, option, testDir] + additionalArguments
p = subprocess.Popen(call, env=myenv)
s = 0
while not os.path.exists(myTestFile):
p.poll()
if p.returncode is not None:
raise Exception(f"Return code: {p.returncode}, Call: \"{' '.join(call)}\", Env: {env}")
time.sleep(1)
s += 1
if s > timeOut:
raise Exception(f"Timed out waiting for application start, Call: \"{' '.join(call)}\", Env: {env}")
with open(myTestFile, encoding='utf-8') as res_file:
lines = res_file.readlines()
try:
p.terminate()
except OSError as e:
if e.errno != errno.ESRCH:
raise e
return lines
def testPyQgisStartupEnvVar(self):
# verify PYQGIS_STARTUP env variable file is run by embedded interpreter
# create a temp python module that writes out test file
testfile = 'pyqgis_startup.txt'
testfilepath = os.path.join(self.TMP_DIR, testfile).replace('\\', '/')
testcode = [
f"from qgis.core import QgsApplication\nf = open('{testfilepath}', 'w')\n",
"f.write('Platform: ' + QgsApplication.platform())\n",
"f.close()\n"
]
testmod = os.path.join(self.TMP_DIR, 'pyqgis_startup.py').replace('\\', '/')
f = open(testmod, 'w')
f.writelines(testcode)
f.close()
testfile_lines = self.doTestStartup(
testFile=testfilepath,
timeOut=360,
env={'PYQGIS_STARTUP': testmod})
# platform should be "Desktop"
self.assertEqual(testfile_lines, ['Platform: desktop'])
def testPyArgs(self):
testfile = 'pyqgis_code.txt'
testfilepath = os.path.join(self.TMP_DIR, testfile).replace('\\', '/')
testcode = [
f"import sys\nf = open('{testfilepath}', 'a')\n",
"for arg in sys.argv:\n"
" f.write(arg)\n",
" f.write('\\n')\n",
"f.close()\n"
]
testmod = os.path.join(self.TMP_DIR, 'pyqgis_code.py').replace('\\', '/')
f = open(testmod, 'w')
f.writelines(testcode)
f.close()
testfile_lines = self.doTestStartup(
testFile=testfilepath,
timeOut=10,
additionalArguments=["--code", testmod, "--py-args", "--specialScriptArgument's", 'a "Quoted" text arg', "--"])
self.assertEqual(testfile_lines, [testmod + '\n',
"--specialScriptArgument's\n",
'a "Quoted" text arg\n'])
if __name__ == '__main__':
# look for qgis bin path
QGIS_BIN = ''
prefixPath = os.environ['QGIS_PREFIX_PATH']
# see qgsapplication.cpp:98
for f in ['', '..', 'bin']:
d = os.path.join(prefixPath, f)
b = os.path.abspath(os.path.join(d, 'qgis'))
if os.path.exists(b):
QGIS_BIN = b
break
b = os.path.abspath(os.path.join(d, 'qgis.exe'))
if os.path.exists(b):
QGIS_BIN = b
break
if sys.platform[:3] == 'dar': # Mac
# QGIS.app may be QGIS_x.x-dev.app for nightlies
# internal binary will match, minus the '.app'
found = False
for app_path in glob.glob(d + '/QGIS*.app'):
m = re.search(r'/(QGIS(_\d\.\d-dev)?)\.app', app_path)
if m:
QGIS_BIN = app_path + '/Contents/MacOS/' + m.group(1)
found = True
break
if found:
break
print(f'\nQGIS_BIN: {QGIS_BIN}')
assert QGIS_BIN, 'QGIS binary not found, skipping test suite'
unittest.main()