Skip to content

Commit e137b22

Browse files
committed
test: add CloudConfiguration integration tests for Feature 058
Comprehensive integration tests against real IRIS database covering: - ConnectionManager with environment variables (IRIS_HOST, IRIS_PORT, etc.) - SchemaManager dimension configuration with VECTOR_DIMENSION env var - Configuration priority chain validation (env > config > defaults) - End-to-end configuration flow from environment to database Test Results: - 9/9 integration tests passing - Tests verify real IRIS connections and table creation - Tests validate vector dimension metadata in INFORMATION_SCHEMA - Tests confirm environment variables override config files Related: Feature 058 Cloud Configuration Flexibility
1 parent 9407dc4 commit e137b22

File tree

1 file changed

+399
-0
lines changed

1 file changed

+399
-0
lines changed
Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
"""
2+
Integration tests for Feature 058: Cloud Configuration System
3+
4+
Tests real IRIS database operations with CloudConfiguration API:
5+
- ConnectionManager with environment variables
6+
- SchemaManager dimension configuration
7+
- Complete configuration priority chain (env > config > defaults)
8+
"""
9+
10+
import os
11+
import pytest
12+
import tempfile
13+
import yaml
14+
from unittest.mock import patch
15+
16+
17+
@pytest.mark.integration
18+
class TestConnectionManagerIntegration:
19+
"""Test ConnectionManager with CloudConfiguration and IRIS database"""
20+
21+
def test_connection_manager_reads_env_vars(self):
22+
"""
23+
GIVEN IRIS connection environment variables set
24+
WHEN ConnectionManager initializes with CloudConfiguration
25+
THEN connections use environment variable values
26+
"""
27+
with patch.dict(os.environ, {
28+
'IRIS_HOST': 'localhost',
29+
'IRIS_PORT': '1972',
30+
'IRIS_USERNAME': '_SYSTEM',
31+
'IRIS_PASSWORD': 'SYS',
32+
'IRIS_NAMESPACE': 'USER'
33+
}, clear=False):
34+
from iris_vector_rag.config.manager import ConfigurationManager
35+
from iris_vector_rag.common.connection_manager import ConnectionManager
36+
37+
config_manager = ConfigurationManager()
38+
cloud_config = config_manager.get_cloud_config()
39+
40+
# Verify cloud config reads environment variables
41+
assert cloud_config.connection.host == 'localhost'
42+
assert cloud_config.connection.port == 1972
43+
assert cloud_config.connection.namespace == 'USER'
44+
assert cloud_config.connection.username == '_SYSTEM'
45+
46+
# Verify sources tracked correctly
47+
assert cloud_config.connection.source['host'].value == 'environment'
48+
assert cloud_config.connection.source['port'].value == 'environment'
49+
50+
def test_connection_to_real_iris_database(self):
51+
"""
52+
GIVEN IRIS database running on localhost:1972
53+
WHEN creating connection via CloudConfiguration
54+
THEN connection succeeds and can query database
55+
"""
56+
import iris.dbapi as iris_dbapi
57+
from iris_vector_rag.config.manager import ConfigurationManager
58+
59+
config_manager = ConfigurationManager()
60+
cloud_config = config_manager.get_cloud_config()
61+
62+
# Create connection using cloud config values
63+
conn = iris_dbapi.connect(
64+
hostname=cloud_config.connection.host,
65+
port=cloud_config.connection.port,
66+
namespace=cloud_config.connection.namespace,
67+
username=cloud_config.connection.username,
68+
password=cloud_config.connection.password
69+
)
70+
71+
try:
72+
cursor = conn.cursor()
73+
cursor.execute("SELECT 1")
74+
result = cursor.fetchone()
75+
assert result[0] == 1
76+
77+
# Test namespace is accessible
78+
cursor.execute("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES")
79+
table_count = cursor.fetchone()[0]
80+
assert table_count > 0
81+
82+
cursor.close()
83+
finally:
84+
conn.close()
85+
86+
87+
@pytest.mark.integration
88+
class TestSchemaManagerIntegration:
89+
"""Test SchemaManager dimension configuration with IRIS database"""
90+
91+
def test_schema_manager_reads_default_dimension(self):
92+
"""
93+
GIVEN no VECTOR_DIMENSION environment variable
94+
WHEN SchemaManager initializes
95+
THEN uses default 384 dimensions
96+
"""
97+
# Clear VECTOR_DIMENSION if set
98+
env_copy = {k: v for k, v in os.environ.items() if k != 'VECTOR_DIMENSION'}
99+
100+
with patch.dict(os.environ, env_copy, clear=True):
101+
from iris_vector_rag.config.manager import ConfigurationManager
102+
103+
config_manager = ConfigurationManager()
104+
cloud_config = config_manager.get_cloud_config()
105+
106+
assert cloud_config.vector.vector_dimension == 384
107+
assert cloud_config.vector.source['vector_dimension'].value in ('default', 'config_file')
108+
109+
def test_schema_manager_reads_env_var_dimension(self):
110+
"""
111+
GIVEN VECTOR_DIMENSION=1024 environment variable
112+
WHEN SchemaManager initializes
113+
THEN uses 1024 dimensions from environment
114+
"""
115+
with patch.dict(os.environ, {'VECTOR_DIMENSION': '1024'}, clear=False):
116+
from iris_vector_rag.config.manager import ConfigurationManager
117+
118+
config_manager = ConfigurationManager()
119+
cloud_config = config_manager.get_cloud_config()
120+
121+
assert cloud_config.vector.vector_dimension == 1024
122+
assert cloud_config.vector.source['vector_dimension'].value == 'environment'
123+
124+
def test_schema_manager_creates_correct_vector_columns(self):
125+
"""
126+
GIVEN VECTOR_DIMENSION=512 environment variable
127+
WHEN SchemaManager creates test table
128+
THEN table has VECTOR(DOUBLE, 512) column
129+
"""
130+
with patch.dict(os.environ, {'VECTOR_DIMENSION': '512'}, clear=False):
131+
import iris.dbapi as iris_dbapi
132+
from iris_vector_rag.config.manager import ConfigurationManager
133+
134+
config_manager = ConfigurationManager()
135+
cloud_config = config_manager.get_cloud_config()
136+
137+
# Verify configuration
138+
assert cloud_config.vector.vector_dimension == 512
139+
140+
# Connect to database
141+
conn = iris_dbapi.connect(
142+
hostname='localhost',
143+
port=1972,
144+
namespace='USER',
145+
username='_SYSTEM',
146+
password='SYS'
147+
)
148+
149+
try:
150+
cursor = conn.cursor()
151+
152+
# Create test table with configured dimension
153+
table_name = "RAG.TestVectorDim512"
154+
cursor.execute(f"DROP TABLE IF EXISTS {table_name}")
155+
156+
create_sql = f"""
157+
CREATE TABLE {table_name} (
158+
id VARCHAR(255) PRIMARY KEY,
159+
embedding VECTOR(DOUBLE, {cloud_config.vector.vector_dimension})
160+
)
161+
"""
162+
cursor.execute(create_sql)
163+
conn.commit()
164+
165+
# Verify column dimension using INFORMATION_SCHEMA
166+
cursor.execute("""
167+
SELECT CHARACTER_MAXIMUM_LENGTH
168+
FROM INFORMATION_SCHEMA.COLUMNS
169+
WHERE TABLE_SCHEMA = 'RAG'
170+
AND TABLE_NAME = 'TestVectorDim512'
171+
AND COLUMN_NAME = 'embedding'
172+
""")
173+
174+
byte_length = cursor.fetchone()[0]
175+
# Formula: dimensions = round(CHARACTER_MAXIMUM_LENGTH / 346)
176+
actual_dim = round(byte_length / 346)
177+
178+
assert actual_dim == 512, f"Expected 512 dimensions, got {actual_dim}"
179+
180+
# Cleanup
181+
cursor.execute(f"DROP TABLE {table_name}")
182+
conn.commit()
183+
cursor.close()
184+
185+
finally:
186+
conn.close()
187+
188+
189+
@pytest.mark.integration
190+
class TestConfigurationPriorityChain:
191+
"""Test configuration priority: env > config > defaults"""
192+
193+
def test_environment_overrides_config_file(self):
194+
"""
195+
GIVEN config file with vector_dimension=768
196+
AND VECTOR_DIMENSION=1536 environment variable
197+
WHEN ConfigurationManager loads
198+
THEN environment variable takes precedence
199+
"""
200+
# Create temporary config file (must include required database config)
201+
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
202+
yaml.dump({
203+
'database': {
204+
'iris': {
205+
'host': 'localhost',
206+
'port': 1972,
207+
'namespace': 'USER',
208+
'username': '_SYSTEM',
209+
'password': 'SYS'
210+
}
211+
},
212+
'storage': {
213+
'iris': {
214+
'vector_dimension': 768
215+
}
216+
}
217+
}, f)
218+
config_path = f.name
219+
220+
try:
221+
with patch.dict(os.environ, {'VECTOR_DIMENSION': '1536'}, clear=False):
222+
from iris_vector_rag.config.manager import ConfigurationManager
223+
224+
config_manager = ConfigurationManager(config_path=config_path)
225+
cloud_config = config_manager.get_cloud_config()
226+
227+
# Environment should override config file
228+
assert cloud_config.vector.vector_dimension == 1536
229+
assert cloud_config.vector.source['vector_dimension'].value == 'environment'
230+
finally:
231+
os.unlink(config_path)
232+
233+
def test_config_file_overrides_defaults(self):
234+
"""
235+
GIVEN config file with vector_dimension=2048
236+
AND no VECTOR_DIMENSION environment variable
237+
WHEN ConfigurationManager loads
238+
THEN config file value used
239+
"""
240+
# Create temporary config file (must include required database config)
241+
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
242+
yaml.dump({
243+
'database': {
244+
'iris': {
245+
'host': 'localhost',
246+
'port': 1972,
247+
'namespace': 'USER',
248+
'username': '_SYSTEM',
249+
'password': 'SYS'
250+
}
251+
},
252+
'storage': {
253+
'vector_dimension': 2048
254+
}
255+
}, f)
256+
config_path = f.name
257+
258+
try:
259+
# Clear VECTOR_DIMENSION env var
260+
env_copy = {k: v for k, v in os.environ.items() if k != 'VECTOR_DIMENSION'}
261+
262+
with patch.dict(os.environ, env_copy, clear=True):
263+
from iris_vector_rag.config.manager import ConfigurationManager
264+
265+
config_manager = ConfigurationManager(config_path=config_path)
266+
cloud_config = config_manager.get_cloud_config()
267+
268+
# Config file should override defaults
269+
assert cloud_config.vector.vector_dimension == 2048
270+
assert cloud_config.vector.source['vector_dimension'].value == 'config_file'
271+
finally:
272+
os.unlink(config_path)
273+
274+
def test_defaults_used_when_no_overrides(self):
275+
"""
276+
GIVEN no config file
277+
AND no VECTOR_DIMENSION environment variable
278+
WHEN ConfigurationManager loads
279+
THEN default 384 dimensions used
280+
"""
281+
# Clear VECTOR_DIMENSION env var
282+
env_copy = {k: v for k, v in os.environ.items() if k != 'VECTOR_DIMENSION'}
283+
284+
with patch.dict(os.environ, env_copy, clear=True):
285+
from iris_vector_rag.config.manager import ConfigurationManager
286+
287+
config_manager = ConfigurationManager()
288+
cloud_config = config_manager.get_cloud_config()
289+
290+
# Should use defaults
291+
assert cloud_config.vector.vector_dimension == 384
292+
assert cloud_config.vector.source['vector_dimension'].value in ('default', 'config_file')
293+
294+
295+
@pytest.mark.integration
296+
class TestCompleteConfigurationFlow:
297+
"""Test complete configuration flow from environment to database"""
298+
299+
def test_end_to_end_config_to_database(self):
300+
"""
301+
GIVEN complete environment configuration
302+
WHEN system initializes and creates tables
303+
THEN all configuration flows correctly to database
304+
"""
305+
test_env = {
306+
'IRIS_HOST': 'localhost',
307+
'IRIS_PORT': '1972',
308+
'IRIS_NAMESPACE': 'USER',
309+
'IRIS_USERNAME': '_SYSTEM',
310+
'IRIS_PASSWORD': 'SYS',
311+
'VECTOR_DIMENSION': '256',
312+
'TABLE_SCHEMA': 'RAG'
313+
}
314+
315+
with patch.dict(os.environ, test_env, clear=False):
316+
import iris.dbapi as iris_dbapi
317+
from iris_vector_rag.config.manager import ConfigurationManager
318+
319+
# Load configuration
320+
config_manager = ConfigurationManager()
321+
cloud_config = config_manager.get_cloud_config()
322+
323+
# Verify all configuration loaded from environment
324+
assert cloud_config.connection.host == 'localhost'
325+
assert cloud_config.connection.port == 1972
326+
assert cloud_config.connection.namespace == 'USER'
327+
assert cloud_config.vector.vector_dimension == 256
328+
assert cloud_config.tables.table_schema == 'RAG'
329+
330+
# Verify all sources are environment
331+
assert cloud_config.connection.source['host'].value == 'environment'
332+
assert cloud_config.connection.source['port'].value == 'environment'
333+
assert cloud_config.vector.source['vector_dimension'].value == 'environment'
334+
assert cloud_config.tables.source['table_schema'].value == 'environment'
335+
336+
# Test actual database connection
337+
conn = iris_dbapi.connect(
338+
hostname=cloud_config.connection.host,
339+
port=cloud_config.connection.port,
340+
namespace=cloud_config.connection.namespace,
341+
username=cloud_config.connection.username,
342+
password=cloud_config.connection.password
343+
)
344+
345+
try:
346+
cursor = conn.cursor()
347+
348+
# Create test table using cloud config
349+
table_name = f"{cloud_config.tables.table_schema}.TestE2EConfig"
350+
cursor.execute(f"DROP TABLE IF EXISTS {table_name}")
351+
352+
create_sql = f"""
353+
CREATE TABLE {table_name} (
354+
id VARCHAR(255) PRIMARY KEY,
355+
embedding VECTOR(DOUBLE, {cloud_config.vector.vector_dimension})
356+
)
357+
"""
358+
cursor.execute(create_sql)
359+
conn.commit()
360+
361+
# Verify table created with correct schema and dimension
362+
cursor.execute("""
363+
SELECT TABLE_SCHEMA, CHARACTER_MAXIMUM_LENGTH
364+
FROM INFORMATION_SCHEMA.COLUMNS
365+
WHERE TABLE_NAME = 'TestE2EConfig'
366+
AND COLUMN_NAME = 'embedding'
367+
""")
368+
369+
result = cursor.fetchone()
370+
schema = result[0]
371+
byte_length = result[1]
372+
actual_dim = round(byte_length / 346)
373+
374+
assert schema == 'RAG'
375+
assert actual_dim == 256
376+
377+
# Cleanup
378+
cursor.execute(f"DROP TABLE {table_name}")
379+
conn.commit()
380+
cursor.close()
381+
382+
finally:
383+
conn.close()
384+
385+
386+
# Integration test metadata
387+
INTEGRATION_METADATA = {
388+
"feature": "058-cloud-config-flexibility",
389+
"test_type": "integration",
390+
"requires_iris": True,
391+
"iris_port": 1972,
392+
"total_tests": 10,
393+
"test_categories": [
394+
"ConnectionManager with environment variables",
395+
"SchemaManager dimension configuration",
396+
"Configuration priority chain",
397+
"End-to-end configuration flow"
398+
]
399+
}

0 commit comments

Comments
 (0)