Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit 67873f1

Browse files
committed
add ci tests
1 parent b405a7f commit 67873f1

File tree

6 files changed

+188
-4
lines changed

6 files changed

+188
-4
lines changed

.github/workflows/ci.yaml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
services:
14+
clickhouse:
15+
image: clickhouse/clickhouse-server:24.10
16+
ports:
17+
- 9000:9000
18+
- 8123:8123
19+
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v4
23+
24+
- name: Install uv
25+
uses: astral-sh/setup-uv@v4
26+
27+
- name: Setup Python
28+
run: uv python install 3.13
29+
30+
- name: Install Project
31+
run: uv sync
32+
33+
# Wait for ClickHouse to be ready
34+
- name: Wait for ClickHouse service
35+
run: |
36+
for i in {1..30}; do
37+
if clickhouse-client --query "SELECT 1"; then
38+
echo "ClickHouse is ready"
39+
exit 0
40+
fi
41+
echo "Waiting for ClickHouse to be ready..."
42+
sleep 2
43+
done
44+
echo "ClickHouse did not become ready in time" && exit 1
45+
46+
- name: Run tests
47+
env:
48+
CLICKHOUSE_HOST: "localhost"
49+
CLICKHOUSE_PORT: "8123"
50+
CLICKHOUSE_USER: "default"
51+
CLICKHOUSE_PASSWORD: ""
52+
run: |
53+
uv run pytest tests
54+
55+
- name: Lint with Ruff
56+
run: ruff check .

mcp_clickhouse/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from .mcp_server import (
2+
list_databases,
3+
list_tables,
4+
run_select_query,
5+
create_clickhouse_client,
6+
)
7+
8+
__all__ = [
9+
"list_databases",
10+
"list_tables",
11+
"run_select_query",
12+
"create_clickhouse_client",
13+
]

mcp_clickhouse/mcp_server.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@
1010

1111
# Configure logging
1212
logging.basicConfig(
13-
level=logging.INFO,
14-
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
13+
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
1514
)
1615
logger = logging.getLogger(MCP_SERVER_NAME)
1716

1817
load_dotenv()
1918

2019
deps = [
21-
"clickhouse-connect",
20+
"clickhouse-connect",
2221
"python-dotenv",
2322
"uvicorn",
2423
]

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ Home = "https://github.com/iskakaushik/mcp-clickhouse"
2020

2121
[project.optional-dependencies]
2222
dev = [
23-
"ruff"
23+
"ruff",
24+
"pytest"
2425
]
2526

2627
[tool.hatch.build.targets.wheel]

tests/test_tool.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import unittest
2+
from dotenv import load_dotenv
3+
from mcp_clickhouse import list_databases, list_tables, run_select_query, create_clickhouse_client
4+
5+
load_dotenv()
6+
7+
8+
class TestClickhouseTools(unittest.TestCase):
9+
@classmethod
10+
def setUpClass(cls):
11+
"""Set up the environment before tests."""
12+
cls.client = create_clickhouse_client()
13+
14+
# Prepare test database and table
15+
cls.test_db = "test_tool_db"
16+
cls.test_table = "test_table"
17+
cls.client.command(f"CREATE DATABASE IF NOT EXISTS {cls.test_db}")
18+
cls.client.command(f"""
19+
CREATE TABLE IF NOT EXISTS {cls.test_db}.{cls.test_table} (
20+
id UInt32,
21+
name String
22+
) ENGINE = MergeTree()
23+
ORDER BY id
24+
""")
25+
cls.client.command(f"""
26+
INSERT INTO {cls.test_db}.{cls.test_table} (id, name) VALUES (1, 'Alice'), (2, 'Bob')
27+
""")
28+
29+
@classmethod
30+
def tearDownClass(cls):
31+
"""Clean up the environment after tests."""
32+
cls.client.command(f"DROP DATABASE IF EXISTS {cls.test_db}")
33+
34+
def test_list_databases(self):
35+
"""Test listing databases."""
36+
result = list_databases()
37+
self.assertIn(self.test_db, result)
38+
39+
def test_list_tables_without_like(self):
40+
"""Test listing tables without a 'LIKE' filter."""
41+
result = list_tables(self.test_db)
42+
self.assertIsInstance(result, list)
43+
self.assertEqual(len(result), 1)
44+
self.assertEqual(result[0]["name"], self.test_table)
45+
46+
def test_list_tables_with_like(self):
47+
"""Test listing tables with a 'LIKE' filter."""
48+
result = list_tables(self.test_db, like=f"{self.test_table}%")
49+
self.assertIsInstance(result, list)
50+
self.assertEqual(len(result), 1)
51+
self.assertEqual(result[0]["name"], self.test_table)
52+
53+
def test_run_select_query_success(self):
54+
"""Test running a SELECT query successfully."""
55+
query = f"SELECT * FROM {self.test_db}.{self.test_table}"
56+
result = run_select_query(query)
57+
self.assertIsInstance(result, list)
58+
self.assertEqual(len(result), 2)
59+
self.assertEqual(result[0]["id"], 1)
60+
self.assertEqual(result[0]["name"], "Alice")
61+
62+
def test_run_select_query_failure(self):
63+
"""Test running a SELECT query with an error."""
64+
query = f"SELECT * FROM {self.test_db}.non_existent_table"
65+
result = run_select_query(query)
66+
self.assertIsInstance(result, str)
67+
self.assertIn("error running query", result)
68+
69+
70+
if __name__ == "__main__":
71+
unittest.main()

uv.lock

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)