Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow to register agents after activation of container #132

Merged
merged 1 commit into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions mango/container/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(
self._aid_counter: int = 0 # counter for aids

self.running: bool = False # True until self.shutdown() is called
self.ready: bool = False # True after self.on_ready() is called

# inbox for all incoming messages
self.inbox: asyncio.Queue = None
Expand Down Expand Up @@ -123,6 +124,11 @@ def register(self, agent: Agent, suggested_aid: str = None):
self._agents[aid] = agent
agent._do_register(self, aid)
logger.debug("Successfully registered agent;%s", aid)
if self.running:
agent._do_start()

if self.ready:
agent.on_ready()
return agent

def _get_aid(self, agent):
Expand Down Expand Up @@ -290,6 +296,8 @@ def dispatch_to_agent_process(self, pid: int, coro_func, *args):
self._container_process_manager.dispatch_to_agent_process(pid, coro_func, *args)

async def start(self):
if self.running:
raise RuntimeError("Container is already running")
self.running: bool = True # True until self.shutdown() is called

# inbox for all incoming messages
Expand All @@ -303,6 +311,9 @@ async def start(self):
agent._do_start()

def on_ready(self):
if self.ready:
raise RuntimeError("Container is already ready")
self.ready = True
for agent in self._agents.values():
agent.on_ready()

Expand Down
1 change: 0 additions & 1 deletion mango/container/external_coupling.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ def __init__(
**kwargs,
)

self.running = True
self.current_start_time_of_step = time.time()
self._new_internal_message: bool = False
self.message_buffer = []
Expand Down
1 change: 0 additions & 1 deletion mango/container/tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ def __init__(

self._tcp_connection_pool = None
self.server = None # will be set within start
self.running = False
self._tcp_connection_pool = TCPConnectionPool(
ttl_in_sec=self._kwargs.get(TCP_CONNECTION_TTL, 30),
max_connections_per_target=self._kwargs.get(
Expand Down
18 changes: 13 additions & 5 deletions tests/unit_tests/core/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,21 @@ async def test_schedule_acl_message():
assert agent2.test_counter == 1


def test_register_twice():
@pytest.mark.asyncio
async def test_delayed_agent_creation():
# GIVEN
c = create_tcp_container(addr=("127.0.0.1", 5555))
agent = MyAgent()
c.register(agent)
agent = c.register(MyAgent())

with pytest.raises(ValueError):
c.register(agent)
async with activate(c) as c:
agent2 = c.register(MyAgent())
await agent.schedule_instant_message(
create_acl("", receiver_addr=agent2.addr, sender_addr=agent.addr),
receiver_addr=agent2.addr,
)

# THEN
assert agent2.test_counter == 1


def test_sync_setup_agent():
Expand Down
98 changes: 98 additions & 0 deletions tests/unit_tests/core/test_agent_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from typing import Any

import pytest

from mango import activate, create_ec_container
from mango.agent.core import Agent


class MyAgent(Agent):
test_counter: int = 0
ready = False
started = False
registered = False

def handle_message(self, content, meta: dict[str, Any]):
self.test_counter += 1

def on_ready(self):
self.ready = True

def on_start(self):
self.started = True

def on_register(self):
self.registered = True


def test_register_twice():
c = create_ec_container()
agent = MyAgent()
c.register(agent)

with pytest.raises(ValueError):
c.register(agent)


@pytest.mark.asyncio
async def test_ready_twice():
c = create_ec_container()
agent = MyAgent()
c.register(agent)

await c.start()
c.on_ready()

with pytest.raises(RuntimeError):
c.on_ready()

await c.shutdown()


@pytest.mark.asyncio
async def test_start_twice():
c = create_ec_container()
agent = MyAgent()
c.register(agent)

await c.start()
with pytest.raises(RuntimeError):
await c.start()

await c.shutdown()


@pytest.mark.asyncio
async def test_agent_state():
# GIVEN
c = create_ec_container()
agent = MyAgent()
assert agent.registered is False
assert agent.started is False
assert agent.ready is False

# WHEN
c.register(agent)

# THEN
assert agent.registered is True
assert agent.started is False
assert agent.ready is False

async with activate(c) as c:
assert agent.started is True
assert agent.ready is True


@pytest.mark.asyncio
async def test_delayed_agent_state():
# GIVEN
c = create_ec_container()

async with activate(c) as c:
agent = MyAgent()
assert agent.registered is False
c.register(agent)
assert agent.registered is True
assert agent.started is True
assert agent.ready is True