Skip to content

Commit

Permalink
Add Tests & Improve Correctness Of Implementation (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
Iapetus-11 authored Jan 19, 2025
1 parent e49e3e7 commit 272091b
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 13 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ jobs:
run: poetry run ruff check . --no-fix

- name: Run Ruff formatter
run: poetry run ruff format . --check
run: poetry run ruff format . --check

- name: Run tests
run: poetry run pytest
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"python.analysis.extraPaths": [
"./tests"
]
}
15 changes: 7 additions & 8 deletions aiomcrcon/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ class MessageType(enum.IntEnum):
LOGIN = 3
COMMAND = 2
RESPONSE = 0
INVALID_AUTH = -1


class Client:
Expand Down Expand Up @@ -55,7 +54,7 @@ async def connect(self, timeout: float = 2.0) -> None:
except Exception as e:
raise RCONConnectionError("The connection failed for an unknown reason.", e)

await self._send_msg(MessageType.LOGIN, self.password)
await asyncio.wait_for(self._send_msg(MessageType.LOGIN, self.password), timeout)

self._ready = True

Expand All @@ -72,14 +71,14 @@ async def _read(self, n: int) -> bytes:

return out

async def _send_msg(self, type_: int, msg: str) -> t.Tuple[str, int]:
async def _send_msg(self, msg_type: int, msg: str) -> tuple[str, int]:
"""Sends data to the server, and returns the response."""

# randomly generate request id
req_id = random.randint(0, 2147483647)

# pack request id, packet type, and the actual message
packet_data = struct.pack("<ii", req_id, type_) + msg.encode("utf8") + b"\x00\x00"
packet_data = struct.pack("<ii", req_id, msg_type) + msg.encode("utf8") + b"\x00\x00"

# pack length of packet + rest of packet data
packet = struct.pack("<i", len(packet_data)) + packet_data
Expand All @@ -98,17 +97,17 @@ async def _send_msg(self, type_: int, msg: str) -> t.Tuple[str, int]:
raise ValueError("Invalid data received from server.")

# decode the incoming request id and packet type
in_type, in_req_id = struct.unpack("<ii", in_data[0:8])
in_req_id, in_type = struct.unpack("<ii", in_data[0:8])

if in_type == MessageType.INVALID_AUTH:
if in_req_id == -1:
raise IncorrectPasswordError

# decode the received message
in_msg = in_data[8:-2].decode("utf8")

return in_msg, in_type
return in_msg, in_req_id

async def send_cmd(self, cmd: str, timeout: float = 2.0) -> t.Tuple[str, int]:
async def send_cmd(self, cmd: str, timeout: float = 2.0) -> tuple[str, int]:
"""Sends a command to the server."""

if not self._ready:
Expand Down
4 changes: 2 additions & 2 deletions aiomcrcon/errors.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import typing as t
from __future__ import annotations


class RCONConnectionError(Exception):
"""Raised when the Client.connect() method fails."""

def __init__(self, msg: t.Optional[str] = None, error: t.Optional[Exception] = None) -> None:
def __init__(self, msg: str | None = None, error: Exception | None = None) -> None:
super().__init__(msg)

self.message = msg
Expand Down
156 changes: 155 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "aio-mc-rcon"
version = "3.3.0"
version = "3.4.0"
description = "An async library for utilizing remote console on Minecraft Java Edition servers"
authors = ["Milo Weinberg <iapetus011@gmail.com>"]
license = "MIT"
Expand All @@ -14,6 +14,8 @@ python = ">=3.9,<4.0"

[tool.poetry.group.dev.dependencies]
ruff = "^0.9.2"
pytest = "^8.3.4"
pytest-asyncio = "^0.25.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
Expand All @@ -22,3 +24,7 @@ build-backend = "poetry.core.masonry.api"
[tool.ruff]
line-length = 100
target-version = "py39"

[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
28 changes: 28 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

from aiomcrcon.client import Client
from rcon_server import Server


@pytest.fixture
async def dummy_server(unused_tcp_port):
server = Server(
host="localhost",
port=unused_tcp_port,
password="hunter2",
)

await server.start()

yield server

await server.close()


@pytest.fixture
def client(dummy_server):
return Client(
host=dummy_server.host,
port=dummy_server.port,
password=dummy_server.password,
)
Loading

0 comments on commit 272091b

Please sign in to comment.