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