def test_no_collisions(): machines = [test_machine()] c = Configuration(machines=machines) assert c.machines == machines machines = [test_machine("a"), test_machine("b")] c = Configuration(machines=machines) assert c.machines == machines
def test_spinnaker_ip_collision(): with pytest.raises(ValueError): machines = [ test_machine("a", spinnaker_prefix="bmp"), test_machine("b", spinnaker_prefix="bmp") ] Configuration(machines=machines)
def test_sensible_defaults(): c = Configuration() assert c.machines == [] assert c.ip == "" assert c.timeout_check_interval == 5.0 assert c.max_retired_jobs == 1200
def test_read_config_file(simple_config, s): # Should fail if config file is missing os.remove(simple_config) assert s.read_config_file() is False # Should fail if config file is syntactically invalid with open(simple_config, "w") as f: f.write("1_2_3") assert s.read_config_file() is False # Should fail if no configuration variable is set with open(simple_config, "w") as f: f.write("config = 123") assert s.read_config_file() is False # Should succeed otherwise! with open(simple_config, "w") as f: # Make a simple config file f.write("configuration = {}".format(repr(Configuration()))) assert s.read_config_file() is True # Should pass on parameters to controller with open(simple_config, "w") as f: f.write("configuration = {}".format(repr( Configuration(max_retired_jobs=123)))) assert s.read_config_file() is True assert s._controller.max_retired_jobs == 123 # Should pass on machines to controller in right order with open(simple_config, "w") as f: f.write("configuration = {}".format(repr( Configuration(machines=[simple_machine("m0", ip_prefix="0"), simple_machine("m1", ip_prefix="1"), simple_machine("m2", ip_prefix="2"), simple_machine("m3", ip_prefix="3"), simple_machine("m4", ip_prefix="4")])))) assert s.read_config_file() is True assert list(s._controller.machines) == "m0 m1 m2 m3 m4".split()
def test_reread_config_file(simple_config, s): if not hasattr(signal, "SIGHUP"): # pragma: no cover return # Make sure config re-reading works assert list(s._controller.machines) == ["m"] # Modify config file with open(simple_config, "w") as f: f.write("configuration = {}".format(repr(Configuration()))) os.kill(os.getpid(), signal.SIGHUP) time.sleep(0.2) # Configuration should have changed accordingly assert list(s._controller.machines) == []
def test_machine_notifications(double_config, s): with SimpleClient() as c0: with SimpleClient() as c1: c0.call("notify_machine", "m0") c1.call("notify_machine") job_id0 = c0.call("create_job", 1, 2, owner="me") time.sleep(0.05) # Should be notified new jobs being scheduled assert c0.get_notification() == {"machines_changed": ["m0"]} assert c1.get_notification() == {"machines_changed": ["m0"]} job_id1 = c0.call("create_job", owner="me") time.sleep(0.05) # Make sure filtering works assert c1.get_notification() == {"machines_changed": ["m1"]} # Should be notified on job completion c0.call("destroy_job", job_id0) assert c0.get_notification() == {"machines_changed": ["m0"]} assert c1.get_notification() == {"machines_changed": ["m0"]} # Should be notified on job completion c1.call("destroy_job", job_id1) assert c1.get_notification() == {"machines_changed": ["m1"]} # Make sure machine changes get announced if not hasattr(signal, "SIGHUP"): # pragma: no cover return with open(double_config, "w") as f: f.write("configuration = {}".format(repr(Configuration()))) os.kill(os.getpid(), signal.SIGHUP) assert c0.get_notification() == {"machines_changed": ["m0"]} assert c1.get_notification() in ( {"machines_changed": ["m0", "m1"]}, {"machines_changed": ["m1", "m0"]})
def __init__(self, config_filename, cold_start=False, port=22244): """ :param config_filename: \ The filename of the config file for the server which describes the\ machines to be controlled. :type config_filename: str :param cold_start: \ If False (the default), the server will attempt to restore its\ previous state, if True, the server will start from scratch. :type cold_start: bool :param port: Which port to listen on. Defaults to 22244. :type port: int """ # ============ STATE THAT NEEDS TO BE ALWAYS DEFINED ============ self._cold_start = cold_start self._port = port # Should the background thread terminate? self._stop = False # Flag for checking if the server is still alive self._running = False # Currently open sockets to clients. Once server started, should only # be accessed from the server thread. self._server_socket = None # The server core object that the object that is persisted self._controller = None # Buffered data received from each socket # {fd: buf, ...} self._client_buffers = {} # ============ SUPERCLASS INITIALISATION ============ PollingServerCore.__init__(self) ConfigurationReloader.__init__(self, config_filename, self.wake) # ============ ACTIVE OBJECTS ============ # The background thread in which the server will run self._server_thread = Thread(target=self._run, name="Server Thread") # The current server configuration options. Once server started, should # only be accessed from the server thread. self._configuration = Configuration() # Infer the saved-state location self._state_filename = self._get_state_filename( self.configuration_file) # Attempt to restore saved state if required if not self._cold_start and path.isfile(self._state_filename): try: with open(self._state_filename, "rb") as f: self._controller = unpickle(f) log.info("Server warm-starting from %s.", self._state_filename) except Exception: # Some other error occurred during unpickling. log.exception("Server state could not be unpacked from %s.", self._state_filename) self._controller = None # Perform cold-start if no saved state was loaded if self._controller is None: log.info("Server cold-starting.") self._controller = Controller() # Notify the background thread when something changes in the background # of the controller (e.g. power state changes). self._controller.on_background_state_change = self.wake # Read configuration file. This must succeed when the server is first # being started. if not self.read_config_file(): self._controller.stop() raise Exception("Config file could not be loaded.") # Start the server self._server_thread.start() self._running = True
def test_name_collision(): with pytest.raises(ValueError): machines = [test_machine("a"), test_machine("b"), test_machine("a")] Configuration(machines=machines)
def test_machine_type(): with pytest.raises(TypeError): Configuration(machines=["m"])