autograder.testing.serverrunner

  1import logging
  2import typing
  3
  4import edq.net.exchange
  5import edq.net.request
  6import edq.net.settings
  7import edq.testing.serverrunner
  8import edq.util.parse
  9import edq.util.reflection
 10
 11import autograder.api.common
 12import autograder.api.constants
 13import autograder.api.metadata.heartbeat
 14import autograder.cli.parser
 15import autograder.error
 16import autograder.model.config
 17import autograder.util.net
 18
 19class ServerRunner(edq.testing.serverrunner.ServerRunner):
 20    """ A server runner specifically for the autograder server. """
 21
 22    def __init__(self,
 23            **kwargs: typing.Any) -> None:
 24        super().__init__(**kwargs)
 25
 26        self._old_exchanges_clean_response_func: typing.Union[str, None] = None
 27        """
 28        The value of edq.net.settings.get_exchanges_clean_response_func() when start() is called.
 29        The original value may be changed in start(), and will be reset in stop().
 30        """
 31
 32        self._old_set_exchanges_clean_response_func: bool = False
 33        """
 34        The value of autograder.cli.parser._set_exchanges_clean_response_func when start() is called.
 35        The original value may be changed in start(), and will be reset in stop().
 36        """
 37
 38        self._old_request_complete_callback: typing.Union[edq.net.exchange.HTTPExchangeComplete, None] = None
 39        """
 40        The value of edq.net.request._request_complete_callback when start() is called.
 41        The original value may be changed in start(), and will be reset in stop().
 42        """
 43
 44        self._old_serverrunner_logging_level: typing.Union[int, None] = None
 45        """
 46        The logging level for the edq server runner befoe tests are run.
 47        The original value may be changed in start(), and will be reset in stop().
 48        """
 49
 50    def start(self) -> None:
 51        # Put the API in testing mode.
 52        autograder.api.common.set_testing_source_info()
 53
 54        super().start()
 55
 56        # Set configs.
 57
 58        self._old_exchanges_clean_response_func = edq.net.settings.get_exchanges_clean_response_func()
 59        edq.net.settings.set_exchanges_clean_response_func(edq.util.reflection.get_qualified_name(autograder.util.net.clean_api_response))
 60
 61        self._old_set_exchanges_clean_response_func = autograder.cli.parser._set_exchanges_clean_response_func
 62        autograder.cli.parser._set_exchanges_clean_response_func = False
 63
 64        def _request_complete_callback(exchange: edq.net.exchange.HTTPExchange) -> None:
 65            # Restart if the request is a write.
 66            if (edq.util.parse.boolean(exchange.headers.get(autograder.api.constants.HEADER_KEY_WRITE, False))):
 67                self.restart()
 68
 69        self._old_request_complete_callback = edq.net.settings.get_request_complete_callback()
 70        edq.net.settings.set_request_complete_callback(typing.cast(edq.net.exchange.HTTPExchangeComplete, _request_complete_callback))
 71
 72        # Disable logging from the runner, since it may disrupt CLI tests.
 73        logger = logging.getLogger('edq.testing.serverrunner')
 74        self._old_serverrunner_logging_level = logger.level
 75        logger.setLevel(logging.WARNING)
 76
 77    def stop(self) -> bool:
 78        if (self._old_serverrunner_logging_level is not None):
 79            logger = logging.getLogger('edq.testing.serverrunner')
 80            logger.setLevel(self._old_serverrunner_logging_level)
 81            self._old_serverrunner_logging_level = None
 82
 83        if (not super().stop()):
 84            return False
 85
 86        # Restore old configs.
 87
 88        edq.net.settings.set_exchanges_clean_response_func(self._old_exchanges_clean_response_func)
 89        self._old_exchanges_clean_response_func = None
 90
 91        autograder.cli.parser._set_exchanges_clean_response_func = self._old_set_exchanges_clean_response_func
 92        self._old_set_exchanges_clean_response_func = False
 93
 94        edq.net.settings.set_request_complete_callback(self._old_request_complete_callback)
 95        self._old_request_complete_callback = None
 96
 97        return True
 98
 99    def identify_server(self) -> bool:
100        # Check the server for a heartbeat.
101        try:
102            autograder.api.metadata.heartbeat.send(autograder.model.config.Config(server = self.server), exit_on_error = False)
103        except autograder.error.ConnectionError:
104            return False
105
106        return True
class ServerRunner(edq.testing.serverrunner.ServerRunner):
 20class ServerRunner(edq.testing.serverrunner.ServerRunner):
 21    """ A server runner specifically for the autograder server. """
 22
 23    def __init__(self,
 24            **kwargs: typing.Any) -> None:
 25        super().__init__(**kwargs)
 26
 27        self._old_exchanges_clean_response_func: typing.Union[str, None] = None
 28        """
 29        The value of edq.net.settings.get_exchanges_clean_response_func() when start() is called.
 30        The original value may be changed in start(), and will be reset in stop().
 31        """
 32
 33        self._old_set_exchanges_clean_response_func: bool = False
 34        """
 35        The value of autograder.cli.parser._set_exchanges_clean_response_func when start() is called.
 36        The original value may be changed in start(), and will be reset in stop().
 37        """
 38
 39        self._old_request_complete_callback: typing.Union[edq.net.exchange.HTTPExchangeComplete, None] = None
 40        """
 41        The value of edq.net.request._request_complete_callback when start() is called.
 42        The original value may be changed in start(), and will be reset in stop().
 43        """
 44
 45        self._old_serverrunner_logging_level: typing.Union[int, None] = None
 46        """
 47        The logging level for the edq server runner befoe tests are run.
 48        The original value may be changed in start(), and will be reset in stop().
 49        """
 50
 51    def start(self) -> None:
 52        # Put the API in testing mode.
 53        autograder.api.common.set_testing_source_info()
 54
 55        super().start()
 56
 57        # Set configs.
 58
 59        self._old_exchanges_clean_response_func = edq.net.settings.get_exchanges_clean_response_func()
 60        edq.net.settings.set_exchanges_clean_response_func(edq.util.reflection.get_qualified_name(autograder.util.net.clean_api_response))
 61
 62        self._old_set_exchanges_clean_response_func = autograder.cli.parser._set_exchanges_clean_response_func
 63        autograder.cli.parser._set_exchanges_clean_response_func = False
 64
 65        def _request_complete_callback(exchange: edq.net.exchange.HTTPExchange) -> None:
 66            # Restart if the request is a write.
 67            if (edq.util.parse.boolean(exchange.headers.get(autograder.api.constants.HEADER_KEY_WRITE, False))):
 68                self.restart()
 69
 70        self._old_request_complete_callback = edq.net.settings.get_request_complete_callback()
 71        edq.net.settings.set_request_complete_callback(typing.cast(edq.net.exchange.HTTPExchangeComplete, _request_complete_callback))
 72
 73        # Disable logging from the runner, since it may disrupt CLI tests.
 74        logger = logging.getLogger('edq.testing.serverrunner')
 75        self._old_serverrunner_logging_level = logger.level
 76        logger.setLevel(logging.WARNING)
 77
 78    def stop(self) -> bool:
 79        if (self._old_serverrunner_logging_level is not None):
 80            logger = logging.getLogger('edq.testing.serverrunner')
 81            logger.setLevel(self._old_serverrunner_logging_level)
 82            self._old_serverrunner_logging_level = None
 83
 84        if (not super().stop()):
 85            return False
 86
 87        # Restore old configs.
 88
 89        edq.net.settings.set_exchanges_clean_response_func(self._old_exchanges_clean_response_func)
 90        self._old_exchanges_clean_response_func = None
 91
 92        autograder.cli.parser._set_exchanges_clean_response_func = self._old_set_exchanges_clean_response_func
 93        self._old_set_exchanges_clean_response_func = False
 94
 95        edq.net.settings.set_request_complete_callback(self._old_request_complete_callback)
 96        self._old_request_complete_callback = None
 97
 98        return True
 99
100    def identify_server(self) -> bool:
101        # Check the server for a heartbeat.
102        try:
103            autograder.api.metadata.heartbeat.send(autograder.model.config.Config(server = self.server), exit_on_error = False)
104        except autograder.error.ConnectionError:
105            return False
106
107        return True

A server runner specifically for the autograder server.

ServerRunner(**kwargs: Any)
23    def __init__(self,
24            **kwargs: typing.Any) -> None:
25        super().__init__(**kwargs)
26
27        self._old_exchanges_clean_response_func: typing.Union[str, None] = None
28        """
29        The value of edq.net.settings.get_exchanges_clean_response_func() when start() is called.
30        The original value may be changed in start(), and will be reset in stop().
31        """
32
33        self._old_set_exchanges_clean_response_func: bool = False
34        """
35        The value of autograder.cli.parser._set_exchanges_clean_response_func when start() is called.
36        The original value may be changed in start(), and will be reset in stop().
37        """
38
39        self._old_request_complete_callback: typing.Union[edq.net.exchange.HTTPExchangeComplete, None] = None
40        """
41        The value of edq.net.request._request_complete_callback when start() is called.
42        The original value may be changed in start(), and will be reset in stop().
43        """
44
45        self._old_serverrunner_logging_level: typing.Union[int, None] = None
46        """
47        The logging level for the edq server runner befoe tests are run.
48        The original value may be changed in start(), and will be reset in stop().
49        """
def start(self) -> None:
51    def start(self) -> None:
52        # Put the API in testing mode.
53        autograder.api.common.set_testing_source_info()
54
55        super().start()
56
57        # Set configs.
58
59        self._old_exchanges_clean_response_func = edq.net.settings.get_exchanges_clean_response_func()
60        edq.net.settings.set_exchanges_clean_response_func(edq.util.reflection.get_qualified_name(autograder.util.net.clean_api_response))
61
62        self._old_set_exchanges_clean_response_func = autograder.cli.parser._set_exchanges_clean_response_func
63        autograder.cli.parser._set_exchanges_clean_response_func = False
64
65        def _request_complete_callback(exchange: edq.net.exchange.HTTPExchange) -> None:
66            # Restart if the request is a write.
67            if (edq.util.parse.boolean(exchange.headers.get(autograder.api.constants.HEADER_KEY_WRITE, False))):
68                self.restart()
69
70        self._old_request_complete_callback = edq.net.settings.get_request_complete_callback()
71        edq.net.settings.set_request_complete_callback(typing.cast(edq.net.exchange.HTTPExchangeComplete, _request_complete_callback))
72
73        # Disable logging from the runner, since it may disrupt CLI tests.
74        logger = logging.getLogger('edq.testing.serverrunner')
75        self._old_serverrunner_logging_level = logger.level
76        logger.setLevel(logging.WARNING)

Start the server.

def stop(self) -> bool:
78    def stop(self) -> bool:
79        if (self._old_serverrunner_logging_level is not None):
80            logger = logging.getLogger('edq.testing.serverrunner')
81            logger.setLevel(self._old_serverrunner_logging_level)
82            self._old_serverrunner_logging_level = None
83
84        if (not super().stop()):
85            return False
86
87        # Restore old configs.
88
89        edq.net.settings.set_exchanges_clean_response_func(self._old_exchanges_clean_response_func)
90        self._old_exchanges_clean_response_func = None
91
92        autograder.cli.parser._set_exchanges_clean_response_func = self._old_set_exchanges_clean_response_func
93        self._old_set_exchanges_clean_response_func = False
94
95        edq.net.settings.set_request_complete_callback(self._old_request_complete_callback)
96        self._old_request_complete_callback = None
97
98        return True

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

def identify_server(self) -> bool:
100    def identify_server(self) -> bool:
101        # Check the server for a heartbeat.
102        try:
103            autograder.api.metadata.heartbeat.send(autograder.model.config.Config(server = self.server), exit_on_error = False)
104        except autograder.error.ConnectionError:
105            return False
106
107        return True

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.