2018-01-05 13:34:17 +00:00
|
|
|
# Copyright 2018 the V8 project authors. All rights reserved.
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
|
|
|
|
|
2018-01-09 13:56:18 +00:00
|
|
|
"""
|
|
|
|
Pipeline
|
|
|
|
|
|
|
|
Test processors are chained together and communicate with each other by
|
|
|
|
calling previous/next processor in the chain.
|
|
|
|
----next_test()----> ----next_test()---->
|
|
|
|
Proc1 Proc2 Proc3
|
|
|
|
<---result_for()---- <---result_for()----
|
|
|
|
|
2018-01-15 08:03:48 +00:00
|
|
|
For every next_test there is exactly one result_for call.
|
|
|
|
If processor ignores the test it has to return SkippedResult.
|
|
|
|
If it created multiple subtests for one test and wants to pass all of them to
|
|
|
|
the previous processor it can enclose them in GroupedResult.
|
|
|
|
|
|
|
|
|
2018-01-09 13:56:18 +00:00
|
|
|
Subtests
|
|
|
|
|
|
|
|
When test processor needs to modify the test or create some variants of the
|
|
|
|
test it creates subtests and sends them to the next processor.
|
|
|
|
Each subtest has:
|
|
|
|
- procid - globally unique id that should contain id of the parent test and
|
|
|
|
some suffix given by test processor, e.g. its name + subtest type.
|
|
|
|
- processor - which created it
|
|
|
|
- origin - pointer to the parent (sub)test
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
2018-01-17 10:59:24 +00:00
|
|
|
DROP_RESULT = 0
|
|
|
|
DROP_OUTPUT = 1
|
|
|
|
DROP_PASS_OUTPUT = 2
|
|
|
|
DROP_PASS_STDOUT = 3
|
|
|
|
|
|
|
|
|
2018-01-05 13:34:17 +00:00
|
|
|
class TestProc(object):
|
|
|
|
def __init__(self):
|
|
|
|
self._prev_proc = None
|
|
|
|
self._next_proc = None
|
2018-01-24 18:25:45 +00:00
|
|
|
self._stopped = False
|
2018-01-17 10:59:24 +00:00
|
|
|
self._requirement = DROP_RESULT
|
2018-01-05 13:34:17 +00:00
|
|
|
|
|
|
|
def connect_to(self, next_proc):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""Puts `next_proc` after itself in the chain."""
|
2018-01-05 13:34:17 +00:00
|
|
|
next_proc._prev_proc = self
|
|
|
|
self._next_proc = next_proc
|
|
|
|
def next_test(self, test):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""
|
|
|
|
Method called by previous processor whenever it produces new test.
|
|
|
|
This method shouldn't be called by anyone except previous processor.
|
2019-01-30 12:20:17 +00:00
|
|
|
Returns a boolean value to signal whether the test was loaded into the
|
|
|
|
execution queue successfully or not.
|
2018-01-09 13:56:18 +00:00
|
|
|
"""
|
2018-01-05 13:34:17 +00:00
|
|
|
raise NotImplementedError()
|
|
|
|
|
2018-01-15 08:03:48 +00:00
|
|
|
def result_for(self, test, result):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""
|
|
|
|
Method called by next processor whenever it has result for some test.
|
|
|
|
This method shouldn't be called by anyone except next processor.
|
|
|
|
"""
|
2018-01-05 13:34:17 +00:00
|
|
|
raise NotImplementedError()
|
|
|
|
|
2018-01-08 12:38:00 +00:00
|
|
|
def heartbeat(self):
|
|
|
|
if self._prev_proc:
|
|
|
|
self._prev_proc.heartbeat()
|
|
|
|
|
2018-01-24 18:25:45 +00:00
|
|
|
def stop(self):
|
2018-01-31 10:21:44 +00:00
|
|
|
if not self._stopped:
|
|
|
|
self._stopped = True
|
|
|
|
if self._prev_proc:
|
|
|
|
self._prev_proc.stop()
|
|
|
|
if self._next_proc:
|
|
|
|
self._next_proc.stop()
|
2018-01-24 18:25:45 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def is_stopped(self):
|
|
|
|
return self._stopped
|
|
|
|
|
2018-01-05 13:34:17 +00:00
|
|
|
### Communication
|
2018-01-15 08:03:48 +00:00
|
|
|
|
2019-08-05 10:58:34 +00:00
|
|
|
def notify_previous(self, event):
|
|
|
|
self._on_event(event)
|
|
|
|
if self._prev_proc:
|
|
|
|
self._prev_proc.notify_previous(event)
|
|
|
|
|
|
|
|
def _on_event(self, event):
|
|
|
|
"""Called when processors to the right signal events, e.g. termination.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
event: A text describing the signalled event.
|
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
2018-01-05 13:34:17 +00:00
|
|
|
def _send_test(self, test):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""Helper method for sending test to the next processor."""
|
2019-01-30 12:20:17 +00:00
|
|
|
return self._next_proc.next_test(test)
|
2018-01-05 13:34:17 +00:00
|
|
|
|
2018-01-15 08:03:48 +00:00
|
|
|
def _send_result(self, test, result):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""Helper method for sending result to the previous processor."""
|
2018-01-15 08:03:48 +00:00
|
|
|
self._prev_proc.result_for(test, result)
|
2022-07-21 12:52:19 +00:00
|
|
|
|
2018-01-05 13:34:17 +00:00
|
|
|
class TestProcObserver(TestProc):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""Processor used for observing the data."""
|
2018-01-17 10:59:24 +00:00
|
|
|
def __init__(self):
|
|
|
|
super(TestProcObserver, self).__init__()
|
2018-01-09 13:56:18 +00:00
|
|
|
|
2018-01-05 13:34:17 +00:00
|
|
|
def next_test(self, test):
|
|
|
|
self._on_next_test(test)
|
2019-01-30 12:20:17 +00:00
|
|
|
return self._send_test(test)
|
2018-01-05 13:34:17 +00:00
|
|
|
|
2018-01-15 08:03:48 +00:00
|
|
|
def result_for(self, test, result):
|
|
|
|
self._on_result_for(test, result)
|
|
|
|
self._send_result(test, result)
|
2018-01-05 13:34:17 +00:00
|
|
|
|
2018-01-08 12:38:00 +00:00
|
|
|
def heartbeat(self):
|
|
|
|
self._on_heartbeat()
|
|
|
|
super(TestProcObserver, self).heartbeat()
|
|
|
|
|
2018-01-05 13:34:17 +00:00
|
|
|
def _on_next_test(self, test):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""Method called after receiving test from previous processor but before
|
|
|
|
sending it to the next one."""
|
2018-01-05 13:34:17 +00:00
|
|
|
pass
|
|
|
|
|
2018-01-15 08:03:48 +00:00
|
|
|
def _on_result_for(self, test, result):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""Method called after receiving result from next processor but before
|
|
|
|
sending it to the previous one."""
|
2018-01-05 13:34:17 +00:00
|
|
|
pass
|
|
|
|
|
2018-01-08 12:38:00 +00:00
|
|
|
def _on_heartbeat(self):
|
|
|
|
pass
|
|
|
|
|
2018-01-05 13:34:17 +00:00
|
|
|
|
|
|
|
class TestProcProducer(TestProc):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""Processor for creating subtests."""
|
|
|
|
|
2018-01-05 13:34:17 +00:00
|
|
|
def __init__(self, name):
|
|
|
|
super(TestProcProducer, self).__init__()
|
2022-12-07 09:26:21 +00:00
|
|
|
self.name = name
|
2018-01-05 13:34:17 +00:00
|
|
|
|
|
|
|
def next_test(self, test):
|
2019-01-30 12:20:17 +00:00
|
|
|
return self._next_test(test)
|
2018-01-05 13:34:17 +00:00
|
|
|
|
2018-01-15 08:03:48 +00:00
|
|
|
def result_for(self, subtest, result):
|
|
|
|
self._result_for(subtest.origin, subtest, result)
|
2018-01-05 13:34:17 +00:00
|
|
|
|
|
|
|
### Implementation
|
|
|
|
def _next_test(self, test):
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2018-01-15 08:03:48 +00:00
|
|
|
def _result_for(self, test, subtest, result):
|
2018-01-09 13:56:18 +00:00
|
|
|
"""
|
|
|
|
result_for method extended with `subtest` parameter.
|
|
|
|
|
|
|
|
Args
|
|
|
|
test: test used by current processor to create the subtest.
|
|
|
|
subtest: test for which the `result` is.
|
2018-01-15 08:03:48 +00:00
|
|
|
result: subtest execution result created by the output processor.
|
2018-01-09 13:56:18 +00:00
|
|
|
"""
|
2018-01-05 13:34:17 +00:00
|
|
|
raise NotImplementedError()
|
|
|
|
|
2022-12-07 09:26:21 +00:00
|
|
|
def test_suffix(self, test):
|
|
|
|
"""Default implementation of rdb test id suffix generated by a producer"""
|
2022-12-08 13:44:48 +00:00
|
|
|
return None
|
2018-01-05 13:34:17 +00:00
|
|
|
|
2018-01-09 17:52:34 +00:00
|
|
|
|
|
|
|
class TestProcFilter(TestProc):
|
|
|
|
"""Processor for filtering tests."""
|
|
|
|
|
|
|
|
def next_test(self, test):
|
2018-01-15 08:03:48 +00:00
|
|
|
if self._filter(test):
|
2019-01-30 12:20:17 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
return self._send_test(test)
|
2018-01-09 17:52:34 +00:00
|
|
|
|
2018-01-15 08:03:48 +00:00
|
|
|
def result_for(self, test, result):
|
|
|
|
self._send_result(test, result)
|
2018-01-09 17:52:34 +00:00
|
|
|
|
|
|
|
def _filter(self, test):
|
|
|
|
"""Returns whether test should be filtered out."""
|
|
|
|
raise NotImplementedError()
|