| # Copyright 2016 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Feedback query delegate interfaces and implementation registry.""" |
| |
| import multiprocessing |
| |
| import common |
| from autotest_lib.client.common_lib.feedback import client |
| |
| |
| # Mapping of query identifiers to delegate classes. |
| _query_delegate_registry = {} |
| |
| |
| class _QueryDelegate(object): |
| """A base class for query delegates.""" |
| |
| _query_count = multiprocessing.Value('d', 0) |
| |
| def __init__(self, test, dut, multiplexer, atomic=True): |
| """Constructs the delegate. |
| |
| @param test: The name of the test. |
| @param dut: The name of the DUT. |
| @param multiplexer: Feedback request multiplexer object. |
| @param atomic: Whether this is an atomic query. |
| """ |
| super(_QueryDelegate, self).__init__() |
| self.test = test |
| self.dut = dut |
| self._multiplexer = multiplexer |
| self._atomic = atomic |
| |
| # Assign a unique query number. |
| with self._query_count.get_lock(): |
| self._query_num = self._query_count.value |
| self._query_count.value += 1 |
| |
| |
| def _process_request(self, req): |
| """Submits a given request to the multiplexer for processing.""" |
| return self._multiplexer.process_request(req, self._query_num, |
| self._atomic) |
| |
| |
| def prepare(self, **kwargs): |
| """Delegate for a query's prepare() method.""" |
| return self._prepare_impl(**kwargs) |
| |
| |
| def _prepare_impl(self, **kwargs): |
| """Concrete implementation of the query's prepare() call.""" |
| raise NotImplementedError |
| |
| |
| def validate(self, **kwargs): |
| """Delegate for a query's validate() method. |
| |
| This clears the atomic sequence with the multiplexer to make sure it |
| isn't blocked waiting for more requests from this query. |
| """ |
| try: |
| return self._validate_impl(**kwargs) |
| finally: |
| if self._atomic: |
| self._multiplexer.end_atomic_seq(self._query_num) |
| |
| |
| def _validate_impl(self, **kwargs): |
| """Concrete implementation of the query's validate() call.""" |
| raise NotImplementedError |
| |
| |
| class OutputQueryDelegate(_QueryDelegate): |
| """A base class for output query delegates.""" |
| |
| |
| class InputQueryDelegate(_QueryDelegate): |
| """A base class for input query delegates.""" |
| |
| def emit(self): |
| """Delegate for an input query's emit() method.""" |
| return self._emit_impl() |
| |
| |
| def _emit_impl(self): |
| """Concrete implementation of the query's emit() call.""" |
| raise NotImplementedError |
| |
| |
| def register_delegate_cls(query_id, delegate_cls): |
| """Registers a delegate class with a given query identifier. |
| |
| @param query_id: Query identifier constant. |
| @param delegate_cls: The class implementing a delegate for this query. |
| """ |
| _query_delegate_registry[query_id] = delegate_cls |
| |
| |
| def get_delegate_cls(query_id): |
| """Returns a query delegate class for a given query type. |
| |
| @param query_id: A query type identifier. |
| |
| @return A query delegate class. |
| |
| @raise ValueError: Unknown query type. |
| @raise NotImplementedError: Query type not supported. |
| """ |
| if query_id not in client.ALL_QUERIES: |
| raise ValueError |
| if query_id not in _query_delegate_registry: |
| raise NotImplementedError |
| return _query_delegate_registry[query_id] |