Merge lp:~saviq/unity8/wrap-qmltestrunner into lp:unity8

Proposed by Michał Sawicz on 2014-05-01
Status: Work in progress
Proposed branch: lp:~saviq/unity8/wrap-qmltestrunner
Merge into: lp:unity8
Diff against target: 252 lines (+138/-17)
5 files modified
cmake/modules/QmlTest.cmake (+36/-14)
tests/CMakeLists.txt (+1/-1)
tests/plugins/LightDM/CMakeLists.txt (+0/-2)
tests/qmltests/CMakeLists.txt (+7/-0)
tools/qmltest_wrapper.py (+94/-0)
To merge this branch: bzr merge lp:~saviq/unity8/wrap-qmltestrunner
Reviewer Review Type Date Requested Status
Michael Zanetti 2014-05-01 Pending
Review via email: mp+217972@code.launchpad.net

Commit message

Enable autopkgtest for graphical QML tests.

To post a comment you must log in.
lp:~saviq/unity8/wrap-qmltestrunner updated on 2014-05-01
873. By Michał Sawicz on 2014-05-01

Fix timeout handling.

874. By Michał Sawicz on 2014-05-01

Disable lightdm dbus test for now.

Unmerged revisions

874. By Michał Sawicz on 2014-05-01

Disable lightdm dbus test for now.

873. By Michał Sawicz on 2014-05-01

Fix timeout handling.

872. By Michał Sawicz on 2014-05-01

Make wrapper executable.

871. By Michał Sawicz on 2014-05-01

Refactor how qmltestrunner and qmlscene paths are determined to allow overriding.

870. By Michał Sawicz on 2014-05-01

Introduce qmltest_wrapper.py to record a vido of failed qmltest output.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmake/modules/QmlTest.cmake'
2--- cmake/modules/QmlTest.cmake 2014-04-29 15:17:21 +0000
3+++ cmake/modules/QmlTest.cmake 2014-05-01 21:22:23 +0000
4@@ -19,13 +19,31 @@
5 # qmltest_DEFAULT_IMPORT_PATHS
6 # qmltest_DEFAULT_PROPERTIES
7
8-find_program(qmltestrunner_exe qmltestrunner)
9-
10-if(NOT qmltestrunner_exe)
11- msg(FATAL_ERROR "Could not locate qmltestrunner.")
12-endif()
13-
14-set(qmlscene_exe ${CMAKE_BINARY_DIR}/tests/uqmlscene/uqmlscene)
15+if(NOT TARGET qmltestrunner)
16+ find_program(qmltestrunner_exe qmltestrunner)
17+
18+ if(NOT qmltestrunner_exe)
19+ msg(FATAL_ERROR "Could not locate qmltestrunner.")
20+ endif()
21+
22+ add_executable(qmltestrunner IMPORTED)
23+ set_target_properties(qmltestrunner PROPERTIES IMPORTED_LOCATION ${qmltestrunner_exe})
24+endif()
25+
26+if(NOT TARGET qmlscene)
27+ find_program(qmlscene_exe qmlscene)
28+
29+ if(NOT qmlscene_exe)
30+ msg(FATAL_ERROR "Could not locate qmlscene.")
31+ endif()
32+
33+ add_executable(qmlscene IMPORTED)
34+ set_target_properties(qmlscene PROPERTIES IMPORTED_LOCATION ${qmlscene_exe})
35+endif()
36+
37+if(NOT DEFINED ARTIFACTS_DIR)
38+ set(ARTIFACTS_DIR ${CMAKE_BINARY_DIR})
39+endif()
40
41 macro(add_manual_qml_test SUBPATH COMPONENT_NAME)
42 set(options NO_ADD_TEST NO_TARGETS)
43@@ -33,6 +51,8 @@
44
45 cmake_parse_arguments(qmltest "${options}" "" "${multi_value_keywords}" ${ARGN})
46
47+ get_target_property(qmlscene_executable qmlscene LOCATION)
48+
49 set(qmlscene_TARGET try${COMPONENT_NAME})
50 set(qmltest_FILE ${SUBPATH}/tst_${COMPONENT_NAME})
51
52@@ -51,7 +71,7 @@
53
54 set(qmlscene_command
55 env ${qmltest_ENVIRONMENT}
56- ${qmlscene_exe} ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
57+ ${qmlscene_executable} ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
58 ${qmlscene_imports}
59 )
60 add_custom_target(${qmlscene_TARGET} ${qmlscene_command})
61@@ -76,6 +96,8 @@
62 set(qmltest_xvfb_TARGET xvfbtest${COMPONENT_NAME})
63 set(qmltest_FILE ${SUBPATH}/tst_${COMPONENT_NAME})
64
65+ get_target_property(qmltestrunner_executable qmltestrunner LOCATION)
66+
67 set(qmltestrunner_imports "")
68 if(NOT "${qmltest_IMPORT_PATHS}" STREQUAL "")
69 foreach(IMPORT_PATH ${qmltest_IMPORT_PATHS})
70@@ -104,10 +126,10 @@
71
72 set(qmltest_command
73 env ${qmltest_ENVIRONMENT}
74- ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
75+ ${qmltestrunner_executable} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
76 ${qmltestrunner_imports}
77 ${ITERATIONS_STRING}
78- -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
79+ -o ${ARTIFACTS_DIR}/${qmltest_TARGET}.xml,xunitxml
80 -o -,txt
81 ${function_ARGS}
82 )
83@@ -119,9 +141,9 @@
84 set(qmltest_xvfb_command
85 env ${qmltest_ENVIRONMENT} ${LD_PRELOAD_PATH}
86 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
87- ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
88+ ${qmltestrunner_executable} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
89 ${qmltestrunner_imports}
90- -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
91+ -o ${ARTIFACTS_DIR}/${qmltest_TARGET}.xml,xunitxml
92 -o -,txt
93 ${function_ARGS}
94 )
95@@ -135,7 +157,7 @@
96 set(testCommand
97 LD_LIBRARY_PATH=${LD_PATH}
98 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
99- -o ${CMAKE_BINARY_DIR}/${CLASSNAME}Test.xml,xunitxml
100+ -o ${ARTIFACTS_DIR}/${CLASSNAME}Test.xml,xunitxml
101 -o -,txt)
102
103 add_qmltest_target(test${CLASS_NAME} "${testCommand}" FALSE TRUE)
104@@ -151,7 +173,7 @@
105 LD_LIBRARY_PATH=${LD_PATH}
106 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
107 ${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}TestExec
108- -o ${CMAKE_BINARY_DIR}/${CLASS_NAME}Test.xml,xunitxml
109+ -o ${ARTIFACTS_DIR}/${CLASS_NAME}Test.xml,xunitxml
110 -o -,txt)
111
112 add_qmltest_target(xvfbtest${CLASS_NAME} "${xvfbtestCommand}" FALSE TRUE)
113
114=== modified file 'tests/CMakeLists.txt'
115--- tests/CMakeLists.txt 2014-03-18 12:46:07 +0000
116+++ tests/CMakeLists.txt 2014-05-01 21:22:23 +0000
117@@ -7,9 +7,9 @@
118 add_custom_target(qmltests)
119 add_dependencies(qmltests qmlunittests qmluitests)
120
121+add_subdirectory(uqmlscene)
122 add_subdirectory(qmltests)
123 add_subdirectory(mocks)
124 add_subdirectory(whitespace)
125 add_subdirectory(plugins)
126 add_subdirectory(utils)
127-add_subdirectory(uqmlscene)
128
129=== modified file 'tests/plugins/LightDM/CMakeLists.txt'
130--- tests/plugins/LightDM/CMakeLists.txt 2014-01-14 21:01:28 +0000
131+++ tests/plugins/LightDM/CMakeLists.txt 2014-05-01 21:22:23 +0000
132@@ -21,5 +21,3 @@
133
134 add_custom_target(testLightDMDBus dbus-launch env QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full ${CMAKE_CURRENT_BINARY_DIR}/test-lightdm-dbus)
135 add_dependencies(testLightDMDBus test-lightdm-dbus)
136-
137-add_dependencies(qmluitests testLightDMDBus)
138
139=== modified file 'tests/qmltests/CMakeLists.txt'
140--- tests/qmltests/CMakeLists.txt 2014-04-22 08:51:33 +0000
141+++ tests/qmltests/CMakeLists.txt 2014-05-01 21:22:23 +0000
142@@ -1,3 +1,10 @@
143+add_executable(qmlscene ALIAS uqmlscene)
144+
145+if(DEFINED QMLTESTRUNNER_EXECUTABLE)
146+ add_executable(qmltestrunner IMPORTED)
147+ set_target_properties(qmltestrunner PROPERTIES IMPORTED_LOCATION "${QMLTESTRUNNER_EXECUTABLE}")
148+endif()
149+
150 # add_qml_test macro
151 include(QmlTest)
152
153
154=== added file 'tools/qmltest_wrapper.py'
155--- tools/qmltest_wrapper.py 1970-01-01 00:00:00 +0000
156+++ tools/qmltest_wrapper.py 2014-05-01 21:22:23 +0000
157@@ -0,0 +1,94 @@
158+#!/usr/bin/python3
159+
160+import os
161+import sys
162+import subprocess
163+import shutil
164+import tempfile
165+
166+ENCODE_LIMIT=120
167+GRACE_TIME=5
168+
169+recordmydesktop_args = [
170+ "recordmydesktop",
171+ "--quick-subsampling",
172+ "--fps=60",
173+ "--no-sound",
174+ "--overwrite",
175+]
176+
177+if __name__ == "__main__":
178+ """
179+ This script wraps qmltestrunner, recording the screen as the test runs
180+ with recordmydesktop. Maximum encoding time is {0}s, the process is
181+ interrupted after that time. If the test succeeds, recording is aborted
182+ and no video produced.
183+ Output video file name is derived from the first logger option in the
184+ "-o /file/path,format" format with *absolute* paths, the file is saved
185+ next to the test log file with the extension ".ogv", falling back to
186+ "qmltest.ogv" in the current directory.
187+ """
188+
189+ argv = sys.argv.copy()
190+ argv[0] = "qmltestrunner"
191+
192+ outfile = os.path.join(os.curdir, "qmltest.ogv")
193+ returncode = 0
194+
195+ try:
196+ for logger in (argv[k+1] for k, v in enumerate(argv) if v == "-o"):
197+ log = logger.split(',')[0]
198+ if os.path.isabs(log):
199+ outfile = "{0}.ogv".format(os.path.splitext(log)[0])
200+ break
201+ except IndexError as err:
202+ raise ValueError("Missing logger definition:\n{0}".format(argv)) from err
203+
204+
205+ with tempfile.TemporaryDirectory() as tmpdir:
206+ # create a temporary file and close it to let recordmydesktop overwrite it
207+ tmpfd, tmpname = tempfile.mkstemp(dir=tmpdir, suffix=".ogv")
208+ os.close(tmpfd)
209+ recordmydesktop_args.extend(["--workdir={0}".format(tmpdir),
210+ "--output={0}".format(tmpname)])
211+
212+ with subprocess.Popen(recordmydesktop_args, stdout=subprocess.PIPE,
213+ stderr=subprocess.PIPE, universal_newlines=True) as recorder:
214+ try:
215+ subprocess.check_call(argv)
216+ except subprocess.CalledProcessError as err:
217+ # store the exit code to return
218+ returncode = err.returncode
219+
220+ # stop recording, give 60 seconds to encode
221+ recorder.terminate()
222+ try:
223+ recorder.wait(ENCODE_LIMIT)
224+ except subprocess.TimeoutExpired:
225+ print("===== Recorder took too long to encode, recording will be incomplete =====")
226+ recorder.terminate()
227+ try:
228+ recorder.wait(GRACE_TIME)
229+ except subprocess.TimeoutExpired:
230+ pass
231+ if recorder.returncode is 0:
232+ # only store the file if recorder exited cleanly
233+ shutil.move(tmpname, outfile)
234+ else:
235+ # abort the recording, test passed
236+ recorder.send_signal(subprocess.signal.SIGABRT)
237+ try:
238+ recorder.wait(GRACE_TIME)
239+ except subprocess.TimeoutExpired:
240+ pass
241+ finally:
242+ recorder.poll()
243+ # kill the recording if still running
244+ if recorder.returncode is None:
245+ recorder.kill()
246+ print("===== Had to kill recorder =====")
247+ elif recorder.returncode is not 0:
248+ # only print recorder output if terminated successfully
249+ print("===== Recorder error =====\nSTDOUT:\n{0}\n\nSTDERR:\n{1}".format(*recorder.communicate()))
250+
251+ sys.exit(returncode)
252\ No newline at end of file

Subscribers

People subscribed via source and target branches