qtcreator.py 10.2 KB
Newer Older
1
2
3
4
import platform;
import shutil;
import os;
import glob;
5
import atexit;
6
import codecs;
7
import subprocess;
8
import sys
9
10
import errno;
from datetime import datetime,timedelta;
11

12
srcPath = ''
13
SettingsPath = ''
14
tmpSettingsDir = ''
15
testSettings.logScreenshotOnFail = True
16
testSettings.logScreenshotOnError = True
17
__origStartApplication__ = None
18

19
source("../../shared/classes.py")
20
source("../../shared/utils.py")
21
source("../../shared/fs_utils.py")
22
source("../../shared/build_utils.py")
23
source("../../shared/project.py")
24
source("../../shared/editor_utils.py")
25
26
source("../../shared/project_explorer.py")
source("../../shared/hook_utils.py")
27
source("../../shared/debugger.py")
28
source("../../shared/workarounds.py")
29

30
31
32
33
34
35
36
37
# ATTENTION: if a test case calls startApplication("qtcreator...") for several times this
# function must be called BEFORE any call except the first (which is done always automatically)
def overrideStartApplication():
    global startApplication, __origStartApplication__
    if (platform.system() != "Darwin"):
        return
    if (__origStartApplication__ == None):
        __origStartApplication__ = startApplication
Christian Stenger's avatar
Christian Stenger committed
38
39
40
41
    def startApplication(*args):
        args = list(args)
        if str(args[0]).startswith('qtcreator'):
            args[0] = args[0].replace('qtcreator', '"Qt Creator"', 1)
42
43
            test.log("Using workaround for MacOS (different AUT name)")
        return __origStartApplication__(*args)
Christian Stenger's avatar
Christian Stenger committed
44

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
def startedWithoutPluginError():
    try:
        loaderErrorWidgetName = ("{name='ExtensionSystem__Internal__PluginErrorOverview' "
                                 "type='ExtensionSystem::PluginErrorOverview' visible='1' "
                                 "windowTitle='Qt Creator - Plugin loader messages'}")
        loaderError = waitForObject(loaderErrorWidgetName, 1000)
        test.fatal("Could not perform clean start of Qt Creator - Plugin error occurred.",
                   waitForObject("{name='pluginError' type='QTextEdit' visible='1' window=%s}"
                                 % loaderErrorWidgetName, 1000).plainText)
        clickButton("{text~='(Next.*|Continue)' type='QPushButton' visible='1'}")
        invokeMenuItem("File", "Exit")
        return False
    except:
        return True

60
def waitForCleanShutdown(timeOut=10):
61
    appCtxt = currentApplicationContext()
62
    shutdownDone = (str(appCtxt)=="")
63
    if platform.system() in ('Windows','Microsoft'):
64
65
        # cleaning helper for running on the build machines
        __checkForQmlViewer__()
66
67
68
        endtime = datetime.utcnow() + timedelta(seconds=timeOut)
        while not shutdownDone:
            # following work-around because os.kill() works for win not until python 2.7
69
70
            if appCtxt.pid==-1:
                break
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
            tasks = subprocess.Popen("tasklist /FI \"PID eq %d\"" % appCtxt.pid, shell=True,stdout=subprocess.PIPE)
            output = tasks.communicate()[0]
            tasks.stdout.close()
            if (output=="INFO: No tasks are running which match the specified criteria."
                or output=="" or output.find("ERROR")==0):
                shutdownDone=True
            if not shutdownDone and datetime.utcnow() > endtime:
                break
    else:
        endtime = datetime.utcnow() + timedelta(seconds=timeOut)
        while not shutdownDone:
            try:
                os.kill(appCtxt.pid,0)
            except OSError, err:
                if err.errno == errno.EPERM or err.errno == errno.ESRCH:
                    shutdownDone=True
            if not shutdownDone and datetime.utcnow() > endtime:
                break

90
91
92
93
94
95
96
97
98
99
100
101
102
def __checkForQmlViewer__():
    tasks = subprocess.Popen("tasklist /FI \"IMAGENAME eq qmlviewer.exe\"", shell=True,
                             stdout=subprocess.PIPE)
    output = tasks.communicate()[0]
    tasks.stdout.close()
    if "INFO: No tasks are running which match the specified criteria." in output:
        return
    else:
        if subprocess.call("taskkill /F /FI \"IMAGENAME eq qmlviewer.exe\"", shell=True) == 0:
            print "Killed still running qmlviewer"
        else:
            print "qmlviewer is still running - failed to kill it"

103
104
105
106
107
108
109
def __removeTestingDir__():
    def __removeIt__(directory):
        deleteDirIfExists(directory)
        return not os.path.exists(directory)

    devicesXML = os.path.join(tmpSettingsDir, "QtProject", "qtcreator", "devices.xml")
    lastMTime = os.path.getmtime(devicesXML)
110
    testingDir = os.path.dirname(tmpSettingsDir)
111
    waitForCleanShutdown()
112
113
    waitFor('os.path.getmtime(devicesXML) > lastMTime', 5000)
    waitFor('__removeIt__(testingDir)', 2000)
114

Robert Loehning's avatar
Robert Loehning committed
115
116
117
118
119
def __substitute__(fileName, search, replace):
    origFileName = fileName + "_orig"
    os.rename(fileName, origFileName)
    origFile = open(origFileName, "r")
    modifiedFile = open(fileName, "w")
120
    for line in origFile:
Robert Loehning's avatar
Robert Loehning committed
121
        modifiedFile.write(line.replace(search, replace))
122
123
    origFile.close()
    modifiedFile.close()
Robert Loehning's avatar
Robert Loehning committed
124
125
126
127
128
129
    os.remove(origFileName)

def substituteTildeWithinToolchains(settingsDir):
    toolchains = os.path.join(settingsDir, "QtProject", 'qtcreator', 'toolchains.xml')
    home = os.path.expanduser("~")
    __substitute__(toolchains, "~", home)
130
131
    test.log("Substituted all tildes with '%s' inside toolchains.xml..." % home)

Robert Loehning's avatar
Robert Loehning committed
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def substituteDefaultCompiler(settingsDir):
    compiler = None
    if platform.system() == 'Darwin':
        compiler = "clang_64"
    elif platform.system() == 'Linux':
        if __is64BitOS__():
            compiler = "gcc_64"
        else:
            compiler = "gcc"
    else:
        test.warning("Called substituteDefaultCompiler() on wrong platform.",
                     "This is a script error.")
    if compiler:
        qtversion = os.path.join(settingsDir, "QtProject", 'qtcreator', 'qtversion.xml')
        __substitute__(qtversion, "SQUISH_DEFAULT_COMPILER", compiler)
        test.log("Injected default compiler '%s' to qtversion.xml..." % compiler)

149
def __guessABI__(supportedABIs, use64Bit):
150
151
152
153
    if platform.system() == 'Linux':
        supportedABIs = filter(lambda x: 'linux' in x, supportedABIs)
    elif platform.system() == 'Darwin':
        supportedABIs = filter(lambda x: 'macos' in x, supportedABIs)
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
180
181
182
183
184
    if use64Bit:
        searchFor = "64bit"
    else:
        searchFor = "32bit"
    for abi in supportedABIs:
        if searchFor in abi:
            return abi
    if use64Bit:
        test.log("Supported ABIs do not include an ABI supporting 64bit - trying 32bit now")
        return __guessABI__(supportedABIs, False)
    test.fatal('Could not guess ABI!',
               'Given ABIs: %s' % str(supportedABIs))
    return ''

def __is64BitOS__():
    if platform.system() in ('Microsoft', 'Windows'):
        machine = os.getenv("PROCESSOR_ARCHITEW6432", os.getenv("PROCESSOR_ARCHITECTURE"))
    else:
        machine = platform.machine()
    if machine:
        return '64' in machine
    else:
        return False

def substituteUnchosenTargetABIs(settingsDir):
    class ReadState:
        NONE = 0
        READING = 1
        CLOSED = 2

    on64Bit = __is64BitOS__()
185
    toolchains = os.path.join(settingsDir, "QtProject", 'qtcreator', 'toolchains.xml')
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
    origToolchains = toolchains + "_orig"
    os.rename(toolchains, origToolchains)
    origFile = open(origToolchains, "r")
    modifiedFile = open(toolchains, "w")
    supported = []
    readState = ReadState.NONE
    for line in origFile:
        if readState == ReadState.NONE:
            if "SupportedAbis" in line:
                supported = []
                readState = ReadState.READING
        elif readState == ReadState.READING:
            if "</valuelist>" in line:
                readState = ReadState.CLOSED
            else:
                supported.append(line.split(">", 1)[1].rsplit("<", 1)[0])
        elif readState == ReadState.CLOSED:
            if "SupportedAbis" in line:
                supported = []
                readState = ReadState.READING
            elif "SET_BY_SQUISH" in line:
                line = line.replace("SET_BY_SQUISH", __guessABI__(supported, on64Bit))
        modifiedFile.write(line)
    origFile.close()
    modifiedFile.close()
    os.remove(origToolchains)
    test.log("Substituted unchosen ABIs inside toolchains.xml...")

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
def copySettingsToTmpDir(destination=None, omitFiles=[]):
    global tmpSettingsDir, SettingsPath, origSettingsDir
    if destination:
        destination = os.path.abspath(destination)
        if not os.path.exists(destination):
            os.makedirs(destination)
        elif os.path.isfile(destination):
                test.warning("Provided destination for settings exists as file.",
                             "Creating another folder for being able to execute tests.")
                destination = tempDir()
    else:
        destination = tempDir()
    tmpSettingsDir = destination
    pathLen = len(origSettingsDir) + 1
    for r,d,f in os.walk(origSettingsDir):
        currentPath = os.path.join(tmpSettingsDir, r[pathLen:])
        for dd in d:
            folder = os.path.join(currentPath, dd)
            if not os.path.exists(folder):
                os.makedirs(folder)
        for ff in f:
            if not ff in omitFiles:
                shutil.copy(os.path.join(r, ff), currentPath)
237
238
    if platform.system() in ('Linux', 'Darwin'):
        substituteTildeWithinToolchains(tmpSettingsDir)
Robert Loehning's avatar
Robert Loehning committed
239
        substituteDefaultCompiler(tmpSettingsDir)
240
241
242
    substituteUnchosenTargetABIs(tmpSettingsDir)
    SettingsPath = ' -settingspath "%s"' % tmpSettingsDir

243
244
245
# current dir is directory holding qtcreator.py
origSettingsDir = os.path.abspath(os.path.join(os.getcwd(), "..", "..", "settings"))

246
if platform.system() in ('Windows', 'Microsoft'):
247
    sdkPath = "C:\\QtSDK"
248
    origSettingsDir = os.path.join(origSettingsDir, "windows")
249
    defaultQtVersion = "Qt 4.7.4 for Desktop - MinGW 4.4 (Qt SDK)"
250
else:
251
    sdkPath = os.path.expanduser("~/QtSDK")
252
    origSettingsDir = os.path.join(origSettingsDir, "unix")
253
    defaultQtVersion = "Desktop Qt 4.7.4 for GCC (Qt SDK)"
254
srcPath = os.getenv("SYSTEST_SRCPATH", sdkPath + "/src")
255

256
257
overrideStartApplication()

258
# the following only doesn't work if the test ends in an exception
259
if os.getenv("SYSTEST_NOSETTINGSPATH") != "1":
260
    copySettingsToTmpDir()
261
    atexit.register(__removeTestingDir__)
262
263
264

if os.getenv("SYSTEST_WRITE_RESULTS") == "1" and os.getenv("SYSTEST_RESULTS_FOLDER") != None:
    atexit.register(writeTestResults, os.getenv("SYSTEST_RESULTS_FOLDER"))