1#!/usr/bin/env python
2# Copyright (C) 2011 Google Inc. All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met:
7#
8#     * Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10#     * Redistributions in binary form must reproduce the above
11# copyright notice, this list of conditions and the following disclaimer
12# in the documentation and/or other materials provided with the
13# distribution.
14#     * Neither the name of Google Inc. nor the names of its
15# contributors may be used to endorse or promote products derived from
16# this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30"""Unit tests for MockDRT."""
31
32import sys
33import unittest
34
35from webkitpy.common import newstringio
36
37from webkitpy.layout_tests.port import mock_drt
38from webkitpy.layout_tests.port import factory
39from webkitpy.layout_tests.port import port_testcase
40from webkitpy.layout_tests.port import test
41
42from webkitpy.tool import mocktool
43mock_options = mocktool.MockOptions(use_apache=True,
44                                    configuration='Release')
45
46
47class MockDRTPortTest(port_testcase.PortTestCase):
48    def make_port(self, options=mock_options):
49        if sys.platform == 'win32':
50            # We use this because the 'win' port doesn't work yet.
51            return mock_drt.MockDRTPort(port_name='mock-chromium-win', options=options)
52        return mock_drt.MockDRTPort(options=options)
53
54    def test_default_worker_model(self):
55        # only overridding the default test; we don't care about this one.
56        pass
57
58    def test_port_name_in_constructor(self):
59        self.assertTrue(mock_drt.MockDRTPort(port_name='mock-test'))
60
61    def test_acquire_http_lock(self):
62        # Only checking that no exception is raised.
63        self.make_port().acquire_http_lock()
64
65    def test_release_http_lock(self):
66        # Only checking that no exception is raised.
67        self.make_port().release_http_lock()
68
69    def test_check_build(self):
70        port = self.make_port()
71        self.assertTrue(port.check_build(True))
72
73    def test_check_sys_deps(self):
74        port = self.make_port()
75        self.assertTrue(port.check_sys_deps(True))
76
77    def test_start_helper(self):
78        # Only checking that no exception is raised.
79        self.make_port().start_helper()
80
81    def test_start_http_server(self):
82        # Only checking that no exception is raised.
83        self.make_port().start_http_server()
84
85    def test_start_websocket_server(self):
86        # Only checking that no exception is raised.
87        self.make_port().start_websocket_server()
88
89    def test_stop_helper(self):
90        # Only checking that no exception is raised.
91        self.make_port().stop_helper()
92
93    def test_stop_http_server(self):
94        # Only checking that no exception is raised.
95        self.make_port().stop_http_server()
96
97    def test_stop_websocket_server(self):
98        # Only checking that no exception is raised.
99        self.make_port().stop_websocket_server()
100
101
102class MockDRTTest(unittest.TestCase):
103    def to_path(self, port, test_name):
104        return port._filesystem.join(port.layout_tests_dir(), test_name)
105
106    def input_line(self, port, test_name, checksum=None):
107        url = port.filename_to_uri(self.to_path(port, test_name))
108        # FIXME: we shouldn't have to work around platform-specific issues
109        # here.
110        if url.startswith('file:////'):
111            url = url[len('file:////') - 1:]
112        if url.startswith('file:///'):
113            url = url[len('file:///') - 1:]
114
115        if checksum:
116            return url + "'" + checksum + '\n'
117        return url + '\n'
118
119    def extra_args(self, pixel_tests):
120        if pixel_tests:
121            return ['--pixel-tests', '-']
122        return ['-']
123
124    def make_drt(self, options, args, filesystem, stdin, stdout, stderr):
125        return mock_drt.MockDRT(options, args, filesystem, stdin, stdout, stderr)
126
127    def make_input_output(self, port, test_name, pixel_tests,
128                          expected_checksum, drt_output, drt_input=None):
129        path = self.to_path(port, test_name)
130        if pixel_tests:
131            if not expected_checksum:
132                expected_checksum = port.expected_checksum(path)
133        if not drt_input:
134            drt_input = self.input_line(port, test_name, expected_checksum)
135        text_output = port.expected_text(path)
136
137        if not drt_output:
138            drt_output = self.expected_output(port, test_name, pixel_tests,
139                                              text_output, expected_checksum)
140        return (drt_input, drt_output)
141
142    def expected_output(self, port, test_name, pixel_tests, text_output, expected_checksum):
143        if pixel_tests and expected_checksum:
144            return ['Content-Type: text/plain\n',
145                    text_output,
146                    '#EOF\n',
147                    '\n',
148                    'ActualHash: %s\n' % expected_checksum,
149                    'ExpectedHash: %s\n' % expected_checksum,
150                    '#EOF\n']
151        else:
152            return ['Content-Type: text/plain\n',
153                    text_output,
154                    '#EOF\n',
155                    '#EOF\n']
156
157    def assertTest(self, test_name, pixel_tests, expected_checksum=None,
158                   drt_output=None, filesystem=None):
159        platform = 'test'
160        filesystem = filesystem or test.unit_test_filesystem()
161        port = factory.get(platform, filesystem=filesystem)
162        drt_input, drt_output = self.make_input_output(port, test_name,
163            pixel_tests, expected_checksum, drt_output)
164
165        args = ['--platform', 'test'] + self.extra_args(pixel_tests)
166        stdin = newstringio.StringIO(drt_input)
167        stdout = newstringio.StringIO()
168        stderr = newstringio.StringIO()
169        options, args = mock_drt.parse_options(args)
170
171        drt = self.make_drt(options, args, filesystem, stdin, stdout, stderr)
172        res = drt.run()
173
174        self.assertEqual(res, 0)
175
176        # We use the StringIO.buflist here instead of getvalue() because
177        # the StringIO might be a mix of unicode/ascii and 8-bit strings.
178        self.assertEqual(stdout.buflist, drt_output)
179        self.assertEqual(stderr.getvalue(), '')
180
181    def test_main(self):
182        filesystem = test.unit_test_filesystem()
183        stdin = newstringio.StringIO()
184        stdout = newstringio.StringIO()
185        stderr = newstringio.StringIO()
186        res = mock_drt.main(['--platform', 'test'] + self.extra_args(False),
187                            filesystem, stdin, stdout, stderr)
188        self.assertEqual(res, 0)
189        self.assertEqual(stdout.getvalue(), '')
190        self.assertEqual(stderr.getvalue(), '')
191        self.assertEqual(filesystem.written_files, {})
192
193    def test_pixeltest_passes(self):
194        # This also tests that we handle HTTP: test URLs properly.
195        self.assertTest('http/tests/passes/text.html', True)
196
197    def test_pixeltest__fails(self):
198        self.assertTest('failures/expected/checksum.html', pixel_tests=True,
199            expected_checksum='wrong-checksum',
200            drt_output=['Content-Type: text/plain\n',
201                        'checksum-txt',
202                        '#EOF\n',
203                        '\n',
204                        'ActualHash: checksum-checksum\n',
205                        'ExpectedHash: wrong-checksum\n',
206                        'Content-Type: image/png\n',
207                        'Content-Length: 13\n',
208                        'checksum\x8a-png',
209                        '#EOF\n'])
210
211    def test_textonly(self):
212        self.assertTest('passes/image.html', False)
213
214    def test_checksum_in_png(self):
215        self.assertTest('passes/checksum_in_image.html', True)
216
217
218class MockChromiumDRTTest(MockDRTTest):
219    def extra_args(self, pixel_tests):
220        if pixel_tests:
221            return ['--pixel-tests=/tmp/png_result0.png']
222        return []
223
224    def make_drt(self, options, args, filesystem, stdin, stdout, stderr):
225        options.chromium = True
226
227        # We have to set these by hand because --platform test won't trigger
228        # the Chromium code paths.
229        options.pixel_path = '/tmp/png_result0.png'
230        options.pixel_tests = True
231
232        return mock_drt.MockChromiumDRT(options, args, filesystem, stdin, stdout, stderr)
233
234    def input_line(self, port, test_name, checksum=None):
235        url = port.filename_to_uri(self.to_path(port, test_name))
236        if checksum:
237            return url + ' 6000 ' + checksum + '\n'
238        return url + ' 6000\n'
239
240    def expected_output(self, port, test_name, pixel_tests, text_output, expected_checksum):
241        url = port.filename_to_uri(self.to_path(port, test_name))
242        if pixel_tests and expected_checksum:
243            return ['#URL:%s\n' % url,
244                    '#MD5:%s\n' % expected_checksum,
245                    text_output,
246                    '\n',
247                    '#EOF\n']
248        else:
249            return ['#URL:%s\n' % url,
250                    text_output,
251                    '\n',
252                    '#EOF\n']
253
254    def test_pixeltest__fails(self):
255        filesystem = test.unit_test_filesystem()
256        self.assertTest('failures/expected/checksum.html', pixel_tests=True,
257            expected_checksum='wrong-checksum',
258            drt_output=['#URL:file:///test.checkout/LayoutTests/failures/expected/checksum.html\n',
259                        '#MD5:checksum-checksum\n',
260                        'checksum-txt',
261                        '\n',
262                        '#EOF\n'],
263            filesystem=filesystem)
264        self.assertEquals(filesystem.written_files,
265            {'/tmp/png_result0.png': 'checksum\x8a-png'})
266
267    def test_chromium_parse_options(self):
268        options, args = mock_drt.parse_options(['--platform', 'chromium-mac',
269            '--pixel-tests=/tmp/png_result0.png'])
270        self.assertTrue(options.chromium)
271        self.assertTrue(options.pixel_tests)
272        self.assertEquals(options.pixel_path, '/tmp/png_result0.png')
273
274
275if __name__ == '__main__':
276    unittest.main()
277