def process_election_voted(self, message): leader = message.payload['leader'] if self.state in (GateNode.STATE_ELECTING, GateNode.STATE_INITIATED): self.answers[message.sender] = leader if self.has_all_answers(): # all children have responded now leader = self.get_best_answer() # select the leader if self.state == GateNode.STATE_ELECTING: # this is an intermediate node self.state = GateNode.STATE_WAITING yield NetworkMessage('election_voted', self.info, self.parent, leader=leader) else: # this is the node which started the election self.state = GateNode.STATE_IDLE self.leader = leader for neighbour in self.neighbours: yield NetworkMessage('election_finished', self.info, neighbour, leader=leader) else: self.handle_error('Unexpected state')
def test_start_election(visitor_repository): node = GateNode(nodes[0], [nodes[1], nodes[2]], visitor_repository) assert list(node.process_message(LocalMessage('start_election'))) == \ [NetworkMessage('election_started', nodes[0], nodes[1]), NetworkMessage('election_started', nodes[0], nodes[2])] assert node.state == GateNode.STATE_INITIATED
def test_leader_removed(): node = GateNode(nodes[0], [nodes[1], nodes[2]], visitor_repository) node.leader = nodes[5] assert list(node.process_message(NetworkMessage('leader_removed', nodes[1], nodes[0]))) == \ [NetworkMessage('leader_removed', nodes[0], nodes[2])] assert node.leader is None
def test_terminate(): node = GateNode(nodes[0], [nodes[1], nodes[2]], visitor_repository) assert list(node.process_message(LocalMessage('terminate'))) == \ [NetworkMessage('terminated', nodes[0], nodes[1]), NetworkMessage('terminated', nodes[0], nodes[2]), None]
def process_election_started(self, message): if self.state == GateNode.STATE_IDLE: self.state = GateNode.STATE_ELECTING self.parent = message.sender self.leader = None self.answers = {} for child in self.get_children(): yield NetworkMessage('election_started', self.info, child) if self.has_all_answers(): # in this case there are no children for this node, so it votes for itself as the leader self.state = GateNode.STATE_WAITING yield NetworkMessage('election_voted', self.info, message.sender, leader=self.info) elif self.state in (GateNode.STATE_ELECTING, GateNode.STATE_INITIATED): yield NetworkMessage('election_voted', self.info, message.sender, leader=None) else: self.handle_error('Unexpected state')
def test_election_start_without_children(visitor_repository): node = GateNode(nodes[0], [nodes[1]], visitor_repository) assert list(node.process_message(NetworkMessage('election_started', nodes[1], nodes[0]))) == \ [NetworkMessage('election_voted', nodes[0], nodes[1], leader=nodes[0])] assert node.state == GateNode.STATE_WAITING assert node.parent == nodes[1]
def test_first_election_message(visitor_repository): node = GateNode(nodes[0], [nodes[1], nodes[2], nodes[3]], visitor_repository) assert list(node.process_message(NetworkMessage('election_started', nodes[1], nodes[0]))) == \ [NetworkMessage('election_started', nodes[0], nodes[2]), NetworkMessage('election_started', nodes[0], nodes[3])] assert node.state == GateNode.STATE_ELECTING assert node.parent == nodes[1]
def test_hello(visitor_repository): node = GateNode(nodes[0], [nodes[1], nodes[2]], visitor_repository) assert list(node.process_message(LocalMessage('say_hello'))) == \ [NetworkMessage('hello', nodes[0], nodes[1]), NetworkMessage('hello', nodes[0], nodes[2])] assert list(node.process_message(NetworkMessage('hello', nodes[1], nodes[0]))) == \ [NetworkMessage('hey', nodes[0], nodes[1])]
def test_finishing_election(visitor_repository): node = GateNode(nodes[0], [nodes[1], nodes[2], nodes[3]], visitor_repository) node.state = GateNode.STATE_WAITING assert list(node.process_message(NetworkMessage('election_finished', nodes[1], nodes[0], leader=nodes[5]))) == \ [NetworkMessage('election_finished', nodes[0], nodes[2], leader=nodes[5]), NetworkMessage('election_finished', nodes[0], nodes[3], leader=nodes[5])] assert node.state == GateNode.STATE_IDLE assert node.leader == nodes[5]
def test_another_election_message(visitor_repository): node = GateNode(nodes[0], [nodes[1], nodes[2], nodes[3]], visitor_repository) node.state = GateNode.STATE_ELECTING node.parent = nodes[1] assert list(node.process_message(NetworkMessage('election_started', nodes[2], nodes[0]))) == \ [NetworkMessage('election_voted', nodes[0], nodes[2], leader=None)] assert node.state == GateNode.STATE_ELECTING assert node.parent == nodes[1]
def test_last_ack_starting_node(visitor_repository): node = GateNode(nodes[0], [nodes[1], nodes[2]], visitor_repository) node.state = GateNode.STATE_INITIATED node.answers = {nodes[1]: nodes[4]} assert list(node.process_message(NetworkMessage('election_voted', nodes[2], nodes[0], leader=nodes[5]))) == \ [NetworkMessage('election_finished', nodes[0], nodes[1], leader=nodes[5]), NetworkMessage('election_finished', nodes[0], nodes[2], leader=nodes[5])] assert node.state == GateNode.STATE_IDLE assert node.leader == nodes[5]
def test_request_mutex(visitor_repository): node = GateNode(nodes[0], [], visitor_repository) node.leader = nodes[0] assert list(node.process_message(NetworkMessage('mutex_requested', nodes[1], nodes[0]))) == \ [NetworkMessage('mutex_granted', nodes[0], nodes[1])] assert node.mutex_holder == nodes[1] assert not node.mutex_queue assert list(node.process_message(NetworkMessage('mutex_requested', nodes[2], nodes[0]))) == [] assert node.mutex_queue == [nodes[2]] assert list(node.process_message(NetworkMessage('mutex_requested', nodes[3], nodes[0]))) == [] assert node.mutex_queue == [nodes[2], nodes[3]] assert list(node.process_message(NetworkMessage('mutex_released', nodes[1], nodes[0]))) == \ [NetworkMessage('mutex_granted', nodes[0], nodes[2])] assert node.mutex_holder == nodes[2] assert node.mutex_queue == [nodes[3]] assert list(node.process_message(NetworkMessage('mutex_released', nodes[2], nodes[0]))) == \ [NetworkMessage('mutex_granted', nodes[0], nodes[3])] assert node.mutex_holder == nodes[3] assert node.mutex_queue == [] assert list(node.process_message(NetworkMessage('mutex_released', nodes[3], nodes[0]))) == [] assert node.mutex_holder is None assert node.mutex_queue == []
def test_last_ack_intermediate_node(visitor_repository): node = GateNode(nodes[0], [nodes[1], nodes[2], nodes[3]], visitor_repository) node.state = GateNode.STATE_ELECTING node.parent = nodes[1] node.answers = {nodes[2]: nodes[5]} assert list(node.process_message(NetworkMessage('election_voted', nodes[3], nodes[0], leader=nodes[4]))) == \ [NetworkMessage('election_voted', nodes[0], nodes[1], leader=nodes[5])] assert node.state == GateNode.STATE_WAITING assert node.answers == {nodes[2]: nodes[5], nodes[3]: nodes[4]}
def test_enter_refused(): node = VisitorNode(nodes[0]) assert list(node.process_message(LocalMessage('enter_park', gate=nodes[1]))) == \ [NetworkMessage('enter_request', nodes[0], nodes[1])] assert node.state == VisitorNode.STATE_ENTERING assert not list( node.process_message( NetworkMessage('enter_response', nodes[1], nodes[0], allowed=False))) assert node.state == VisitorNode.STATE_IDLE
def test_leave_rejected(): node = VisitorNode(nodes[0]) node.state = VisitorNode.STATE_ENTERED assert list(node.process_message(LocalMessage('leave_park', gate=nodes[1]))) == \ [NetworkMessage('leave_request', nodes[0], nodes[1])] assert node.state == VisitorNode.STATE_LEAVING assert not list( node.process_message( NetworkMessage('leave_response', nodes[1], nodes[0], allowed=False))) assert node.state == VisitorNode.STATE_ENTERED
def leave_park(self, message): gate = message.payload['gate'] if self.state == VisitorNode.STATE_ENTERED: yield NetworkMessage('leave_request', self.info, gate) self.state = VisitorNode.STATE_LEAVING else: self.handle_unexpected_state()
def terminate(self): if self.state == GateNode.STATE_IDLE: for neighbour in self.neighbours: yield NetworkMessage('terminated', self.info, neighbour) yield None # no more messages will be sent by this node else: self.handle_error('Unexpected state')
def test_first_ack(visitor_repository): node = GateNode(nodes[0], [nodes[1], nodes[2], nodes[3]], visitor_repository) node.state = GateNode.STATE_INITIATED assert list(node.process_message(NetworkMessage('election_voted', nodes[1], nodes[0], leader=nodes[5]))) == [] assert node.state == GateNode.STATE_INITIATED assert node.answers == {nodes[1]: nodes[5]}
def enter_park(self, message): gate = message.payload['gate'] if self.state == VisitorNode.STATE_IDLE: yield NetworkMessage('enter_request', self.info, gate) self.state = VisitorNode.STATE_ENTERING else: self.handle_unexpected_state()
def process_leader_removed(self, message): if self.leader is None: # leader was already removed by a previous message return self.leader = None for neighbour in self.neighbours: if neighbour != message.sender: yield NetworkMessage('leader_removed', self.info, neighbour)
def remove_leader(self): if self.state != GateNode.STATE_IDLE: self.handle_error('Unexpected state') if self.leader != self.info: self.handle_error('Not the leader') self.leader = None for neighbour in self.neighbours: yield NetworkMessage('leader_removed', self.info, neighbour)
def start_election(self): if self.state == GateNode.STATE_IDLE: self.state = GateNode.STATE_INITIATED self.parent = None self.leader = None self.answers = {} for neighbour in self.neighbours: yield NetworkMessage('election_started', self.info, neighbour) else: self.handle_error('Unexpected state')
def process_mutex_granted(self, message): if not self.mutex_requested: self.handle_error('Mutex not requested') state = self.repository.read_state() for entering_node in self.enter_queue: try: state.enter(entering_node.id) yield NetworkMessage('enter_response', self.info, entering_node, allowed=True) except AssertionError: # if node cannot enter yield NetworkMessage('enter_response', self.info, entering_node, allowed=False) for leaving_node in self.leave_queue: try: state.leave(leaving_node.id) yield NetworkMessage('leave_response', self.info, leaving_node, allowed=True) except AssertionError: # if node cannot leave yield NetworkMessage('leave_response', self.info, leaving_node, allowed=False) self.repository.write_state(state) self.mutex_requested = False self.enter_queue = [] self.leave_queue = [] yield NetworkMessage('mutex_released', self.info, self.leader)
def process_election_finished(self, message): leader = message.payload['leader'] if self.state == GateNode.STATE_WAITING: self.state = GateNode.STATE_IDLE self.leader = leader for neighbour in self.neighbours: if neighbour != message.sender: yield NetworkMessage('election_finished', self.info, neighbour, leader=leader)
def process_mutex_released(self, message): if self.leader != self.info: self.handle_error('Not a leader') if self.mutex_holder is None: self.handle_error('No mutex holder') if self.mutex_holder != message.sender: self.handle_error('Invalid sender') if self.mutex_queue: # some nodes are waiting in the queue self.mutex_holder = self.mutex_queue.pop(0) yield NetworkMessage('mutex_granted', self.info, self.mutex_holder) else: self.mutex_holder = None
def test_leave_request(visitor_repository): visitor_repository.write_state(State(capacity=1, visitors=[nodes[1].id])) node = GateNode(nodes[0], [], visitor_repository) node.leader = nodes[5] assert list(node.process_message(NetworkMessage('leave_request', nodes[1], nodes[0]))) == \ [NetworkMessage('mutex_requested', nodes[0], nodes[5])] assert node.leave_queue == [nodes[1]] assert list(node.process_message(NetworkMessage('leave_request', nodes[2], nodes[0]))) == [] assert node.leave_queue == [nodes[1], nodes[2]] assert list(node.process_message(NetworkMessage('mutex_granted', nodes[5], nodes[0]))) == \ [NetworkMessage('leave_response', nodes[0], nodes[1], allowed=True), NetworkMessage('leave_response', nodes[0], nodes[2], allowed=False), NetworkMessage('mutex_released', nodes[0], nodes[5])] assert node.leave_queue == [] assert list(node.process_message(NetworkMessage('leave_request', nodes[3], nodes[0]))) == \ [NetworkMessage('mutex_requested', nodes[0], nodes[5])] assert node.leave_queue == [nodes[3]]
def process_hello(self, message): yield NetworkMessage('hey', self.info, message.sender)
def say_hello(self): for neighbour in self.neighbours: yield NetworkMessage('hello', self.info, neighbour)
def process_leave_request(self, message): if not self.mutex_requested: yield NetworkMessage('mutex_requested', self.info, self.leader) self.mutex_requested = True self.leave_queue.append(message.sender)
def process_mutex_requested(self, message): if self.mutex_holder is None: self.mutex_holder = message.sender yield NetworkMessage('mutex_granted', self.info, self.mutex_holder) else: self.mutex_queue.append(message.sender)