RAG Integration Tests
February 11, 2026 ยท View on GitHub
This directory contains modular integration tests for RAG and Ingestion APIs, organized by functionality for easier maintenance and extension.
Prerequisites
1. Running Services
- RAG Server: Must be running on
http://localhost:8081(or custom URL) - Ingestor Server: Must be running on
http://localhost:8082(or custom URL) - Milvus: Vector database must be accessible
- Nvingest: Ensure nvingest and its dependencies are also running.
- Model Endpoints: Required for RAG operations, can be cloud or on-prem.
2. Test Data
- Recommended: The test uses specific default files for optimal testing:
- Collection with metadata:
multimodal_test.pdf,woods_frost.docx - Collection without metadata:
table_test.pdf,embedded_table.pdf
- Collection with metadata:
- These files should be placed in the data directory (default:
../../data/multimodal) - Ensure files are accessible and readable
- Alternatively, specify individual files using the file arguments to override defaults
Recommended Files for Testing:
- Collection with metadata:
multimodal_test.pdf,woods_frost.docx - Collection without metadata:
table_test.pdf,embedded_table.pdf
These files should be placed in your data directory (default: ../../data/multimodal).
Why These Files? These specific files are chosen because they provide comprehensive test coverage including multimodal content, tables, embedded objects, and various document formats that exercise all major features of the RAG pipeline. The sample queries and response checks are also tailored to these files.
Quick Start
1. Install Requirements
pip install -r tests/integration/requirements.txt
2. Run Tests
# Default: runs basic sequence (core functionality tests)
python -m tests.integration.main --rag-server http://localhost:8081 --ingestor-server http://localhost:8082
# Run specific sequences
python -m tests.integration.main --sequence basic
python -m tests.integration.main --sequence nemo_guardrails
python -m tests.integration.main --sequence custom_prompt
# List available sequences
python -m tests.integration.main --list-sequences
3. Additional Options
# With custom data directory
python -m tests.integration.main --data-dir ../../data/multimodal
# Override with custom files
python -m tests.integration.main --files-with-metadata doc1.pdf doc2.docx --files-without-metadata doc3.pdf
# Use custom collection names
python -m tests.integration.main --collection-with-metadata my_metadata_collection --collection-without-metadata my_plain_collection
# Verbose logging
python -m tests.integration.main --verbose
# Test selection examples
python -m tests.integration.main --test-numbers 1 3 5
python -m tests.integration.main --test-names "Health Checks" "Create Collections"
python -m tests.integration.main --test-range 1-5
python -m tests.integration.main --exclude-tests 16
python -m tests.integration.main --list-tests
Sequence
Sequences are defined in test_sequences.yaml file.
Each sequence can define:
pre_sequence: Tests to run before the main sequence (e.g., setup, cleanup)test_cases: Main test cases to run in sequence.post_sequence: Tests to run after the main sequence (e.g., cleanup, verification)
Execution Flow:
- Pre-sequence tests run first (if defined)
- Main sequence tests run defined by
test_cases: []in the same order as specified. - Post-sequence tests run last (always executes, even if main sequence fails)
Result Display:
- Tests are automatically marked as ๐ง PRE, ๐ MAIN, or ๐งน POST in the results table
- Summary includes phase breakdown statistics
Usage
# Default: runs basic sequence
python -m tests.integration.main
# Run specific sequence
python -m tests.integration.main --sequence basic
python -m tests.integration.main --sequence image_captioning
python -m tests.integration.main --sequence full
# List available sequences (shows pre/post hooks)
python -m tests.integration.main --list-sequences
Adding New Test Cases
Quick Guide: Adding a New Test Case
- Choose the appropriate test module based on functionality
- Add your test method with the
@test_casedecorator:
from ..base import test_case
@test_case(26, "New Feature Test") # Ensure the test number is unique
async def _test_new_feature(self) -> bool:
"""Test new feature functionality"""
try:
# Prepare request payload
payload = {
"param1": "value1",
"param2": "value2"
}
# Log request details
logger.info(f"๐ง Testing new feature")
logger.info(f"๐ Request payload:\n{json.dumps(payload, indent=2)}")
# Your test logic here - implement the actual API calls
async with aiohttp.ClientSession() as session:
async with session.post(f"{self.rag_server_url}/v1/your-endpoint", json=payload) as response:
result = await response.json()
if response.status == 200:
logger.info(f"โ
New feature test passed:")
logger.info(f"Response JSON:\n{json.dumps(result, indent=2)}")
# Add test result automatically
self.add_test_result(
self._test_new_feature.test_number,
self._test_new_feature.test_name,
"Tests the new feature functionality",
["POST /v1/your-endpoint"],
["param1", "param2"],
time.time() - start_time,
TestStatus.SUCCESS
)
return True
else:
logger.error(f"โ New feature test failed: {response.status}")
logger.error(f"Response JSON:\n{json.dumps(result, indent=2)}")
return False
except Exception as e:
logger.error(f"โ New feature test error: {e}")
return False
That's it! The test will be automatically discovered and can be run with:
python -m tests.integration.main --test-numbers 26
Adding a New Test Module
If you need to create a completely new test module:
- Create new test module file in
test_cases/directory:
# test_cases/new_feature.py
import json
import logging
import time
from typing import Any
import aiohttp
from ..base import BaseTestModule, TestStatus, test_case
logger = logging.getLogger(__name__)
class NewFeatureModule(BaseTestModule):
@test_case(26, "New Feature Test 1")
async def _test_feature_1(self) -> bool:
"""Test feature 1 - implement actual API calls"""
try:
payload = {"field1": "value1"}
logger.info(f"๐ง Testing feature 1")
logger.info(f"๐ Request payload:\n{json.dumps(payload, indent=2)}")
async with aiohttp.ClientSession() as session:
async with session.post(f"{self.rag_server_url}/v1/feature1", json=payload) as response:
result = await response.json()
if response.status == 200:
logger.info(f"โ
Feature 1 test passed:")
logger.info(f"Response JSON:\n{json.dumps(result, indent=2)}")
return True
else:
logger.error(f"โ Feature 1 test failed: {response.status}")
logger.error(f"Response JSON:\n{json.dumps(result, indent=2)}")
return False
except Exception as e:
logger.error(f"โ Feature 1 test error: {e}")
return False
@test_case(27, "New Feature Test 2")
async def _test_feature_2(self) -> bool:
"""Test feature 2 - implement actual API calls"""
try:
logger.info(f"๐ง Testing feature 2")
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.rag_server_url}/v1/feature2") as response:
result = await response.json()
if response.status == 200:
logger.info(f"โ
Feature 2 test passed:")
logger.info(f"Response JSON:\n{json.dumps(result, indent=2)}")
return True
else:
logger.error(f"โ Feature 2 test failed: {response.status}")
logger.error(f"Response JSON:\n{json.dumps(result, indent=2)}")
return False
except Exception as e:
logger.error(f"โ Feature 2 test error: {e}")
return False
That's it! The module will be automatically discovered. No need to register it anywhere.
Adding a New Test Sequence
To add a new test sequence:
- Edit
test_sequences.yamland add your sequence:
sequences:
# Add your new sequence here
my_custom_sequence:
name: "My Custom Tests"
description: "Custom test sequence for specific functionality"
test_numbers: [20, 21, 23] # Mix of existing and new tests
pre_sequence: [1] # Optional: setup tests
post_sequence: [16, 17, 18, 19] # Optional: cleanup tests
- Use your new sequence:
python -m tests.integration.main --sequence my_custom_sequence
That's it! No code changes needed. Pre/post hooks are automatically executed and displayed in results.
Best Practices
- Error Handling: Always wrap test logic in try-catch blocks
- Logging: Use
loggerfor consistent logging with pretty-printed JSON - Pretty Printing: Always log request payloads and response data with
json.dumps(data, indent=2) - Visual Indicators: Use emojis (๐, ๐ค, ๐, ๐๏ธ, ๐, ๐) for better readability
- Verification: Verify both response status and content
- Cleanup: Ensure tests don't leave persistent state
- Documentation: Add clear descriptions for each test
- Incremental Numbers: Use sequential test numbers (20, 21, 22, etc.)
Test Selection
The integration test suite supports multiple ways to run tests:
Predefined Sequences (Recommended)
# Default: runs basic sequence
python -m tests.integration.main
# Run specific sequences
python -m tests.integration.main --sequence basic
python -m tests.integration.main --sequence optional
python -m tests.integration.main --sequence full
# List available sequences
python -m tests.integration.main --list-sequences
Individual Test Selection
# List all available tests
python -m tests.integration.main --list-tests
# Run specific test numbers
python -m tests.integration.main --test-numbers 1 3 5
# Run test range
python -m tests.integration.main --test-range 1-5
# Run tests by name
python -m tests.integration.main --test-names "Health Checks" "Create Collections"
# Run tests by partial name matching
python -m tests.integration.main --test-names "Health" "Upload" "Search"
# Mix numbers and names
python -m tests.integration.main --tests 1 "Create Collections" 5
# Exclude specific tests
python -m tests.integration.main --exclude-tests 16
Troubleshooting
Common Issues
-
Connection Refused
- Ensure containers are running
- Check server URLs and ports
- Verify network connectivity
-
Timeout Errors
- Increase
--timeoutvalue for slow environments - Check server performance and resources
- Increase
-
Missing Test Files
- Verify
--data-dirpath exists - Ensure test files are accessible
- Check file permissions
- Recommended default files: Ensure
multimodal_test.pdf,woods_frost.docx,table_test.pdf, andembedded_table.pdfare in the data directory - When using
--files-with-metadataor--files-without-metadata, verify all specified files exist
- Verify
-
Task Failures
- Check container logs for detailed error messages
- Verify Milvus connection and configuration
- Check model endpoint availability
-
Collection Name Conflicts
- Use
--collection-with-metadataand--collection-without-metadatato avoid conflicts with existing collections - The script automatically cleans up test collections via post-sequence hooks, but conflicts may occur if tests are interrupted
- Use
-
Debugging Failed Tests
- Post-sequence cleanup tests always run, even if main sequence fails
- Check the test results table for phase breakdown (๐ง PRE, ๐ MAIN, ๐งน POST)
- Use
--verbosefor detailed logging during test execution - Check container logs for detailed error messages
Output
- Console: Real-time test progress and final results table
- Log File:
integration_test.logwith complete test execution details - Exit Codes:
0for success,1for failure