def test_agent_hello(DummyAgent, address_config_file): ag = DummyAgent(1, str(address_config_file)) ag.start() messenger = ZTesterMessenger('tester') participants = Participants(str(address_config_file)) ctx = zmq.Context() ssend = ctx.socket(zmq.PUSH) ssend.connect(participants.address('agent')) srecv = ctx.socket(zmq.PULL) srecv.bind(participants.address('mediator')) ssend.send_string(str(messenger.build_start_message())) content = list(range(10)) ssend.send_string( json.dumps({ 'sender': 'oi', 'receiver': '', 'type': 'bumba', 'content': content })) msg = Message.from_json(srecv.recv_json()) assert msg.sender == 'agent' assert msg.type == 'RESULT' assert msg.content == content[::-1] ssend.send_string(str(messenger.build_stop_message())) ag.join()
def __init__(self, aux_id, main_config, run_config, address_config, component_config=None): super().__init__() self.aux_id = aux_id self.config = load_config(main_config) self.run_config = load_config(run_config, self.config['simulation']['variables']) self.participants = Participants(address_config) if component_config is not None: self.components = ComponentManager.get_component_enum(component_config) self.sockets = {}
def __init__(self, participants_config, components_config=None): super().__init__() # TODO: give a better name self.places = [] self.agent_positions = {} self.participants = Participants(participants_config) self._messenger = None if components_config is not None: self.components = ComponentManager.get_component_enum( components_config)
def __init__(self, address_config, component_config=None): super().__init__() # communication participants = Participants(address_config) self.address = participants.address('strategy') self.tester_address = participants.address('tester') self.socket_receive = None self.socket_send = None # internal state if component_config is not None: self.components = ComponentManager.get_component_enum(component_config)
def __init__(self, ag_id, address_config, component_config=None): super().__init__() self.id = ag_id # communication participants = Participants(address_config) self.address = participants.address(self.alias) self.mediator_address = participants.address('mediator') self.socket_receive = None self.socket_send = None self._messenger = None # internal state if component_config is not None: self.components = ComponentManager.get_component_enum(component_config)
def __init__(self, ag_id, address_config, component_config=None): super().__init__() self.id = ag_id # communication participants = Participants(address_config) self.address = participants.address(self.alias) self.mediator_address = participants.address('mediator') self.socket_receive = None self.socket_send = None self._messenger = None # internal state if component_config is not None: self.components = ComponentManager.get_component_enum( component_config)
def __init__(self, participants_config, components_config=None): super().__init__() # TODO: give a better name self.places = [] self.agent_positions = {} self.participants = Participants(participants_config) self._messenger = None if components_config is not None: self.components = ComponentManager.get_component_enum(components_config)
def __init__(self, participants_config, tester_alias="tester"): super().__init__() self.simulation_participants = SimulationParticipants(participants_config) self.participants = {} self.participant_sockets = {} self.tester_alias = tester_alias # TODO please, rename this self.sockets_participants = {} self._log = []
def test_participants_invalid_alias_and_address(address_configuration_file, config_json): participants = Participants(str(address_configuration_file)) alias, address = random.choice(list(config_json.items())) with pytest.raises(KeyError): participants.alias(address + address) with pytest.raises(KeyError): participants.address(alias + alias)
class Tester(BaseTester): messenger_class = TesterMessenger def __init__(self, main_config, run_config, address_config, component_config=None): super().__init__() self.config = load_config(main_config) self.run_config = load_config(run_config, self.config['simulation']['variables']) self.participants = Participants(address_config) if component_config is not None: self.components = ComponentManager.get_component_enum( component_config) self.sockets = {} @property def alias(self): return 'tester' def run(self): logging.info('Tester: running.') mode = Mode.from_string(self.config['simulation']['mode']) self.context = zmq.Context() self.socket_receive = self.context.socket(zmq.PULL) self.socket_receive.bind(self.participants.address('tester')) self.initialize_participants() self.main_loop(mode) logging.debug('Tester: stopping.') time.sleep(2) def initialize_participants(self): logging.info("Tester: initializing participants") for alias in self.run_config.keys(): self.initialize_participant(alias) def initialize_participants_distributed(self): logging.info("Tester: initializing participants") self.initialize_participant('strategy') self.config['auxiliares'].keys() for participant in self.participants.aliases: if not participant.startswith('tester_'): continue self.initialize_participant(participant) def stop_participants(self): logging.info("Tester: stopping participants") stop_message = str(self.messenger.build_stop_message()) for alias in self.run_config.keys(): self.sockets[alias].send_string(stop_message) def main_loop(self, mode): result = None if mode == Mode.CENTRALIZED: result = self.main_loop_centralized() elif mode == Mode.DISTRIBUTED: result = self.main_loop_distributed() else: msg = "Unknown mode: {}".format(mode) logging.error(msg) raise CoreException(msg) return result def main_loop_centralized(self): """ """ start_message = str(self.messenger.build_start_message()) stop_message = str(self.messenger.build_stop_message()) self.sockets['strategy'].send_string( str(self.build_strategy_config_message())) self.sockets['strategy'].send_string(start_message) self.sockets['mediator'].send_string( str(self.build_mediator_config_message())) while True: logging.debug('Tester: waiting message from strategy') msg = self.receive_message() logging.debug('Tester received {}'.format(str(msg))) if msg.sender != 'strategy': logging.error( 'received message from {} instead of strategy'.format( msg.sender)) # we shouldn't been receiving messages from any other sender at this point... break if msg.type == 'STOP': logging.debug('stop participants') self.stop_participants() break elif msg.type == 'EVALUATE': time.sleep(.01) self.sockets['mediator'].send_string(start_message) logging.debug('Tester: lets configure environment') evaluation_id = msg.content.get('id') environ_config = self.build_environment_config_message( msg.content) self.sockets['environment'].send_string(str(environ_config)) self.sockets['environment'].send_string(start_message) # TODO this must work for multiple agents logging.debug('Tester: lets configure agent(s)') for agent_alias in self.get_agents_aliases(): self.sockets[agent_alias].send_string( str(self.build_agent_config_message())) self.sockets[agent_alias].send_string(start_message) logging.debug('Tester: waiting for mediator\'s answer') msg = self.receive_message() logging.debug('Tester evaluate {}'.format(str(msg)[:50])) result = { 'id': evaluation_id, 'data': self.evaluate(msg.content) } # TODO check if the message is from mediator or raise error logging.debug( 'Tester: send answer to strategy {}'.format(result)) result_message = self.messenger.build_result_message( receiver='strategy', content=result) self.sockets['strategy'].send_string(str(result_message)) logging.debug('Tester: waiting report...') msg = self.receive_message() self.report_result(msg) def receive_message_from_poller(self, poller, socket, timeout): result = poller.poll(timeout) if socket in result: return Message.from_string(socket.recv_string()) return None def get_auxiliary_testers_aliases(self): return [a for a in self.run_config.keys() if a.startswith('aux')] def main_loop_distributed(self): start_message = str(self.messenger.build_start_message()) stop_message = str(self.messenger.build_stop_message()) self.sockets['strategy'].send_string( str(self.build_strategy_config_message())) self.sockets['strategy'].send_string(start_message) eval_buffer = deque() available_testers = set(self.get_auxiliary_testers_aliases()) working_testers = set() poller = zmq.Poller() poller.register(self.socket_receive, zmq.POLLIN) should_stop = False while not should_stop or len(working_testers) > 0: socket = dict(poller.poll(100)) if self.socket_receive in socket: msg = Message.from_string(self.socket_receive.recv_string()) if msg.sender == 'strategy': if msg.type == 'EVALUATE': eval_buffer.append(msg) elif msg.type == 'STOP': should_stop = True elif msg.sender.startswith('aux'): working_testers.remove(msg.sender) available_testers.add(msg.sender) self.sockets['strategy'].send_string(str(msg)) while len(available_testers) > 0 and len(eval_buffer) > 0: msg = eval_buffer.popleft() # handle stop message tester = available_testers.pop() working_testers.add(tester) # TODO msg.sender = 'tester' self.sockets[tester].send_string(str(msg)) time.sleep(2) self.stop_participants() logging.debug('tester, waiting report...') msg = self.receive_message() self.report_result(msg) poller.unregister(self.socket_receive)
class Environment(abc.ABC, Process): messenger_class = EnvironmentMessenger def __init__(self, participants_config, components_config=None): super().__init__() # TODO: give a better name self.places = [] self.agent_positions = {} self.participants = Participants(participants_config) self._messenger = None if components_config is not None: self.components = ComponentManager.get_component_enum(components_config) @property def messenger(self): if self._messenger is None: if self.messenger_class is None: raise ZephyrusException("Calling 'messenger' without defining 'messenger_class'") self._messenger = self.messenger_class('environment') return self._messenger def run(self): # TODO add log context = zmq.Context() self.socket_receive = context.socket(zmq.PULL) self.socket_receive.bind(self.participants.address('environment')) self.socket_send = context.socket(zmq.PUSH) # connect with interaction self.socket_send.connect(self.participants.address('mediator')) logging.info("Environment: running.") self.ready() def ready(self): while True: logging.debug('Environmnent is ready.') msg = Message.from_string(self.socket_receive.recv_string()) if msg.type == "START": self.mainloop() elif msg.type == "STOP": logging.info("Environment: stopping.") break elif msg.type == "CONFIG": self.configure(msg.content) else: logging.error("Environmnent received an invalid message.") logging.error(str(msg)) @abc.abstractmethod def mainloop(self): pass @abc.abstractmethod def configure(self, config_data): pass def __str__(self): return 'Environ: ' + ' '.join(self.places[:]) def add_agent(self, agent_id, line, col): if not 0 <= line < self.nlines or 0 <= col < self.ncols: raise ValueError("Invalid line or col provided") self.agent_pos[agent_id] = (line, col) return len(self.agent_pos)
class AuxiliaryTester(BaseTester): messenger_class = AuxiliaryTesterMessenger def __init__(self, aux_id, main_config, run_config, address_config, component_config=None): super().__init__() self.aux_id = aux_id self.config = load_config(main_config) self.run_config = load_config(run_config, self.config['simulation']['variables']) self.participants = Participants(address_config) if component_config is not None: self.components = ComponentManager.get_component_enum(component_config) self.sockets = {} @property def alias(self): return 'aux_{}'.format(self.aux_id) def run(self): logging.info('Auxiliary {}: running.'.format(self.aux_id)) self.context = zmq.Context() # connect to main self.socket_main = self.context.socket(zmq.PUSH) self.socket_main.connect(self.participants.address('tester')) self.socket_receive = self.context.socket(zmq.PULL) self.socket_receive.bind(self.participants.address(self.alias)) self.initialize_participants() self.main_loop() logging.debug('Auxiliary {}: stopping'.format(self.aux_id)) time.sleep(2) def initialize_participants(self): logging.info("Auxiliary Tester: initializing participants") for alias in self.run_config.keys(): self.initialize_participant(alias) def stop_participants(self): logging.info("Auxiliary Tester: stopping participants") stop_message = str(self.messenger.build_stop_message()) for alias in self.run_config.keys(): self.sockets[alias].send_string(stop_message) def main_loop(self): start_message = str(self.messenger.build_start_message()) stop_message = str(self.messenger.build_stop_message()) self.sockets['mediator'].send_string(str(self.build_mediator_config_message())) while True: logging.debug('Auxiliary {}: waiting message from strategy'.format(self.aux_id)) msg = self.receive_message() logging.debug('Auxiliary Tester {}: received {}'.format(self.aux_id, str(msg))) if msg.sender != 'tester': logging.error('received message from {} instead of tester'.format(msg.sender)) # we shouldn't been receiving messages from any other sender at this point... break if msg.type == 'STOP': logging.debug('stop participants') self.stop_participants() break elif msg.type == 'EVALUATE': self.sockets['mediator'].send_string(start_message) time.sleep(.01) logging.debug('Auxiliary: lets configure environment') evaluation_id = msg.content.get('id') environ_config = self.build_environment_config_message(msg.content) self.sockets['environment'].send_string(str(environ_config)) self.sockets['environment'].send_string(start_message) # TODO this must work for multiple agents logging.debug('Auxiliary: lets configure agent(s)') for agent_alias in self.get_agents_aliases(): self.sockets[agent_alias].send_string(str(self.build_agent_config_message())) self.sockets[agent_alias].send_string(start_message) logging.debug('Auxiliary: waiting for mediator\'s answer') msg = self.receive_message() logging.debug('Auxiliary: evaluate {}'.format(str(msg)[:50])) result = { 'id': evaluation_id, 'data': self.evaluate(msg.content) } # TODO check if the message is from mediator or raise error logging.debug('Auxiliary: send answer to strategy') result_message = self.messenger.build_result_message(receiver='tester', content=result) self.socket_main.send_string(str(result_message))
class Mediator(Process): messenger_class = MediatorMessenger def __init__(self, participants_config, tester_alias="tester"): super().__init__() self.simulation_participants = SimulationParticipants(participants_config) self.participants = {} self.participant_sockets = {} self.tester_alias = tester_alias # TODO please, rename this self.sockets_participants = {} self._log = [] @property def messenger(self): if getattr(self, '_messenger', None) is None: self._messenger = self.messenger_class('mediator') return self._messenger def run(self): self.context = zmq.Context() self.socket_receive = self.context.socket(zmq.PULL) address = self.simulation_participants.address('mediator') self.socket_receive.bind(address) self.socket_tester = self.context.socket(zmq.PUSH) address = self.simulation_participants.address(self.tester_alias) self.socket_tester.connect(address) self.connect_to_participants() logging.info('Mediator: running.') self.ready() def connect_to_participants(self): self.remove_all_participants() logging.debug('Mediator is connecting to all participants') for alias, address in self.participants.items(): self.sockets_participants[alias] = self.context.socket(zmq.PUSH) self.sockets_participants[alias].connect(address) def remove_all_participants(self): logging.debug('Mediator is removing all participants') # explicitly closing sockets altough GC handles it for us. # http://pyzmq.readthedocs.io/en/latest/api/zmq.html#zmq.Socket.close for socket in self.sockets_participants.values(): pass # if not socket.closed: # print('oi') # socket.close() self.sockets_participants = {} def ready(self): while True: logging.debug('Mediator is ready!!') # TODO APL msg = Message.from_string(self.socket_receive.recv_string()) logging.debug('Mediator: received {}'.format(str(msg))) if msg.type == "FINISH": self.broadcast(self.messenger.build_finish_message()) break elif msg.type == "START": self.mainloop() elif msg.type == "CONFIG": self.configure(msg.content) elif msg.type == "STOP": logging.info("Mediator: stopping.") break else: logging.error('Mediator received invalid message {}'.format(str(msg))) def get_next_message_string(self): if len(self.msg_buffer) > 0: return self.msg_buffer.popleft() return self.socket_receive.recv_string() def configure(self, content): self.participants = content self.connect_to_participants() def mainloop(self): active_participants = set(self.participants.keys()) logging.debug('Mediator, participants are: {}'.format(self.participants)) nstarted = 0 self.msg_buffer = deque() while nstarted < len(active_participants): msg_str = self.socket_receive.recv_string() msg = Message.from_string(msg_str) if msg.receiver != 'mediator' or msg.type != 'START': self.msg_buffer.append(msg_str) logging.debug("Monitor: buffering message '{}'".format(msg_str)) # TODO raise error else: logging.debug("Monitor: a participant started") nstarted += 1 while len(active_participants) > 0: msg_str = self.get_next_message_string() logging.debug('Mediator, received {}'.format(msg_str)) msg = Message.from_string(msg_str) sender = msg.sender receiver = msg.receiver if sender is None or receiver is None: emsg = "Messages sent through Mediator must specify both sender and receiver." raise CoreException(emsg) if receiver == 'mediator': # TODO we must made clear the difference between FINISH and STOP if msg.type == 'STOP': active_participants.remove(sender) else: self._log.append(msg_str) logging.debug('Mediator: sending it to {}'.format(receiver)) self.sockets_participants[receiver].send_string(msg_str) # TODO We must improve this. Think about how badly this scales. msg = Message('mediator', 'tester', 'RESULT', self._log) self.socket_tester.send_string(str(msg)) self._log = [] def add_participant(self, pid: int, address: str): # TODO apl # print 'adcionou participante', pid, 'em', endereco self.participants[pid] = address def remove_particioant(self, pid: int): del self.participants[pid] def broadcast(self, message): raw = str(message) for pid in self.participants: self.sockets_participants[pid].send(raw)
class Environment(abc.ABC, Process): messenger_class = EnvironmentMessenger def __init__(self, participants_config, components_config=None): super().__init__() # TODO: give a better name self.places = [] self.agent_positions = {} self.participants = Participants(participants_config) self._messenger = None if components_config is not None: self.components = ComponentManager.get_component_enum( components_config) @property def messenger(self): if self._messenger is None: if self.messenger_class is None: raise ZephyrusException( "Calling 'messenger' without defining 'messenger_class'") self._messenger = self.messenger_class('environment') return self._messenger def run(self): # TODO add log context = zmq.Context() self.socket_receive = context.socket(zmq.PULL) self.socket_receive.bind(self.participants.address('environment')) self.socket_send = context.socket(zmq.PUSH) # connect with interaction self.socket_send.connect(self.participants.address('mediator')) logging.info("Environment: running.") self.ready() def ready(self): while True: logging.debug('Environmnent is ready.') msg = Message.from_string(self.socket_receive.recv_string()) if msg.type == "START": self.mainloop() elif msg.type == "STOP": logging.info("Environment: stopping.") break elif msg.type == "CONFIG": self.configure(msg.content) else: logging.error("Environmnent received an invalid message.") logging.error(str(msg)) @abc.abstractmethod def mainloop(self): pass @abc.abstractmethod def configure(self, config_data): pass def __str__(self): return 'Environ: ' + ' '.join(self.places[:]) def add_agent(self, agent_id, line, col): if not 0 <= line < self.nlines or 0 <= col < self.ncols: raise ValueError("Invalid line or col provided") self.agent_pos[agent_id] = (line, col) return len(self.agent_pos)
def test_participants_invalid_config_file(tmpdir): p = tmpdir.mkdir("foo").join("fakeconfig.json") p.write("[invalid gibberish]") with pytest.raises(ImproperlyConfigured): Participants(str(p))
def test_participants_alias_and_address(address_configuration_file, config_json): participants = Participants(str(address_configuration_file)) alias, address = random.choice(list(config_json.items())) assert participants.alias(address) == alias assert participants.address(alias) == address