REGRESSION(r263625): [WPE][GTK] MiniBrowser output no longer includes stderr and...
[WebKit-https.git] / Tools / Scripts / webkitpy / port / gtk.py
1 # Copyright (C) 2010 Google Inc. All rights reserved.
2 # Copyright (C) 2013 Samsung Electronics.  All rights reserved.
3 # Copyright (C) 2017 Igalia S.L. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met:
8 #
9 #     * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 #     * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
14 # distribution.
15 #     * Neither the Google name nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 import os
32 import subprocess
33 import uuid
34 import logging
35
36 from webkitpy.common.system import path
37 from webkitpy.common.memoized import memoized
38 from webkitpy.layout_tests.models.test_configuration import TestConfiguration
39 from webkitpy.port.base import Port
40 from webkitpy.port.pulseaudio_sanitizer import PulseAudioSanitizer
41 from webkitpy.port.xvfbdriver import XvfbDriver
42 from webkitpy.port.westondriver import WestonDriver
43 from webkitpy.port.xorgdriver import XorgDriver
44 from webkitpy.port.waylanddriver import WaylandDriver
45 from webkitpy.port.linux_get_crash_log import GDBCrashLogGenerator
46 from webkitpy.port.leakdetector_valgrind import LeakDetectorValgrind
47
48 _log = logging.getLogger(__name__)
49
50
51 class GtkPort(Port):
52     port_name = "gtk"
53
54     def __init__(self, *args, **kwargs):
55         super(GtkPort, self).__init__(*args, **kwargs)
56         self._pulseaudio_sanitizer = PulseAudioSanitizer()
57         self._display_server = self.get_option("display_server")
58
59         if self.get_option("leaks"):
60             self._leakdetector = LeakDetectorValgrind(self._executive, self._filesystem, self.results_directory())
61             if not self.get_option("wrapper"):
62                 raise ValueError('use --wrapper=\"valgrind\" for memory leak detection on GTK')
63
64         if self._should_use_jhbuild():
65             self._jhbuild_wrapper = [self.path_from_webkit_base('Tools', 'jhbuild', 'jhbuild-wrapper'), '--gtk', 'run']
66             if self.get_option('wrapper'):
67                 self.set_option('wrapper', ' '.join(self._jhbuild_wrapper) + ' ' + self.get_option('wrapper'))
68             else:
69                 self.set_option_default('wrapper', ' '.join(self._jhbuild_wrapper))
70
71     def _built_executables_path(self, *path):
72         return self._build_path(*(('bin',) + path))
73
74     def _built_libraries_path(self, *path):
75         return self._build_path(*(('lib',) + path))
76
77     def _port_flag_for_scripts(self):
78         return "--gtk"
79
80     @memoized
81     def _driver_class(self):
82         if self._display_server == "weston":
83             return WestonDriver
84         if self._display_server == "wayland":
85             return WaylandDriver
86         if self._display_server == "xorg":
87             return XorgDriver
88         return XvfbDriver
89
90     def default_timeout_ms(self):
91         default_timeout = 15000
92         # Starting an application under Valgrind takes a lot longer than normal
93         # so increase the timeout (empirically 10x is enough to avoid timeouts).
94         multiplier = 10 if self.get_option("leaks") else 1
95         # Debug builds are slower (no compiler optimizations are used).
96         if self.get_option('configuration') == 'Debug':
97             multiplier *= 2
98         return multiplier * default_timeout
99
100     def driver_stop_timeout(self):
101         if self.get_option("leaks"):
102             # Wait the default timeout time before killing the process in driver.stop().
103             return self.default_timeout_ms()
104         return super(GtkPort, self).driver_stop_timeout()
105
106     def setup_test_run(self, device_type=None):
107         super(GtkPort, self).setup_test_run(device_type)
108         self._pulseaudio_sanitizer.unload_pulseaudio_module()
109
110         if self.get_option("leaks"):
111             self._leakdetector.clean_leaks_files_from_results_directory()
112
113     def clean_up_test_run(self):
114         super(GtkPort, self).clean_up_test_run()
115         self._pulseaudio_sanitizer.restore_pulseaudio_module()
116
117     def setup_environ_for_server(self, server_name=None):
118         environment = super(GtkPort, self).setup_environ_for_server(server_name)
119         environment['G_DEBUG'] = 'fatal-criticals'
120         environment['GSETTINGS_BACKEND'] = 'memory'
121         environment['LIBOVERLAY_SCROLLBAR'] = '0'
122         environment['TEST_RUNNER_INJECTED_BUNDLE_FILENAME'] = self._build_path('lib', 'libTestRunnerInjectedBundle.so')
123         environment['TEST_RUNNER_TEST_PLUGIN_PATH'] = self._build_path('lib', 'plugins')
124         self._copy_value_from_environ_if_set(environment, 'WEBKIT_OUTPUTDIR')
125         self._copy_value_from_environ_if_set(environment, 'WEBKIT_JHBUILD')
126         self._copy_value_from_environ_if_set(environment, 'WEBKIT_TOP_LEVEL')
127         self._copy_value_from_environ_if_set(environment, 'WEBKIT_DEBUG')
128         self._copy_value_from_environ_if_set(environment, 'WEBKIT_GST_USE_PLAYBIN3')
129         for gst_variable in ('DEBUG', 'DEBUG_DUMP_DOT_DIR', 'DEBUG_FILE', 'DEBUG_NO_COLOR',
130                              'PLUGIN_SCANNER', 'PLUGIN_PATH', 'PLUGIN_SYSTEM_PATH', 'REGISTRY',
131                              'PLUGIN_PATH_1_0'):
132             self._copy_value_from_environ_if_set(environment, 'GST_%s' % gst_variable)
133
134         # Configure the software libgl renderer if jhbuild ready and we test inside a virtualized window system
135         if self._driver_class() in [XvfbDriver, WestonDriver] and (self._should_use_jhbuild() or self._is_flatpak()):
136             if self._should_use_jhbuild():
137                 llvmpipe_libgl_path = self.host.executive.run_command(self._jhbuild_wrapper + ['printenv', 'LLVMPIPE_LIBGL_PATH'],
138                                                                     ignore_errors=True).strip()
139                 dri_libgl_path = os.path.join(llvmpipe_libgl_path, "dri")
140             else:  # in flatpak
141                 llvmpipe_libgl_path = "/usr/lib/x86_64-linux-gnu/"
142                 dri_libgl_path = os.path.join(llvmpipe_libgl_path, "GL", "lib", "dri")
143
144             if os.path.exists(os.path.join(llvmpipe_libgl_path, "libGL.so")) and os.path.exists(os.path.join(dri_libgl_path, "swrast_dri.so")):
145                 # Make sure va-api support gets disabled because it's incompatible with Mesa's softGL driver.
146                 environment['LIBVA_DRIVER_NAME'] = "null"
147                 # Force the Gallium llvmpipe software rasterizer
148                 environment['LIBGL_ALWAYS_SOFTWARE'] = "1"
149                 environment['LIBGL_DRIVERS_PATH'] = dri_libgl_path
150             else:
151                 _log.warning("Can't find Gallium llvmpipe driver. Try to run update-webkitgtk-libs or update-webkit-flatpak")
152         if self.get_option("leaks"):
153             # Turn off GLib memory optimisations https://wiki.gnome.org/Valgrind.
154             environment['G_SLICE'] = 'always-malloc'
155             environment['G_DEBUG'] += ',gc-friendly'
156             # Turn off bmalloc when running under Valgrind, see https://bugs.webkit.org/show_bug.cgi?id=177745
157             environment['Malloc'] = '1'
158             xmlfilename = "".join(("drt-%p-", uuid.uuid1().hex, "-leaks.xml"))
159             xmlfile = os.path.join(self.results_directory(), xmlfilename)
160             suppressionsfile = self.path_from_webkit_base('Tools', 'Scripts', 'valgrind', 'suppressions.txt')
161             environment['VALGRIND_OPTS'] = \
162                 "--tool=memcheck " \
163                 "--num-callers=40 " \
164                 "--demangle=no " \
165                 "--trace-children=no " \
166                 "--smc-check=all-non-file " \
167                 "--leak-check=yes " \
168                 "--leak-resolution=high " \
169                 "--show-possibly-lost=no " \
170                 "--show-reachable=no " \
171                 "--leak-check=full " \
172                 "--undef-value-errors=no " \
173                 "--gen-suppressions=all " \
174                 "--xml=yes " \
175                 "--xml-file=%s " \
176                 "--suppressions=%s" % (xmlfile, suppressionsfile)
177         return environment
178
179     def _generate_all_test_configurations(self):
180         configurations = []
181         for build_type in self.ALL_BUILD_TYPES:
182             configurations.append(TestConfiguration(version=self.version_name(), architecture='x86', build_type=build_type))
183         return configurations
184
185     def _path_to_driver(self):
186         return self._built_executables_path(self.driver_name())
187
188     def _path_to_image_diff(self):
189         return self._built_executables_path('ImageDiff')
190
191     def _path_to_default_image_diff(self):
192         return self._path_to_image_diff()
193
194     def _path_to_webcore_library(self):
195         gtk_library_names = [
196             "libwebkitgtk-1.0.so",
197             "libwebkitgtk-3.0.so",
198             "libwebkit2gtk-1.0.so",
199         ]
200
201         for library in gtk_library_names:
202             full_library = self._built_libraries_path(library)
203             if self._filesystem.isfile(full_library):
204                 return full_library
205         return None
206
207     def _search_paths(self):
208         search_paths = []
209         if self._driver_class() in [WaylandDriver, WestonDriver]:
210             search_paths.append(self.port_name + "-wayland")
211         search_paths.append(self.port_name)
212         search_paths.append('glib')
213         search_paths.append('wk2')
214         search_paths.extend(self.get_option("additional_platform_directory", []))
215         return search_paths
216
217     def default_baseline_search_path(self, **kwargs):
218         return list(map(self._webkit_baseline_path, self._search_paths()))
219
220     def _port_specific_expectations_files(self, **kwargs):
221         return [self._filesystem.join(self._webkit_baseline_path(p), 'TestExpectations') for p in reversed(self._search_paths())]
222
223     def print_leaks_summary(self):
224         if not self.get_option('leaks'):
225             return
226         # FIXME: This is a hack, but we don't have a better way to get this information from the workers yet
227         # because we're in the manager process.
228         leaks_files = self._leakdetector.leaks_files_in_results_directory()
229         if not leaks_files:
230             return
231         self._leakdetector.parse_and_print_leaks_detail(leaks_files)
232
233     def show_results_html_file(self, results_filename):
234         self.run_minibrowser([path.abspath_to_uri(self.host.platform, results_filename)])
235
236     def check_sys_deps(self):
237         return super(GtkPort, self).check_sys_deps() and self._driver_class().check_driver(self)
238
239     def _get_crash_log(self, name, pid, stdout, stderr, newer_than, target_host=None):
240         return GDBCrashLogGenerator(self._executive, name, pid, newer_than,
241                                     self._filesystem, self._path_to_driver, self.port_name, self.get_option('configuration')).generate_crash_log(stdout, stderr)
242
243     def test_expectations_file_position(self):
244         # GTK port baseline search path is gtk -> glib -> wk2 -> generic (as gtk-wk2 and gtk baselines are merged), so port test expectations file is at third to last position.
245         return 3
246
247     def build_webkit_command(self, build_style=None):
248         command = super(GtkPort, self).build_webkit_command(build_style)
249         command.extend(["--gtk", "--update-gtk"])
250         command.append(super(GtkPort, self).make_args())
251         return command
252
253     def run_webkit_tests_command(self):
254         command = super(GtkPort, self).run_webkit_tests_command()
255         command.append("--gtk")
256         return command
257
258     def configuration_for_upload(self, host=None):
259         configuration = super(GtkPort, self).configuration_for_upload(host=host)
260         configuration['platform'] = 'GTK'
261         configuration['version_name'] = self._display_server.capitalize() if self._display_server else 'Xvfb'
262         return configuration
263
264     def run_minibrowser(self, args):
265         miniBrowser = self._build_path('bin', 'MiniBrowser')
266         if not self._filesystem.isfile(miniBrowser):
267             print("%s not found... Did you run build-webkit?" % miniBrowser)
268             return 1
269         command = [miniBrowser]
270         if self._should_use_jhbuild():
271             command = self._jhbuild_wrapper + command
272         return self._executive.run_command(command + args, cwd=self.webkit_base(), stdout=None, return_stderr=False, decode_output=False)