lms.testing.serverrunner

  1import logging
  2import typing
  3
  4import edq.net.exchange
  5import edq.net.request
  6import edq.testing.serverrunner
  7import edq.util.parse
  8import edq.util.reflection
  9
 10import lms.backend.instance
 11import lms.cli.parser
 12import lms.model.constants
 13import lms.util.net
 14
 15BACKEND_REQUEST_CLEANING_FUNCS: typing.Dict[typing.Union[str, None], typing.Callable] = {
 16    lms.model.constants.BACKEND_TYPE_BLACKBOARD: lms.util.net.clean_blackboard_response,
 17    lms.model.constants.BACKEND_TYPE_CANVAS: lms.util.net.clean_canvas_response,
 18    lms.model.constants.BACKEND_TYPE_MOODLE: lms.util.net.clean_moodle_response,
 19}
 20
 21BACKEND_EXCHANGE_FINALIZING_FUNCS: typing.Dict[typing.Union[str, None], typing.Callable] = {
 22    lms.model.constants.BACKEND_TYPE_MOODLE: lms.util.net.finalize_moodle_exchange,
 23}
 24
 25class LMSServerRunner(edq.testing.serverrunner.ServerRunner):
 26    """ A server runner specifically for LMS servers. """
 27
 28    def __init__(self,
 29            backend_type: typing.Union[str, None] = None,
 30            **kwargs: typing.Any) -> None:
 31        super().__init__(**kwargs)
 32
 33        self.backend_type: typing.Union[str, None] = backend_type
 34        """
 35        The type of server being run.
 36        This value will be resolved after the server is started
 37        (since part of resolution may involve pinging the server.
 38        """
 39
 40        self._old_exchanges_clean_func: typing.Union[str, None] = None
 41        """
 42        The value of edq.net.exchange._exchanges_clean_func when start() is called.
 43        The original value may be changed in start(), and will be reset in stop().
 44        """
 45
 46        self._old_exchanges_finalize_func: typing.Union[str, None] = None
 47        """
 48        The value of edq.net.exchange._exchanges_finalize_func when start() is called.
 49        The original value may be changed in start(), and will be reset in stop().
 50        """
 51
 52        self._old_set_exchanges_clean_func: bool = False
 53        """
 54        The value of lms.cli.parser._set_exchanges_clean_func when start() is called.
 55        The original value may be changed in start(), and will be reset in stop().
 56        """
 57
 58        self._old_make_request_exchange_complete_func: typing.Union[edq.net.exchange.HTTPExchangeComplete, None] = None
 59        """
 60        The value of edq.net.request._make_request_exchange_complete_func when start() is called.
 61        The original value may be changed in start(), and will be reset in stop().
 62        """
 63
 64        self._old_serverrunner_logging_level: typing.Union[int, None] = None
 65        """
 66        The logging level for the edq server runner befoe tests are run.
 67        The original value may be changed in start(), and will be reset in stop().
 68        """
 69
 70    def start(self) -> None:
 71        # Set configs.
 72
 73        exchange_clean_func = BACKEND_REQUEST_CLEANING_FUNCS.get(self.backend_type, lms.util.net.clean_lms_response)
 74        exchange_clean_func_name = edq.util.reflection.get_qualified_name(exchange_clean_func)
 75        self._old_exchanges_clean_func = edq.net.exchange._exchanges_clean_func
 76        edq.net.exchange._exchanges_clean_func = exchange_clean_func_name
 77
 78        self._old_exchanges_finalize_func = edq.net.exchange._exchanges_finalize_func
 79        exchange_finalize_func = BACKEND_EXCHANGE_FINALIZING_FUNCS.get(self.backend_type, None)
 80        if (exchange_finalize_func is not None):
 81            exchange_finalize_func_name = edq.util.reflection.get_qualified_name(exchange_finalize_func)
 82            edq.net.exchange._exchanges_finalize_func = exchange_finalize_func_name
 83        else:
 84            edq.net.exchange._exchanges_finalize_func = None
 85
 86        self._old_set_exchanges_clean_func = lms.cli.parser._set_exchanges_clean_func
 87        lms.cli.parser._set_exchanges_clean_func = False
 88
 89        def _make_request_callback(exchange: edq.net.exchange.HTTPExchange) -> None:
 90            # Restart if the request is a write.
 91            if (edq.util.parse.boolean(exchange.headers.get(lms.model.constants.HEADER_KEY_WRITE, False))):
 92                self.restart()
 93
 94        self._old_make_request_exchange_complete_func = edq.net.request._make_request_exchange_complete_func
 95        edq.net.request._make_request_exchange_complete_func = typing.cast(edq.net.exchange.HTTPExchangeComplete, _make_request_callback)
 96
 97        # Disable logging from the runner, since it may disrupt CLI tests.
 98        logger = logging.getLogger('edq.testing.serverrunner')
 99        self._old_serverrunner_logging_level = logger.level
100        logger.setLevel(logging.WARNING)
101
102        # Start the server.
103        super().start()
104
105    def stop(self) -> bool:
106        if (self._old_serverrunner_logging_level is not None):
107            logger = logging.getLogger('edq.testing.serverrunner')
108            logger.setLevel(self._old_serverrunner_logging_level)
109            self._old_serverrunner_logging_level = None
110
111        if (not super().stop()):
112            return False
113
114        # Restore old configs.
115
116        edq.net.exchange._exchanges_clean_func = self._old_exchanges_clean_func
117        self._old_exchanges_clean_func = None
118
119        lms.cli.parser._set_exchanges_clean_func = self._old_set_exchanges_clean_func
120        self._old_set_exchanges_clean_func = False
121
122        edq.net.request._make_request_exchange_complete_func = self._old_make_request_exchange_complete_func
123        self._old_make_request_exchange_complete_func = None
124
125        return True
126
127    def identify_server(self) ->  bool:
128        backend_type = lms.backend.instance.guess_backend_type_from_request(self.server, timeout_secs = self.identify_wait_secs)
129        return (backend_type is not None)
BACKEND_REQUEST_CLEANING_FUNCS: Dict[Optional[str], Callable] = {'blackboard': <function clean_blackboard_response>, 'canvas': <function clean_canvas_response>, 'moodle': <function clean_moodle_response>}
BACKEND_EXCHANGE_FINALIZING_FUNCS: Dict[Optional[str], Callable] = {'moodle': <function finalize_moodle_exchange>}
class LMSServerRunner(edq.testing.serverrunner.ServerRunner):
 26class LMSServerRunner(edq.testing.serverrunner.ServerRunner):
 27    """ A server runner specifically for LMS servers. """
 28
 29    def __init__(self,
 30            backend_type: typing.Union[str, None] = None,
 31            **kwargs: typing.Any) -> None:
 32        super().__init__(**kwargs)
 33
 34        self.backend_type: typing.Union[str, None] = backend_type
 35        """
 36        The type of server being run.
 37        This value will be resolved after the server is started
 38        (since part of resolution may involve pinging the server.
 39        """
 40
 41        self._old_exchanges_clean_func: typing.Union[str, None] = None
 42        """
 43        The value of edq.net.exchange._exchanges_clean_func when start() is called.
 44        The original value may be changed in start(), and will be reset in stop().
 45        """
 46
 47        self._old_exchanges_finalize_func: typing.Union[str, None] = None
 48        """
 49        The value of edq.net.exchange._exchanges_finalize_func when start() is called.
 50        The original value may be changed in start(), and will be reset in stop().
 51        """
 52
 53        self._old_set_exchanges_clean_func: bool = False
 54        """
 55        The value of lms.cli.parser._set_exchanges_clean_func when start() is called.
 56        The original value may be changed in start(), and will be reset in stop().
 57        """
 58
 59        self._old_make_request_exchange_complete_func: typing.Union[edq.net.exchange.HTTPExchangeComplete, None] = None
 60        """
 61        The value of edq.net.request._make_request_exchange_complete_func when start() is called.
 62        The original value may be changed in start(), and will be reset in stop().
 63        """
 64
 65        self._old_serverrunner_logging_level: typing.Union[int, None] = None
 66        """
 67        The logging level for the edq server runner befoe tests are run.
 68        The original value may be changed in start(), and will be reset in stop().
 69        """
 70
 71    def start(self) -> None:
 72        # Set configs.
 73
 74        exchange_clean_func = BACKEND_REQUEST_CLEANING_FUNCS.get(self.backend_type, lms.util.net.clean_lms_response)
 75        exchange_clean_func_name = edq.util.reflection.get_qualified_name(exchange_clean_func)
 76        self._old_exchanges_clean_func = edq.net.exchange._exchanges_clean_func
 77        edq.net.exchange._exchanges_clean_func = exchange_clean_func_name
 78
 79        self._old_exchanges_finalize_func = edq.net.exchange._exchanges_finalize_func
 80        exchange_finalize_func = BACKEND_EXCHANGE_FINALIZING_FUNCS.get(self.backend_type, None)
 81        if (exchange_finalize_func is not None):
 82            exchange_finalize_func_name = edq.util.reflection.get_qualified_name(exchange_finalize_func)
 83            edq.net.exchange._exchanges_finalize_func = exchange_finalize_func_name
 84        else:
 85            edq.net.exchange._exchanges_finalize_func = None
 86
 87        self._old_set_exchanges_clean_func = lms.cli.parser._set_exchanges_clean_func
 88        lms.cli.parser._set_exchanges_clean_func = False
 89
 90        def _make_request_callback(exchange: edq.net.exchange.HTTPExchange) -> None:
 91            # Restart if the request is a write.
 92            if (edq.util.parse.boolean(exchange.headers.get(lms.model.constants.HEADER_KEY_WRITE, False))):
 93                self.restart()
 94
 95        self._old_make_request_exchange_complete_func = edq.net.request._make_request_exchange_complete_func
 96        edq.net.request._make_request_exchange_complete_func = typing.cast(edq.net.exchange.HTTPExchangeComplete, _make_request_callback)
 97
 98        # Disable logging from the runner, since it may disrupt CLI tests.
 99        logger = logging.getLogger('edq.testing.serverrunner')
100        self._old_serverrunner_logging_level = logger.level
101        logger.setLevel(logging.WARNING)
102
103        # Start the server.
104        super().start()
105
106    def stop(self) -> bool:
107        if (self._old_serverrunner_logging_level is not None):
108            logger = logging.getLogger('edq.testing.serverrunner')
109            logger.setLevel(self._old_serverrunner_logging_level)
110            self._old_serverrunner_logging_level = None
111
112        if (not super().stop()):
113            return False
114
115        # Restore old configs.
116
117        edq.net.exchange._exchanges_clean_func = self._old_exchanges_clean_func
118        self._old_exchanges_clean_func = None
119
120        lms.cli.parser._set_exchanges_clean_func = self._old_set_exchanges_clean_func
121        self._old_set_exchanges_clean_func = False
122
123        edq.net.request._make_request_exchange_complete_func = self._old_make_request_exchange_complete_func
124        self._old_make_request_exchange_complete_func = None
125
126        return True
127
128    def identify_server(self) ->  bool:
129        backend_type = lms.backend.instance.guess_backend_type_from_request(self.server, timeout_secs = self.identify_wait_secs)
130        return (backend_type is not None)

A server runner specifically for LMS servers.

LMSServerRunner(backend_type: Optional[str] = None, **kwargs: Any)
29    def __init__(self,
30            backend_type: typing.Union[str, None] = None,
31            **kwargs: typing.Any) -> None:
32        super().__init__(**kwargs)
33
34        self.backend_type: typing.Union[str, None] = backend_type
35        """
36        The type of server being run.
37        This value will be resolved after the server is started
38        (since part of resolution may involve pinging the server.
39        """
40
41        self._old_exchanges_clean_func: typing.Union[str, None] = None
42        """
43        The value of edq.net.exchange._exchanges_clean_func when start() is called.
44        The original value may be changed in start(), and will be reset in stop().
45        """
46
47        self._old_exchanges_finalize_func: typing.Union[str, None] = None
48        """
49        The value of edq.net.exchange._exchanges_finalize_func when start() is called.
50        The original value may be changed in start(), and will be reset in stop().
51        """
52
53        self._old_set_exchanges_clean_func: bool = False
54        """
55        The value of lms.cli.parser._set_exchanges_clean_func when start() is called.
56        The original value may be changed in start(), and will be reset in stop().
57        """
58
59        self._old_make_request_exchange_complete_func: typing.Union[edq.net.exchange.HTTPExchangeComplete, None] = None
60        """
61        The value of edq.net.request._make_request_exchange_complete_func when start() is called.
62        The original value may be changed in start(), and will be reset in stop().
63        """
64
65        self._old_serverrunner_logging_level: typing.Union[int, None] = None
66        """
67        The logging level for the edq server runner befoe tests are run.
68        The original value may be changed in start(), and will be reset in stop().
69        """
backend_type: Optional[str]

The type of server being run. This value will be resolved after the server is started (since part of resolution may involve pinging the server.

def start(self) -> None:
 71    def start(self) -> None:
 72        # Set configs.
 73
 74        exchange_clean_func = BACKEND_REQUEST_CLEANING_FUNCS.get(self.backend_type, lms.util.net.clean_lms_response)
 75        exchange_clean_func_name = edq.util.reflection.get_qualified_name(exchange_clean_func)
 76        self._old_exchanges_clean_func = edq.net.exchange._exchanges_clean_func
 77        edq.net.exchange._exchanges_clean_func = exchange_clean_func_name
 78
 79        self._old_exchanges_finalize_func = edq.net.exchange._exchanges_finalize_func
 80        exchange_finalize_func = BACKEND_EXCHANGE_FINALIZING_FUNCS.get(self.backend_type, None)
 81        if (exchange_finalize_func is not None):
 82            exchange_finalize_func_name = edq.util.reflection.get_qualified_name(exchange_finalize_func)
 83            edq.net.exchange._exchanges_finalize_func = exchange_finalize_func_name
 84        else:
 85            edq.net.exchange._exchanges_finalize_func = None
 86
 87        self._old_set_exchanges_clean_func = lms.cli.parser._set_exchanges_clean_func
 88        lms.cli.parser._set_exchanges_clean_func = False
 89
 90        def _make_request_callback(exchange: edq.net.exchange.HTTPExchange) -> None:
 91            # Restart if the request is a write.
 92            if (edq.util.parse.boolean(exchange.headers.get(lms.model.constants.HEADER_KEY_WRITE, False))):
 93                self.restart()
 94
 95        self._old_make_request_exchange_complete_func = edq.net.request._make_request_exchange_complete_func
 96        edq.net.request._make_request_exchange_complete_func = typing.cast(edq.net.exchange.HTTPExchangeComplete, _make_request_callback)
 97
 98        # Disable logging from the runner, since it may disrupt CLI tests.
 99        logger = logging.getLogger('edq.testing.serverrunner')
100        self._old_serverrunner_logging_level = logger.level
101        logger.setLevel(logging.WARNING)
102
103        # Start the server.
104        super().start()

Start the server.

def stop(self) -> bool:
106    def stop(self) -> bool:
107        if (self._old_serverrunner_logging_level is not None):
108            logger = logging.getLogger('edq.testing.serverrunner')
109            logger.setLevel(self._old_serverrunner_logging_level)
110            self._old_serverrunner_logging_level = None
111
112        if (not super().stop()):
113            return False
114
115        # Restore old configs.
116
117        edq.net.exchange._exchanges_clean_func = self._old_exchanges_clean_func
118        self._old_exchanges_clean_func = None
119
120        lms.cli.parser._set_exchanges_clean_func = self._old_set_exchanges_clean_func
121        self._old_set_exchanges_clean_func = False
122
123        edq.net.request._make_request_exchange_complete_func = self._old_make_request_exchange_complete_func
124        self._old_make_request_exchange_complete_func = None
125
126        return True

Stop the server. Return true if child classes should perform shutdown behavior.

def identify_server(self) -> bool:
128    def identify_server(self) ->  bool:
129        backend_type = lms.backend.instance.guess_backend_type_from_request(self.server, timeout_secs = self.identify_wait_secs)
130        return (backend_type is not None)

Attempt to identify the target server and return true on a successful attempt. This is used on startup to wait for the server to complete startup.

Child classes must implement this or set self.startup_skip_identify to true.