iOS 12 Simulator Release WK2 frequently timing out while running layout tests
[WebKit-https.git] / Tools / Scripts / webkitpy / port / server_process_unittest.py
1 # Copyright (C) 2011 Google Inc. All rights reserved.
2 # Copyright (C) 2011-2019 Apple 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 import sys
31 import time
32 import unittest
33
34 from webkitpy.port.factory import PortFactory
35 from webkitpy.port import server_process
36 from webkitpy.common.system.systemhost import SystemHost
37 from webkitpy.common.system.systemhost_mock import MockSystemHost
38 from webkitpy.common.system.outputcapture import OutputCapture
39
40
41 class TrivialMockPort(object):
42     def __init__(self):
43         self.host = MockSystemHost()
44         self.host.executive.kill_process = lambda x: None
45         self.host.executive.kill_process = lambda x: None
46
47     def results_directory(self):
48         return "/mock-results"
49
50     def check_for_leaks(self, process_name, process_id):
51         pass
52
53     def process_kill_time(self):
54         return 1
55
56
57 class MockFile(object):
58     def __init__(self, server_process):
59         self._server_process = server_process
60         self.closed = False
61
62     def fileno(self):
63         return 1
64
65     def write(self, line):
66         self._server_process.broken_pipes.append(self)
67         raise IOError
68
69     def read(self, size=0):
70         # This means end of file
71         return ''
72
73     def close(self):
74         self.closed = True
75
76
77 class MockProc(object):
78     def __init__(self, server_process):
79         self.stdin = MockFile(server_process)
80         self.stdout = MockFile(server_process)
81         self.stderr = MockFile(server_process)
82         self.pid = 1
83
84     def poll(self):
85         return 1
86
87     def wait(self):
88         return 0
89
90
91 class FakeServerProcess(server_process.ServerProcess):
92     def _start(self):
93         self._proc = MockProc(self)
94         self.stdin = self._proc.stdin
95         self.stdout = self._proc.stdout
96         self.stderr = self._proc.stderr
97         self._pid = self._proc.pid
98         self.broken_pipes = []
99
100
101 class TestServerProcess(unittest.TestCase):
102     def serial_test_basic(self):
103         # Give -u switch to force stdout and stderr to be unbuffered for Windows
104         cmd = [sys.executable, '-uc', 'import sys; print "stdout"; print "again"; print >>sys.stderr, "stderr"; sys.stdin.readline();']
105         host = SystemHost()
106         factory = PortFactory(host)
107         port = factory.get()
108         now = time.time()
109         proc = server_process.ServerProcess(port, 'python', cmd)
110         proc.write('')
111
112         self.assertEqual(proc.poll(), None)
113         self.assertFalse(proc.has_crashed())
114
115         # check that doing a read after an expired deadline returns
116         # nothing immediately.
117         line = proc.read_stdout_line(now - 1)
118         self.assertEqual(line, None)
119
120         line = proc.read_stdout_line(now + 1.0)
121         self.assertEqual(line.strip(), "stdout")
122
123         self.assertTrue(proc.has_available_stdout())
124
125         line = proc.read_stderr_line(now + 1.0)
126         self.assertEqual(line.strip(), "stderr")
127
128         line = proc.read_stdout_line(now + 1.0)
129         self.assertEqual(line.strip(), "again")
130         self.assertFalse(proc.has_available_stdout())
131
132         proc.write('End\n')
133         time.sleep(0.1)  # Give process a moment to close.
134         self.assertEqual(proc.poll(), 0)
135
136         proc.stop(0)
137
138     def serial_test_read_after_process_exits(self):
139         cmd = [sys.executable, '-c', 'import sys; print "stdout"; print >>sys.stderr, "stderr";']
140         host = SystemHost()
141         factory = PortFactory(host)
142         port = factory.get()
143         now = time.time()
144         proc = server_process.ServerProcess(port, 'python', cmd)
145         proc.write('')
146         time.sleep(0.1)  # Give process a moment to close.
147
148         line = proc.read_stdout_line(now + 1.0)
149         self.assertEqual(line.strip(), "stdout")
150
151         line = proc.read_stderr_line(now + 1.0)
152         self.assertEqual(line.strip(), "stderr")
153
154         proc.stop(0)
155
156     def serial_test_process_crashing(self):
157         # Give -u switch to force stdout to be unbuffered for Windows
158         cmd = [sys.executable, '-uc', 'import sys; print "stdout 1"; print "stdout 2"; print "stdout 3"; sys.stdin.readline(); sys.exit(1);']
159         host = SystemHost()
160         factory = PortFactory(host)
161         port = factory.get()
162         now = time.time()
163         proc = server_process.ServerProcess(port, 'python', cmd)
164         proc.write('')
165
166         line = proc.read_stdout_line(now + 1.0)
167         self.assertEqual(line.strip(), 'stdout 1')
168
169         proc.write('End\n')
170         time.sleep(0.1)  # Give process a moment to close.
171
172         line = proc.read_stdout_line(now + 1.0)
173         self.assertEqual(line.strip(), 'stdout 2')
174
175         self.assertEqual(True, proc.has_crashed())
176
177         line = proc.read_stdout_line(now + 1.0)
178         self.assertEqual(line, None)
179
180         proc.stop(0)
181
182     def serial_test_process_crashing_no_data(self):
183         cmd = [sys.executable, '-c',
184                'import sys; sys.stdin.readline(); sys.exit(1);']
185         host = SystemHost()
186         factory = PortFactory(host)
187         port = factory.get()
188         now = time.time()
189         proc = server_process.ServerProcess(port, 'python', cmd)
190         proc.write('')
191
192         self.assertEqual(False, proc.has_crashed())
193
194         proc.write('End\n')
195         time.sleep(0.1)  # Give process a moment to close.
196
197         line = proc.read_stdout_line(now + 1.0)
198         self.assertEqual(line, None)
199
200         self.assertEqual(True, proc.has_crashed())
201
202         proc.stop(0)
203
204     def test_cleanup(self):
205         port_obj = TrivialMockPort()
206         server_process = FakeServerProcess(port_obj=port_obj, name="test", cmd=["test"])
207         server_process._start()
208         server_process.stop()
209         self.assertTrue(server_process.stdin.closed)
210         self.assertTrue(server_process.stdout.closed)
211         self.assertTrue(server_process.stderr.closed)
212
213     def test_broken_pipe(self):
214         port_obj = TrivialMockPort()
215
216         port_obj.host.platform.os_name = 'win'
217         server_process = FakeServerProcess(port_obj=port_obj, name="test", cmd=["test"])
218         server_process.write("should break")
219         self.assertTrue(server_process.has_crashed())
220         self.assertIsNotNone(server_process.pid())
221         self.assertIsNone(server_process._proc)
222         self.assertEqual(server_process.broken_pipes, [server_process.stdin])
223
224         port_obj.host.platform.os_name = 'mac'
225         server_process = FakeServerProcess(port_obj=port_obj, name="test", cmd=["test"])
226         server_process.write("should break")
227         self.assertTrue(server_process.has_crashed())
228         self.assertIsNone(server_process._proc)
229         self.assertEqual(server_process.broken_pipes, [server_process.stdin])