Skip to content

Commit 60e3be7

Browse files
authored
Merge pull request #83 from mindsdb/test/STRC-198-update
updated integration tests
2 parents c4bf66f + 01c56b1 commit 60e3be7

File tree

11 files changed

+412
-215
lines changed

11 files changed

+412
-215
lines changed

.env.example

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# ----------------------------------
2+
# Integration Test Config
3+
# ----------------------------------
4+
5+
# Base URL
6+
MINDS_API_BASE_URL=<your base url>
7+
8+
# URL for the OpenAPI specification.
9+
MINDS_OPENAPI_SPEC_URL=<your base url>/openapi.json
10+
11+
# Authentication token, required
12+
MINDS_API_TOKEN=your_token

pytest.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[pytest]
2+
markers =
3+
happy_path: marks tests as part of the primary success path (end-to-end test)

requirements_test.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
pytest
2+
python-dotenv
3+
psycopg2-binary==2.9.10

tests/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# This can be empty, it just marks the directory as a Python package
2+
3+
__version__ = "0.1.0"

tests/integration/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# This can be empty, it just marks the directory as a Python package
2+
3+
__version__ = "0.1.0"

tests/integration/config.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# minds/tests/integration/config.py
2+
import logging
3+
import os
4+
5+
from dotenv import load_dotenv
6+
7+
# ===================================================================
8+
# 1. CONFIGURATION
9+
# ===================================================================
10+
11+
# Set up basic logging to output INFO level messages.
12+
logging.basicConfig(
13+
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
14+
)
15+
16+
# Load environment variables from a .env file if it exists.
17+
load_dotenv()
18+
19+
# --- API and Schema Configuration ---
20+
MINDS_API_BASE_URL = os.getenv("MINDS_API_BASE_URL") #
21+
MINDS_OPENAPI_SPEC_URL = os.getenv(
22+
"MINDS_OPENAPI_SPEC_URL", f"{MINDS_API_BASE_URL.strip('/')}/openapi.json"
23+
)
24+
AUTH_TOKEN = os.getenv("MINDS_API_TOKEN")
25+
26+
# --- DATASOURCE CONFIGURATIONS ---
27+
DATASOURCE_CONFIGS = []
28+
29+
# --- PostgreSQL Configuration (Reads from your existing PG_ environment variables) ---
30+
POSTGRES_CONFIG = {
31+
"host": os.getenv("PG_HOST", "samples.mindsdb.com"),
32+
"port": int(os.getenv("PG_PORT", 5432)),
33+
"user": os.getenv("PG_USER", "demo_user"),
34+
"password": os.getenv("PG_PASSWORD", "demo_password"),
35+
"database": os.getenv("PG_DB_NAME", "demo"),
36+
"schema": os.getenv("PG_SCHEMA", "demo"),
37+
}
38+
if all(POSTGRES_CONFIG.values()):
39+
DATASOURCE_CONFIGS.append(
40+
{
41+
"engine": "postgres",
42+
"name_prefix": "test_pg_ds",
43+
"connection_data": POSTGRES_CONFIG,
44+
"sample_table": "house_sales", # A known table in the demo PG database
45+
}
46+
)
47+
48+
# --- Snowflake Configuration (Only enabled if all credentials are provided) ---
49+
SNOWFLAKE_CONFIG = {
50+
"account": os.getenv("SNOWFLAKE_ACCOUNT"),
51+
"user": os.getenv("SNOWFLAKE_USER"),
52+
"password": os.getenv("SNOWFLAKE_PASSWORD"),
53+
"schema": os.getenv("SNOWFLAKE_SCHEMA"),
54+
"database": os.getenv("SNOWFLAKE_DATABASE"),
55+
"warehouse": os.getenv("SNOWFLAKE_WAREHOUSE"),
56+
}
57+
if all(SNOWFLAKE_CONFIG.values()):
58+
DATASOURCE_CONFIGS.append(
59+
{
60+
"engine": "snowflake",
61+
"name_prefix": "test-sf-ds",
62+
"connection_data": SNOWFLAKE_CONFIG,
63+
"sample_table": "CUSTOMER",
64+
}
65+
)

tests/integration/conftest.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import logging
2+
import pytest
3+
import time
4+
import psycopg2
5+
6+
from minds.client import Client
7+
from minds.exceptions import ObjectNotFound
8+
from . import config
9+
10+
logging.basicConfig(
11+
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
12+
)
13+
14+
15+
@pytest.fixture(scope="session")
16+
def db_ground_truth():
17+
"""
18+
Connects directly to the PG database to fetch the true max values for assertions,
19+
making tests resilient to data changes.
20+
"""
21+
conn = None
22+
try:
23+
# Use a dictionary of connection parameters that psycopg2 expects
24+
conn_params = {
25+
"dbname": config.POSTGRES_CONFIG["database"],
26+
"user": config.POSTGRES_CONFIG["user"],
27+
"password": config.POSTGRES_CONFIG["password"],
28+
"host": config.POSTGRES_CONFIG["host"],
29+
"port": config.POSTGRES_CONFIG["port"],
30+
}
31+
conn = psycopg2.connect(**conn_params)
32+
cur = conn.cursor()
33+
34+
# Fully qualify the table name with its schema ('demo_data') to resolve the "relation does not exist" error.
35+
cur.execute("SELECT MAX(rental_price) FROM demo_data.home_rentals;")
36+
max_rental_price = cur.fetchone()[0]
37+
38+
cur.close()
39+
logging.info(
40+
f"Fetched ground truth from DB: max_rental_price={max_rental_price}"
41+
)
42+
return {"max_rental_price": max_rental_price}
43+
except Exception as e:
44+
pytest.skip(f"Could not connect to PG database to get ground truth: {e}")
45+
finally:
46+
if conn:
47+
conn.close()
48+
49+
50+
@pytest.fixture(scope="session")
51+
def sdk_client() -> Client:
52+
"""Initialize a Minds Client using centralized config."""
53+
logging.info(f"Connecting to Minds API at {config.MINDS_API_BASE_URL}")
54+
client = Client(api_key=config.AUTH_TOKEN, base_url=config.MINDS_API_BASE_URL)
55+
return client
56+
57+
58+
@pytest.fixture(scope="function")
59+
def sdk_datasource(sdk_client: Client):
60+
"""Creates a temporary datasource for test use and cleans it up."""
61+
timestamp = str(int(time.time()))[-6:]
62+
ds_base = config.DATASOURCE_CONFIGS[0]
63+
ds_name = f"{ds_base['name_prefix']}_{timestamp}"
64+
65+
ds_config = {
66+
"name": ds_name,
67+
"engine": ds_base["engine"],
68+
"connection_data": ds_base["connection_data"],
69+
"description": "Temporary test datasource",
70+
}
71+
72+
logging.info(f"Creating test datasource {ds_name}")
73+
ds = sdk_client.datasources.create(**ds_config)
74+
75+
yield ds # make datasource available to tests
76+
77+
# Cleanup
78+
logging.info(f"Dropping test datasource {ds_name}")
79+
try:
80+
sdk_client.datasources.drop(ds_name)
81+
except ObjectNotFound:
82+
logging.warning(f"Datasource {ds_name} already removed.")
83+
84+
85+
@pytest.fixture(scope="function")
86+
def sdk_mind(sdk_client: Client, sdk_datasource):
87+
"""Creates a temporary mind for test use and cleans it up."""
88+
timestamp = int(time.time())
89+
mind_name = f"test_mind_{timestamp}"
90+
91+
logging.info(
92+
f"Creating test mind {mind_name} with datasource {sdk_datasource.name}"
93+
)
94+
# Create the mind with 'home_rentals' from the start.
95+
sdk_client.minds.create(
96+
mind_name,
97+
datasources=[{"name": sdk_datasource.name, "tables": ["home_rentals"]}],
98+
provider="openai",
99+
)
100+
101+
yield mind_name
102+
103+
# Cleanup
104+
mind_name_upd = f"{mind_name}_upd"
105+
logging.info(f"Dropping test mind {mind_name_upd}")
106+
try:
107+
sdk_client.minds.drop(mind_name_upd)
108+
except ObjectNotFound:
109+
# Also try dropping the original name in case the test failed before the update
110+
try:
111+
sdk_client.minds.drop(mind_name)
112+
except ObjectNotFound:
113+
logging.warning(f"Mind {mind_name} or {mind_name_upd} already removed.")

0 commit comments

Comments
 (0)