def test_response_callback_manager_with_invalid_callback_instance(self):
     cbm = callback_manager._ResponseCallbackManager()
     callback = MockEventCallback()
     with self.assertRaises(ValueError):
         cbm.add_callback("/test", callback)
     self.assertEqual(None, cbm.callbacks_by_channel.get("/test"))
     self.assertEqual(0, len(cbm.callbacks_by_channel))
 def test_response_callback_manager_with_double_registration(self):
     cbm = callback_manager._ResponseCallbackManager()
     cbm.add_callback("/test", MockResponseCallback)
     cbm.add_callback("/test", MockResponseCallback)
     self.assertEqual(1, len(cbm.callbacks_by_channel))
     cbm.remove_callback("/test", MockResponseCallback)
     self.assertEqual(0, len(cbm.callbacks_by_channel))
 def test_response_callback_manager_with_valid_callback(self):
     cbm = callback_manager._ResponseCallbackManager()
     cbm.add_callback("/test", MockResponseCallback)
     self.assertEqual(1, len(cbm.callbacks_by_channel.get("/test")))
     self.assertEqual(1, len(cbm.callbacks_by_channel))
     cbm.add_callback(callback=MockResponseCallback)
     self.assertEqual(1, len(cbm.callbacks_by_channel.get("")))
     self.assertEqual(2, len(cbm.callbacks_by_channel))
     cbm.remove_callback("/test", MockResponseCallback)
     self.assertEqual(None, cbm.callbacks_by_channel.get("/test"))
     self.assertEqual(1, len(cbm.callbacks_by_channel))
     cbm.remove_callback(callback=MockResponseCallback)
     self.assertEqual(None, cbm.callbacks_by_channel.get(""))
     self.assertEqual(0, len(cbm.callbacks_by_channel))
Example #4
0
    def __init__(self, config):
        """
        Constructor parameters:

        :param config: The :class:`dxlclient.client_config.DxlClientConfig` object containing the configuration
            settings for the client.
        """
        super(DxlClient, self).__init__()

        if config is None or not isinstance(config, DxlClientConfig):
            raise ValueError("Client configuration not specified")

        # The client configuration
        self._config = config
        # The lock for the client configuration
        self._config_lock = threading.RLock()
        # The condition associated with the client configuration
        self._config_lock_condition = threading.Condition(self._config_lock)

        # The flag for the connection state
        self._connected = False
        # The lock for the flag for the connection state
        self._connected_lock = threading.RLock()
        # The condition for the flag on connection state
        self._connected_wait_condition = threading.Condition(
            self._connected_lock)
        # The current broker the client is connected to
        self._current_broker = None
        # The lock for the current broker the client is connected to
        self._current_broker_lock = threading.RLock()

        # The default wait time for a synchronous request
        self._default_wait = self._DEFAULT_WAIT

        # The wait for policy delay (in seconds)
        self._wait_for_policy_delay = self._DEFAULT_WAIT_FOR_POLICY_DELAY

        # The minimum amount of threads in a thread pool
        self._core_pool_size = self._DEFAULT_MIN_POOL_SIZE
        # The maximum amount of threads in a thread pool
        self._maximum_pool_size = self._DEFAULT_MAX_POOL_SIZE

        # The quality of server (QOS) for messages
        self._qos = self._DEFAULT_QOS
        # The "reply-to" prefix. self is typically used for setting up response
        # channels for requests, etc.
        self._reply_to_topic = self._REPLY_TO_PREFIX + self._config._client_id

        # The request callbacks manager
        self._request_callbacks = callback_manager._RequestCallbackManager()
        # The response callbacks manager
        self._response_callbacks = callback_manager._ResponseCallbackManager()
        # The event callbacks manager
        self._event_callbacks = callback_manager._EventCallbackManager()

        # The current list of subscriptions
        self._subscriptions = set()
        # The lock for the current list of subscriptions
        self._subscriptions_lock = threading.RLock()

        # The underlying MQTT client instance
        self._client = mqtt.Client(client_id=self._config._client_id,
                                   clean_session=True,
                                   userdata=self,
                                   protocol=mqtt.MQTTv31)

        # The MQTT client connect callback
        self._client.on_connect = _on_connect
        # The MQTT client disconnect callback
        self._client.on_disconnect = _on_disconnect
        # The MQTT client message callback
        self._client.on_message = _on_message
        # The MQTT client log callback
        if logger.isEnabledFor(logging.DEBUG):
            self._client.on_log = _on_log

        # pylint: disable=no-member
        # The MQTT client TLS configuration
        self._client.tls_set(config.broker_ca_bundle,
                             certfile=config.cert_file,
                             keyfile=config.private_key,
                             cert_reqs=ssl.CERT_REQUIRED,
                             tls_version=ssl.PROTOCOL_SSLv23,
                             ciphers=None)
        # The MQTT client TLS configuration to bypass hostname validation
        self._client.tls_insecure_set(True)

        # Generate a message pool prefix
        self._message_pool_prefix = "DxlMessagePool-" + UuidGenerator.generate_id_as_string(
        )

        # The thread pool for message handling
        self._thread_pool = ThreadPool(
            num_threads=config.incoming_message_thread_pool_size,
            queue_size=config.incoming_message_queue_size,
            thread_prefix=self._message_pool_prefix)

        # Subscribe to the client reply channel
        self.subscribe(self._reply_to_topic)

        # The request manager (manages synchronous and asynchronous request callbacks,
        # notifications, etc.).
        self._request_manager = RequestManager(client=self)

        # The service manager (manages services request callbacks, notifications, etc.).
        self._service_manager = _ServiceManager(client=self)

        # The loop thread
        self._thread = None
        # The loop thread terminate flag
        self._thread_terminate = False

        # The lock for the connect thread
        self._connect_wait_lock = threading.RLock()
        # The condition associated with the client configuration
        self._connect_wait_condition = threading.Condition(
            self._connect_wait_lock)

        self._destroy_lock = threading.RLock()
        self._destroyed = False