Skip to content

Commit

Permalink
Refactor service_name handling for simplicity
Browse files Browse the repository at this point in the history
Add `ready` property to check IrisConnector status
Update dependencies
Resolve unit test failure
Add test coverage for `IrisConnector`
  • Loading branch information
NeonDaniel committed Jan 25, 2025
1 parent 99ba1c6 commit b2040ac
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 10 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ ENV EXTRAS=${EXTRAS}
RUN mkdir -p /neon_iris/requirements
COPY ./requirements/* /neon_iris/requirements

RUN apt-get update && apt-get install -y git
RUN pip install wheel && pip install -r /neon_iris/requirements/requirements.txt
RUN if [ "$EXTRAS" = "gradio" ]; then \
pip install -r /neon_iris/requirements/gradio.txt; \
Expand Down
3 changes: 1 addition & 2 deletions neon_iris/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,7 @@ def _send_serialized_message(self, serialized: dict):

def _init_mq_connection(self):
mq_config = self._config.get("MQ") or self._config
mq_connection = IrisConnector(vhost=self._vhost, config=mq_config,
service_name="mq_handler")
mq_connection = IrisConnector(vhost=self._vhost, config=mq_config)
mq_connection.register_consumer("neon_response_handler", self._vhost,
self.uid, self.handle_neon_response,
auto_ack=False)
Expand Down
11 changes: 9 additions & 2 deletions neon_iris/mq_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class IrisConnector(MQConnector, Thread):

def __init__(self, *args, **kwargs):
vhost = kwargs.pop('vhost')
# TODO: service_name chosen for backwards-compat. and should be updated
# to something more descriptive
kwargs['service_name'] = 'mq_handler'
Thread.__init__(self, daemon=True)
MQConnector.__init__(self, *args, **kwargs)
self.vhost = vhost
Expand All @@ -62,8 +65,12 @@ def connection(self) -> SelectConnection:
self._connection = self.init_connection()
return self._connection

@property
def ready(self) -> bool:
return self._ready.is_set()

def run(self, *args, **kwargs):
MQConnector.run(self, daemonize_consumers=True)
MQConnector.run(self)
self._connection.ioloop.start()

def init_connection(self) -> SelectConnection:
Expand Down Expand Up @@ -124,7 +131,7 @@ def shutdown(self):

if self.connection:
self.connection.ioloop.stop()
# self.connection = None
self._ready.clear()

except Exception as e:
LOG.error(f"Failed to close connection: {e}")
7 changes: 3 additions & 4 deletions requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
click~=8.0
click-default-group~=1.2
neon-utils~=1.12
neon-utils[sentry]~=1.12
pyyaml>=5.4,<7.0.0
#neon-mq-connector~=0.7,>=0.7.2a11
neon-mq-connector@git+https://github.com/neongeckocom/neon_mq_connector@FEAT_SupportSelectConnections
ovos-bus-client~=0.0,>=0.0.3,<0.2.0
neon-mq-connector~=0.7,>=0.7.2a12
ovos-bus-client~=0.0
ovos-config~=0.1,<0.2.0
4 changes: 2 additions & 2 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import sys
import unittest

from neon_mq_connector.utils.client_utils import NeonMQHandler
from neon_iris.mq_connector import IrisConnector

sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
from neon_iris.client import NeonAIClient
Expand All @@ -57,7 +57,7 @@ def test_client_create(self):
self.assertEqual(client._connection.config, _test_config["MQ"])
self.assertTrue(os.path.isdir(client.audio_cache_dir))
self.assertIsInstance(client.client_name, str)
self.assertIsInstance(client.connection, NeonMQHandler)
self.assertIsInstance(client.connection, IrisConnector)
self.assertEqual(client.connection.vhost, "/neon_chat_api")
client.shutdown()

Expand Down
77 changes: 77 additions & 0 deletions tests/test_mq_connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
# All trademark and other rights reserved by their respective owners
# Copyright 2008-2022 Neongecko.com Inc.
# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
# BSD-3 License
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


import unittest
from threading import Thread

import pytest

from os import environ
from neon_minerva.integration.rabbit_mq import rmq_instance
from neon_mq_connector import MQConnector
from pika.adapters.select_connection import SelectConnection

environ['TEST_RMQ_USERNAME'] = "test_user"
environ['TEST_RMQ_PASSWORD'] = "test_password"
environ['TEST_RMQ_VHOSTS'] = "/neon_chat_api"


@pytest.mark.usefixtures("rmq_instance")
class TestClient(unittest.TestCase):
mq_config = {"server": "localhost",
"port": None,
"users": {"mq_handler": {"user": "test_user",
"password": "test_password"}}}

def setUp(self):
if self.mq_config["port"] is None:
self.mq_config["port"] = self.rmq_instance.port

def test_lifecycle(self):
from neon_iris.mq_connector import IrisConnector
connector = IrisConnector(vhost="/neon_chat_api", config=self.mq_config)
self.assertIsInstance(connector, MQConnector)
self.assertIsInstance(connector.connection, SelectConnection)
self.assertFalse(connector.ready)

# Start the connector
thread = Thread(target=connector.run)
thread.start()
connector.wait_for_connection()
self.assertTrue(connector.ready)

# Stop the connector
connector.shutdown()
self.assertFalse(connector.ready)
thread.join(timeout=5)
self.assertFalse(thread.is_alive())


if __name__ == '__main__':
unittest.main()

0 comments on commit b2040ac

Please sign in to comment.