This commit is contained in:
icecheng 2025-09-07 11:59:09 +08:00
parent 6c71045b3a
commit de3abc691b
11 changed files with 1375 additions and 489 deletions

1375
README.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,136 +0,0 @@
# RabbitMQ Test Suite
This directory contains comprehensive tests for different RabbitMQ exchange types and patterns.
## Test Files
### Individual Test Files
1. **`run_fanout_test.py`** - Tests Fanout Exchange
- Broadcasts messages to all bound queues
- Demonstrates one-to-many messaging pattern
- Run: `python run_fanout_test.py`
2. **`run_direct_test.py`** - Tests Direct Exchange
- Routes messages based on exact routing key matches
- Demonstrates selective message routing
- Run: `python run_direct_test.py`
3. **`run_topic_test.py`** - Tests Topic Exchange
- Routes messages using wildcard patterns (* and #)
- Demonstrates hierarchical message routing
- Run: `python run_topic_test.py`
4. **`run_multi_queue_test.py`** - Tests Multi-Queue Load Balancing
- Distributes messages across multiple queues
- Demonstrates load balancing and parallel processing
- Run: `python run_multi_queue_test.py`
### Combined Test File
5. **`test.py`** - Runs all tests sequentially
- Executes all exchange type tests in order
- Run: `python test.py`
## Test Features
### Producer and Consumer Coordination
- Each test starts consumers in the background
- Producers send messages after consumers are ready
- Tests demonstrate real-time message processing
- Automatic cleanup and task cancellation
### Message Patterns Tested
#### Fanout Exchange
- **Pattern**: One-to-many broadcasting
- **Queues**: 3 queues (demo.fanout.queue-0, demo.fanout.queue-1, demo.fanout.queue-2)
- **Behavior**: All queues receive every message
- **Use Case**: Notifications, announcements, logging
#### Direct Exchange
- **Pattern**: Exact routing key matching
- **Queues**: error, warning, info (with debug routing to info)
- **Behavior**: Messages routed based on exact routing key
- **Use Case**: Log level routing, priority-based processing
#### Topic Exchange
- **Pattern**: Wildcard pattern matching
- **Queues**: Critical, Success, Failed
- **Behavior**: Messages routed using * and # wildcards
- **Use Case**: Hierarchical event routing, microservice communication
#### Multi-Queue Load Balancing
- **Pattern**: Round-robin distribution
- **Queues**: 3 balanced queues
- **Behavior**: Messages distributed evenly across queues
- **Use Case**: Horizontal scaling, parallel processing
## Running Tests
### Prerequisites
- RabbitMQ server running on localhost:5673
- Python 3.7+ with asyncio support
- Required packages: aio-pika
### Individual Test Execution
```bash
# Test Fanout Exchange
python run_fanout_test.py
# Test Direct Exchange
python run_direct_test.py
# Test Topic Exchange
python run_topic_test.py
# Test Multi-Queue Load Balancing
python run_multi_queue_test.py
```
### Run All Tests
```bash
python test.py
```
## Test Output
Each test provides detailed output showing:
- Consumer startup messages
- Message reception and processing
- Queue routing behavior
- Message persistence status
- Test completion status
## Configuration
Tests use the configuration from `config.py`:
- RabbitMQ URI: `amqp://guest:guest@localhost:5673/`
- Exchange and queue naming conventions
- Message persistence settings
## Architecture
### Producer Side
- Sets up exchanges and queues
- Publishes test messages with appropriate routing keys
- Handles connection management
### Consumer Side
- Starts multiple consumers for different queues
- Processes messages with simulated business logic
- Demonstrates concurrent message handling
### Test Coordination
- Uses asyncio tasks for concurrent execution
- Implements proper startup/shutdown sequences
- Ensures clean resource cleanup
## Extending Tests
To add new test scenarios:
1. Create a new test file following the naming pattern `run_xxx_test.py`
2. Import appropriate producer and consumer functions
3. Implement the test logic with proper async/await patterns
4. Add consumer startup, message publishing, and cleanup phases
5. Update this README with the new test description

BIN
assert/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
assert/img_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
assert/img_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
assert/img_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
assert/img_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
assert/img_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

75
help.py
View File

@ -1,75 +0,0 @@
#!/usr/bin/env python3
"""
RabbitMQ Test Help
Shows available test commands and usage information.
"""
import os
import sys
def show_help():
"""Display help information for RabbitMQ tests"""
print("🐰 RabbitMQ Test Suite Help")
print("=" * 50)
print("\n📋 Available Test Files:")
print("-" * 30)
test_files = [
("run_fanout_test.py", "Test Fanout Exchange (broadcast messaging)"),
("run_direct_test.py", "Test Direct Exchange (routing by key)"),
("run_topic_test.py", "Test Topic Exchange (wildcard routing)"),
("run_multi_queue_test.py", "Test Multi-Queue Load Balancing"),
("test.py", "Run all tests sequentially"),
("run_all_tests.py", "Run all individual test files with summary")
]
for filename, description in test_files:
exists = "" if os.path.exists(filename) else ""
print(f"{exists} {filename:<25} - {description}")
print("\n🚀 Usage Examples:")
print("-" * 20)
print("python run_fanout_test.py # Test fanout exchange")
print("python run_direct_test.py # Test direct exchange")
print("python run_topic_test.py # Test topic exchange")
print("python run_multi_queue_test.py # Test load balancing")
print("python test.py # Run all tests")
print("python run_all_tests.py # Run with detailed summary")
print("\n📖 Test Patterns:")
print("-" * 20)
print("• Fanout: One-to-many broadcasting")
print("• Direct: Exact routing key matching")
print("• Topic: Wildcard pattern matching (* and #)")
print("• Multi: Round-robin load balancing")
print("\n⚙️ Prerequisites:")
print("-" * 20)
print("• RabbitMQ server running on localhost:5673")
print("• Python 3.7+ with asyncio support")
print("• aio-pika package installed")
print("\n📁 File Structure:")
print("-" * 20)
print("product/ - Message producers")
print("comsumer/ - Message consumers")
print("config.py - RabbitMQ configuration")
print("run_*.py - Individual test files")
print("test.py - Combined test runner")
print("\n🔧 Configuration:")
print("-" * 20)
print("Edit config.py to change:")
print("• RabbitMQ connection URI")
print("• Exchange and queue names")
print("• Message persistence settings")
print("\n📚 Documentation:")
print("-" * 20)
print("See README_TESTS.md for detailed information")
if __name__ == "__main__":
show_help()

View File

@ -1,113 +0,0 @@
#!/usr/bin/env python3
"""
Run All RabbitMQ Tests
This script runs all individual test files in sequence.
"""
import asyncio
import sys
import os
import subprocess
# Add current directory to Python path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
def run_test_file(test_file):
"""Run a test file and return success status"""
try:
print(f"\n{'='*60}")
print(f"Running {test_file}")
print(f"{'='*60}")
result = subprocess.run([sys.executable, test_file],
capture_output=True,
text=True,
timeout=30)
if result.returncode == 0:
print(f"{test_file} completed successfully")
if result.stdout:
print("Output:")
print(result.stdout)
return True
else:
print(f"{test_file} failed with return code {result.returncode}")
if result.stderr:
print("Error:")
print(result.stderr)
return False
except subprocess.TimeoutExpired:
print(f"{test_file} timed out after 30 seconds")
return False
except Exception as e:
print(f"💥 {test_file} failed with exception: {e}")
return False
def main():
"""Main function to run all tests"""
print("🚀 Starting RabbitMQ Test Suite")
print("This will run all individual test files in sequence.")
# List of test files to run
test_files = [
"run_fanout_test.py",
"run_direct_test.py",
"run_topic_test.py",
"run_multi_queue_test.py"
]
# Check if test files exist
missing_files = []
for test_file in test_files:
if not os.path.exists(test_file):
missing_files.append(test_file)
if missing_files:
print(f"❌ Missing test files: {missing_files}")
sys.exit(1)
# Run all tests
results = []
for test_file in test_files:
success = run_test_file(test_file)
results.append((test_file, success))
# Wait between tests
if test_file != test_files[-1]: # Don't wait after last test
print("\n⏳ Waiting 2 seconds before next test...")
import time
time.sleep(2)
# Print summary
print(f"\n{'='*60}")
print("TEST SUMMARY")
print(f"{'='*60}")
passed = 0
failed = 0
for test_file, success in results:
status = "✅ PASSED" if success else "❌ FAILED"
print(f"{test_file:<25} {status}")
if success:
passed += 1
else:
failed += 1
print(f"\nTotal: {len(results)} tests")
print(f"Passed: {passed}")
print(f"Failed: {failed}")
if failed == 0:
print("\n🎉 All tests passed!")
sys.exit(0)
else:
print(f"\n💥 {failed} test(s) failed!")
sys.exit(1)
if __name__ == "__main__":
main()

165
test.py
View File

@ -1,165 +0,0 @@
import asyncio
import sys
import os
# Add current directory to Python path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from product.direct_multi_publish import setup_multi_queue_balance, BalancedProducer
from product.direct_publish import setup_direct_exchange, direct_publish
from product.fanout_publish import fanout_publish, setup_fanout_exchange
from product.topic_publish import setup_topic_exchange, topic_publish
from comsumer.direct_consumer import start_all_direct_consumers
from comsumer.fanout_consumer import start_all_fanout_consumers
from comsumer.topic_consumer import start_all_topic_consumers
from comsumer.direct_multi_consumer import start_balanced_consumers
async def run_fanout_test():
"""Run fanout exchange test with producer and consumer"""
print("=== Running Fanout Exchange Test ===")
# Start consumer in background
consumer_task = asyncio.create_task(start_all_fanout_consumers())
# Wait for consumer to start
await asyncio.sleep(1)
# Setup and publish messages
await setup_fanout_exchange("demo.fanout", "demo.fanout.queue-")
await fanout_publish(message="hello world", exchange_name="demo.fanout")
await fanout_publish(message="test message 2", exchange_name="demo.fanout")
await fanout_publish(message="test message 3", exchange_name="demo.fanout")
# Wait for messages to be processed
await asyncio.sleep(3)
# Cancel consumer
consumer_task.cancel()
print("✅ Fanout test completed successfully!")
async def run_direct_exchange_test():
"""Run direct exchange test with producer and consumer"""
print("=== Running Direct Exchange Test ===")
# Start consumer in background
consumer_task = asyncio.create_task(start_all_direct_consumers())
# Wait for consumer to start
await asyncio.sleep(1)
# Setup exchange and publish messages
await setup_direct_exchange()
test_messages = [
("System crash, unable to start", "error"), # Route to error queue
("Disk space insufficient", "warning"), # Route to warning queue
("User login successful", "info"), # Route to info queue
("Debug info: Database connection successful", "debug") # Route to info queue
]
for msg, routing_key in test_messages:
await direct_publish(msg, routing_key)
await asyncio.sleep(0.5)
# Wait for messages to be processed
await asyncio.sleep(3)
# Cancel consumer
consumer_task.cancel()
print("✅ Direct exchange test completed successfully!")
async def run_topic_exchange_test():
"""Run topic exchange test with producer and consumer"""
print("=== Running Topic Exchange Test ===")
# Start consumer in background
consumer_task = asyncio.create_task(start_all_topic_consumers())
# Wait for consumer to start
await asyncio.sleep(1)
# Setup exchange and publish messages
await setup_topic_exchange()
test_messages = [
("Order creation failed (critical error)", "order.create.critical"),
("User login successful", "user.login.success"),
("Order payment completed", "order.pay.success"),
("System crash (critical error)", "system.crash.critical"),
("User login failed", "user.login.failed"),
("Normal system log", "system.log.info") # Won't match any binding key, will be discarded
]
for msg, routing_key in test_messages:
await topic_publish(msg, routing_key)
await asyncio.sleep(0.5)
# Wait for messages to be processed
await asyncio.sleep(3)
# Cancel consumer
consumer_task.cancel()
print("✅ Topic exchange test completed successfully!")
async def run_multi_queue_balance_test():
"""Run multi-queue load balancing test with producer and consumer"""
print("=== Running Multi-Queue Load Balancing Test ===")
queue_count = 3
# Start consumer in background
consumer_task = asyncio.create_task(start_balanced_consumers(queue_count=queue_count))
# Wait for consumer to start
await asyncio.sleep(1)
# Setup and publish messages
await setup_multi_queue_balance(queue_count=queue_count)
producer = BalancedProducer(queue_count=queue_count)
await producer.connect()
for i in range(10):
await producer.publish(f"Task {i + 1}: Multi-queue load balancing test")
await asyncio.sleep(0.3)
await producer.close()
# Wait for messages to be processed
await asyncio.sleep(3)
# Cancel consumer
consumer_task.cancel()
print("✅ Multi-queue load balancing test completed successfully!")
async def main():
"""Main function to run all tests"""
print("🚀 Starting RabbitMQ Tests...")
try:
# Run all tests
await run_fanout_test()
await asyncio.sleep(1)
await run_direct_exchange_test()
await asyncio.sleep(1)
await run_topic_exchange_test()
await asyncio.sleep(1)
await run_multi_queue_balance_test()
print("\n🎉 All tests completed successfully!")
except Exception as e:
print(f"❌ Test failed: {e}")
sys.exit(1)
if __name__ == "__main__":
asyncio.run(main())