def decode(obj: bytes) -> Message: """ Decode bytes into a 'StateUpdate' message. :param obj: the bytes object. :return: the 'StateUpdate' message. """ message_pb = ProtobufMessage() state_update_pb = state_update_pb2.StateUpdateMessage() message_pb.ParseFromString(obj) message_id = message_pb.dialogue_message.message_id dialogue_reference = ( message_pb.dialogue_message.dialogue_starter_reference, message_pb.dialogue_message.dialogue_responder_reference, ) target = message_pb.dialogue_message.target state_update_pb.ParseFromString(message_pb.dialogue_message.content) performative = state_update_pb.WhichOneof("performative") performative_id = StateUpdateMessage.Performative(str(performative)) performative_content = dict() # type: Dict[str, Any] if performative_id == StateUpdateMessage.Performative.INITIALIZE: exchange_params_by_currency_id = ( state_update_pb.initialize.exchange_params_by_currency_id) exchange_params_by_currency_id_dict = dict( exchange_params_by_currency_id) performative_content[ "exchange_params_by_currency_id"] = exchange_params_by_currency_id_dict utility_params_by_good_id = ( state_update_pb.initialize.utility_params_by_good_id) utility_params_by_good_id_dict = dict(utility_params_by_good_id) performative_content[ "utility_params_by_good_id"] = utility_params_by_good_id_dict amount_by_currency_id = state_update_pb.initialize.amount_by_currency_id amount_by_currency_id_dict = dict(amount_by_currency_id) performative_content[ "amount_by_currency_id"] = amount_by_currency_id_dict quantities_by_good_id = state_update_pb.initialize.quantities_by_good_id quantities_by_good_id_dict = dict(quantities_by_good_id) performative_content[ "quantities_by_good_id"] = quantities_by_good_id_dict elif performative_id == StateUpdateMessage.Performative.APPLY: amount_by_currency_id = state_update_pb.apply.amount_by_currency_id amount_by_currency_id_dict = dict(amount_by_currency_id) performative_content[ "amount_by_currency_id"] = amount_by_currency_id_dict quantities_by_good_id = state_update_pb.apply.quantities_by_good_id quantities_by_good_id_dict = dict(quantities_by_good_id) performative_content[ "quantities_by_good_id"] = quantities_by_good_id_dict else: raise ValueError( "Performative not valid: {}.".format(performative_id)) return StateUpdateMessage(message_id=message_id, dialogue_reference=dialogue_reference, target=target, performative=performative, **performative_content)
def test_serialization_end(self): """Test serialization of end message.""" msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.END, ) assert msg._is_consistent() assert len(msg.valid_performatives) == 3 encoded_msg = msg.serializer.encode(msg) decoded_msg = msg.serializer.decode(encoded_msg) assert msg == decoded_msg
def test_serialization_apply(self): """Test serialization of apply message.""" currency_change = {"FET": 10} good_change = {"a_good": 1} msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, amount_by_currency_id=currency_change, quantities_by_good_id=good_change, ) assert msg._is_consistent() assert len(msg.valid_performatives) == 3 encoded_msg = msg.serializer.encode(msg) decoded_msg = msg.serializer.decode(encoded_msg) assert msg == decoded_msg
def test_serialization_negative(): """Test serialization when performative is not recognized.""" currency_change = {"FET": 10} good_change = {"a_good": 1} msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, amount_by_currency_id=currency_change, quantities_by_good_id=good_change, ) with patch.object(StateUpdateMessage.Performative, "__eq__", return_value=False): with pytest.raises( ValueError, match=f"Performative not valid: {msg.performative}"): msg.serializer.encode(msg) encoded_tx_bytes = msg.serializer.encode(msg) with patch.object(StateUpdateMessage.Performative, "__eq__", return_value=False): with pytest.raises( ValueError, match=f"Performative not valid: {msg.performative}"): msg.serializer.decode(encoded_tx_bytes)
def test_message_consistency(self): """Test for an error in consistency of a message.""" currency_endowment = {"FET": 100} good_endowment = {"a_good": 2} exchange_params = {"FET": 10.0} utility_params = {"a_good": 20.0} assert StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=currency_endowment, quantities_by_good_id=good_endowment, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, ) currency_change = {"FET": 10} good_change = {"a_good": 1} stum = StateUpdateMessage( performative=StateUpdateMessage.Performative.APPLY, amount_by_currency_id=currency_change, quantities_by_good_id=good_change, ) assert stum._is_consistent() assert len(stum.valid_performatives) == 3 stum = StateUpdateMessage( performative=StateUpdateMessage.Performative.END, ) assert stum._is_consistent()
def test_decision_maker_handle_state_update_initialize_and_apply(self): """Test the handle method for a stateUpdate message with Initialize and Apply performative.""" good_holdings = {"good_id": 2} currency_holdings = {"FET": 100} utility_params = {"good_id": 20.0} exchange_params = {"FET": 10.0} currency_deltas = {"FET": -10} good_deltas = {"good_id": 1} state_update_dialogues = StateUpdateDialogues("agent") state_update_message_1 = StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, dialogue_reference=state_update_dialogues. new_self_initiated_dialogue_reference(), amount_by_currency_id=currency_holdings, quantities_by_good_id=good_holdings, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, ) state_update_dialogue = cast( Optional[StateUpdateDialogue], state_update_dialogues.create_with_message("decision_maker", state_update_message_1), ) assert state_update_dialogue is not None, "StateUpdateDialogue not created" self.decision_maker.handle(state_update_message_1) assert (self.decision_maker_handler.context.ownership_state. amount_by_currency_id is not None) assert (self.decision_maker_handler.context.ownership_state. quantities_by_good_id is not None) assert (self.decision_maker_handler.context.preferences. exchange_params_by_currency_id is not None) assert (self.decision_maker_handler.context.preferences. utility_params_by_good_id is not None) state_update_message_2 = state_update_dialogue.reply( performative=StateUpdateMessage.Performative.APPLY, amount_by_currency_id=currency_deltas, quantities_by_good_id=good_deltas, ) self.decision_maker.handle(state_update_message_2) expected_amount_by_currency_id = { key: currency_holdings.get(key, 0) + currency_deltas.get(key, 0) for key in set(currency_holdings) | set(currency_deltas) } expected_quantities_by_good_id = { key: good_holdings.get(key, 0) + good_deltas.get(key, 0) for key in set(good_holdings) | set(good_deltas) } assert ( self.decision_maker_handler.context.ownership_state. amount_by_currency_id == expected_amount_by_currency_id ), "The amount_by_currency_id must be equal with the expected amount." assert (self.decision_maker_handler.context.ownership_state. quantities_by_good_id == expected_quantities_by_good_id)
def test_message_inconsistency(self): """Test for an error in consistency of a message.""" currency_endowment = {"FET": 100} good_endowment = {"a_good": 2} exchange_params = {"UNKNOWN": 10.0} utility_params = {"a_good": 20.0} with pytest.raises(ValueError, match="Field .* is not supported"): StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=currency_endowment, quantities_by_good_id=good_endowment, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, non_exists_field="some value", )
def test_serialization_initialize(self): """Test serialization of initialize message.""" currency_endowment = {"FET": 100} good_endowment = {"a_good": 2} exchange_params = {"FET": 10.0} utility_params = {"a_good": 20.0} msg = StateUpdateMessage( performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=currency_endowment, quantities_by_good_id=good_endowment, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, ) encoded_msg = msg.serializer.encode(msg) decoded_msg = msg.serializer.decode(encoded_msg) assert msg == decoded_msg
def test_light_protocol_rule_3_target_less_than_message_id(): """Test that if message_id is not 1, target must be > message_id""" with patch.object(_default_logger, "error") as mock_logger: currency_endowment = {"FET": 100} good_endowment = {"a_good": 2} exchange_params = {"FET": 10.0} utility_params = {"a_good": 20.0} message_id = 2 target = 2 assert StateUpdateMessage( message_id=message_id, target=target, performative=StateUpdateMessage.Performative.INITIALIZE, amount_by_currency_id=currency_endowment, quantities_by_good_id=good_endowment, exchange_params_by_currency_id=exchange_params, utility_params_by_good_id=utility_params, ) mock_logger.assert_any_call( f"Invalid 'target'. Expected an integer between 1 and {message_id - 1} inclusive. Found {target}." )