Testing Architecture π‘ BETA
Overview
The General Bots testing framework is designed with a multi-layered, isolated approach to ensure comprehensive coverage from individual components to complete user workflows.
Architecture Diagram
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Test Execution Layer β
β (GitHub Actions, CI/CD, Local Development) β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββΌβββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββ βββββββββββ ββββββββββββ
β Unit β β Integr. β β E2E β
β Tests β β Tests β β Tests β
ββββββ¬βββββ ββββββ¬βββββ βββββββ¬βββββ
β β β
ββββββββββββββΌβββββββββββββ
β
ββββββββββββββΌβββββββββββββ
β Test Harness Layer β
β (Context, Utils, Mocks) β
ββββββββββββββ¬βββββββββββββ
β
ββββββββββββββΌβββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββ βββββββββββ ββββββββββββ
βbotserverβ β Browserβ β Services β
β(Testing)β β (WebDrv)β β(Mock/Iso)β
βββββββββββ βββββββββββ ββββββββββββ
β β β
ββββββββββββββΌβββββββββββββ
β
ββββββββββββββΌβββββββββββββ
β Temporary Stack Layer β
β (Isolated Environments) β
ββββββββββββββ¬βββββββββββββ
β
ββββββββββββββ΄βββββββββββββ
β β
βΌ βΌ
βββββββββββββββ ββββββββββββββββ
β PostgreSQL β β Redis, MinIO β
β (Isolated) β β (Isolated) β
βββββββββββββββ ββββββββββββββββ
Test Layers
1. Unit Tests
Purpose: Test individual components in isolation
Scope:
- Single functions or methods
- Mocked external dependencies
- No database or external services
Example:
#![allow(unused)] fn main() { #[test] fn test_message_formatting() { let msg = format_message("Hello"); assert_eq!(msg, "Hello!"); } }
Location: bottest/tests/unit/
2. Integration Tests
Purpose: Test multiple components working together
Scope:
- Multi-component interactions
- Real database connections
- Service integration
- Error handling across components
Example:
#![allow(unused)] fn main() { #[tokio::test] async fn test_message_storage_and_retrieval() { let db = setup_test_db().await; let msg = Message::new("Hello"); db.save(&msg).await.unwrap(); let retrieved = db.get(msg.id).await.unwrap(); assert_eq!(retrieved.text, "Hello"); } }
Location: bottest/tests/integration/
3. End-to-End Tests
Purpose: Test complete user workflows
Scope:
- Complete user journeys
- Browser interactions
- Multi-phase workflows
- Real-world scenarios
Phases:
- Platform Loading
- botserver Initialization
- User Authentication
- Chat Interaction
- Logout & Session Management
Example:
#![allow(unused)] fn main() { #[tokio::test] async fn test_complete_platform_flow_login_chat_logout() { let ctx = E2ETestContext::setup_with_browser().await?; verify_platform_loading(&ctx).await?; verify_botserver_running(&ctx).await?; test_user_login(browser, &ctx).await?; test_chat_interaction(browser, &ctx).await?; test_user_logout(browser, &ctx).await?; ctx.close().await; } }
Location: bottest/tests/e2e/
Test Harness
The test harness provides utilities for test setup and context management:
TestHarness
βββ Setup utilities
β βββ Create test database
β βββ Start mock services
β βββ Initialize configurations
β βββ Provision test data
βββ Context management
β βββ Resource tracking
β βββ Cleanup coordination
β βββ Error handling
βββ Helper functions
βββ HTTP requests
βββ Browser interactions
βββ Service mocking
E2ETestContext
Provides complete environment for E2E testing:
#![allow(unused)] fn main() { pub struct E2ETestContext { pub ctx: TestContext, pub server: botserverInstance, pub browser: Option<Browser>, } impl E2ETestContext { pub async fn setup() -> Result<Self> pub async fn setup_with_browser() -> Result<Self> pub fn base_url(&self) -> &str pub fn has_browser(&self) -> bool pub async fn close(self) } }
Temporary Stack Architecture
Isolated test environments for complete system integration:
/tmp/botserver-test-{timestamp}-{id}/
βββ postgres/
β βββ data/ β PostgreSQL data files
β βββ postgresql.log β Database logs
β βββ postgresql.conf β Configuration
βββ redis/
β βββ data/ β Redis persistence
β βββ redis.log
βββ minio/
β βββ data/ β S3-compatible storage
β βββ minio.log
βββ botserver/
β βββ config/
β β βββ config.toml β Application config
β β βββ .env β Environment variables
β βββ logs/
β β βββ botserver.log β Main application logs
β β βββ api.log β API logs
β β βββ debug.log β Debug logs
β βββ cache/ β Local cache
β βββ state.json β Stack metadata
βββ env.stack β Connection strings for tests
Isolation Strategy
Service Isolation
Each test gets dedicated service instances:
- Database: Separate PostgreSQL cluster on port 5433
- Cache: Separate Redis instance on port 6380
- Storage: Separate MinIO instance on port 9001
- API: Separate botserver on port 8000
Network Isolation
- All services on localhost (127.0.0.1)
- Non-standard ports to avoid conflicts
- Docker containers for complete OS-level isolation
Data Isolation
- Separate database schemas per test
- Temporary file systems for storage
- No shared configuration between tests
- Automatic cleanup on completion
Test Execution Flow
1. Test Initialization
ββ Parse environment variables
ββ Check prerequisites (WebDriver, services)
ββ Create test context
2. Stack Setup
ββ Create temporary directory
ββ Initialize databases
ββ Start services
ββ Wait for readiness
3. Test Execution
ββ Setup phase
ββ Action phase
ββ Verification phase
ββ Assertion phase
4. Cleanup
ββ Close browser connections
ββ Shutdown services gracefully
ββ Remove temporary directories
ββ Report results
Browser Automation
Uses WebDriver (Selenium) protocol for browser testing:
Test Code
β
Reqwest HTTP Client
β
WebDriver Protocol (JSON-RPC)
β
chromedriver / Selenium Server
β
Chrome/Chromium Browser
β
Test Verification
WebDriver Commands
- Navigate to URL
- Find elements by selector
- Click buttons and links
- Fill form inputs
- Wait for elements
- Execute JavaScript
- Take screenshots
- Get element text
Error Handling
Comprehensive error handling at all levels:
Test Execution
β
ββ Setup Error
β ββ Fail fast, preserve environment
β
ββ Execution Error
β ββ Log detailed context
β ββ Capture screenshots
β ββ Optionally preserve stack
β
ββ Cleanup Error
ββ Log warning, continue cleanup
Performance Considerations
Test Execution Times
- Unit Tests: ~0.1-1 second
- Integration Tests: ~1-10 seconds
- E2E Tests: ~30-60 seconds
- Full Suite: ~2-3 minutes
Optimization Strategies
- Parallel Execution: Run independent tests simultaneously
- Caching: Reuse expensive resources
- Lazy Loading: Initialize only needed components
- Release Mode: Use
--releasefor faster compilation - Selective Testing: Run only relevant tests during development
CI/CD Integration
GitHub Actions Workflow
Trigger (push/PR)
β
Setup Environment
ββ Install Rust
ββ Start WebDriver
ββ Setup test infrastructure
β
Run Tests
ββ Unit tests
ββ Integration tests
ββ E2E tests
β
Collect Artifacts
ββ Test results
ββ Coverage reports
ββ Screenshots/logs
ββ Performance metrics
β
Report Results
ββ Pass/fail status
Best Practices
1. Test Organization
- Keep tests focused and single-purpose
- Use descriptive names
- Group related tests
- Organize by layer (unit/integration/e2e)
2. Test Design
- Make tests independent
- Use realistic data
- Test both happy and error paths
- Avoid test interdependencies
3. Test Maintenance
- Keep tests up to date with code
- Remove obsolete tests
- Refactor test helpers
- Monitor test execution time
4. Test Documentation
- Document complex test logic
- Explain test prerequisites
- Document setup/teardown
- Include troubleshooting tips
Debugging
Debug Helpers
RUST_LOG=debug- Verbose loggingHEADED=1- Show browser UI--nocapture- Print test output--test-threads=1- Run sequentially
Debug Techniques
- Check server logs
- Review screenshots
- Inspect HTTP requests
- Step through code
- Use REPL for experimentation
Future Enhancements
- Load Testing - Concurrent user scenarios
- Visual Regression - Screenshot comparison
- Accessibility Testing - WCAG compliance
- Security Testing - Vulnerability scanning
- Performance Profiling - Memory and CPU analysis
- Multi-region - Test across deployments
- Snapshot Testing - Compare outputs over time