ecu-tests/tests/test_smoke_mock.py

172 lines
7.6 KiB
Python

import pytest
from ecu_framework.lin.base import LinFrame
class TestMockLinInterface:
"""Test suite validating the pure-Python mock LIN interface behavior.
Coverage goals:
- REQ-001: Echo loopback for local testing (send -> receive same frame)
- REQ-002: Deterministic master request responses (no randomness)
- REQ-003: Frame ID filtering in receive()
- REQ-004: Graceful handling of timeout when no frame is available
Notes:
- These tests run entirely without hardware and should be fast and stable.
- The injected mock interface enqueues frames on transmit to emulate a bus.
- Deterministic responses allow exact byte-for-byte assertions.
"""
@pytest.mark.smoke
@pytest.mark.req_001
@pytest.mark.req_003
def test_mock_send_receive_echo(self, lin):
"""
Title: Mock LIN Interface - Send/Receive Echo Test
Description:
Validates that the mock LIN interface correctly echoes frames sent on the bus,
enabling loopback testing without hardware dependencies.
Requirements: REQ-001, REQ-003
Test Steps:
1. Create a LIN frame with specific ID and data payload
2. Send the frame via the mock interface
3. Attempt to receive the echoed frame with ID filtering
4. Verify the received frame matches the transmitted frame exactly
Expected Result:
- Frame is successfully echoed by mock interface
- Received frame ID matches transmitted frame ID (0x12)
- Received frame data payload matches transmitted data [1, 2, 3]
"""
# Step 1: Create test frame with known ID and payload
test_frame = LinFrame(id=0x12, data=bytes([1, 2, 3]))
# Step 2: Transmit frame via mock interface (mock will enqueue to RX)
lin.send(test_frame)
# Step 3: Receive echoed frame with ID filtering and timeout
received_frame = lin.receive(id=0x12, timeout=0.5)
# Step 4: Validate echo functionality and payload integrity
assert received_frame is not None, "Mock interface should echo transmitted frames"
assert received_frame.id == test_frame.id, f"Expected ID {test_frame.id:#x}, got {received_frame.id:#x}"
assert received_frame.data == test_frame.data, f"Expected data {test_frame.data!r}, got {received_frame.data!r}"
@pytest.mark.smoke
@pytest.mark.req_002
def test_mock_request_synthesized_response(self, lin):
"""
Title: Mock LIN Interface - Master Request Response Test
Description:
Validates that the mock interface synthesizes deterministic responses
for master request operations, simulating slave node behavior.
Requirements: REQ-002
Test Steps:
1. Issue a master request for specific frame ID and data length
2. Verify mock interface generates a response frame
3. Validate response frame ID matches request ID
4. Verify response data length matches requested length
5. Confirm response data is deterministic (not random)
Expected Result:
- Mock interface generates response within timeout period
- Response frame ID matches request ID (0x21)
- Response data length equals requested length (4 bytes)
- Response data follows deterministic pattern: [id+0, id+1, id+2, id+3]
"""
# Step 1: Issue master request with specific parameters
request_id = 0x21
requested_length = 4
# Step 2: Execute request operation; mock synthesizes deterministic bytes
response_frame = lin.request(id=request_id, length=requested_length, timeout=0.5)
# Step 3: Validate response generation
assert response_frame is not None, "Mock interface should generate response for master requests"
# Step 4: Verify response frame properties (ID and length)
assert response_frame.id == request_id, f"Response ID {response_frame.id:#x} should match request ID {request_id:#x}"
assert len(response_frame.data) == requested_length, f"Response length {len(response_frame.data)} should match requested length {requested_length}"
# Step 5: Validate deterministic response pattern
expected_data = bytes((request_id + i) & 0xFF for i in range(requested_length))
assert response_frame.data == expected_data, f"Response data {response_frame.data!r} should follow deterministic pattern {expected_data!r}"
@pytest.mark.smoke
@pytest.mark.req_004
def test_mock_receive_timeout_behavior(self, lin):
"""
Title: Mock LIN Interface - Receive Timeout Test
Description:
Validates that the mock interface properly handles timeout scenarios
when no matching frames are available for reception.
Requirements: REQ-004
Test Steps:
1. Attempt to receive a frame with non-existent ID
2. Use short timeout to avoid blocking test execution
3. Verify timeout behavior returns None rather than blocking indefinitely
Expected Result:
- Receive operation returns None when no matching frames available
- Operation completes within specified timeout period
- No exceptions or errors during timeout scenario
"""
# Step 1: Attempt to receive frame with ID that hasn't been transmitted
non_existent_id = 0xFF
short_timeout = 0.1 # 100ms timeout
# Step 2: Execute receive with timeout (should return None quickly)
result = lin.receive(id=non_existent_id, timeout=short_timeout)
# Step 3: Verify proper timeout behavior (no exceptions, returns None)
assert result is None, "Receive operation should return None when no matching frames available"
@pytest.mark.boundary
@pytest.mark.req_001
@pytest.mark.req_003
@pytest.mark.parametrize("frame_id,data_payload", [
(0x01, bytes([0x55])),
(0x3F, bytes([0xAA, 0x55])),
(0x20, bytes([0x01, 0x02, 0x03, 0x04, 0x05])),
(0x15, bytes([0xFF, 0x00, 0xCC, 0x33, 0xF0, 0x0F, 0xA5, 0x5A])),
])
def test_mock_frame_validation_boundaries(self, lin, frame_id, data_payload):
"""
Title: Mock LIN Interface - Frame Validation Boundaries Test
Description:
Validates mock interface handling of various frame configurations
including boundary conditions for frame IDs and data lengths.
Requirements: REQ-001, REQ-003
Test Steps:
1. Test various valid frame ID values (0x01 to 0x3F)
2. Test different data payload lengths (1 to 8 bytes)
3. Verify proper echo behavior for all valid combinations
Expected Result:
- All valid frame configurations are properly echoed
- Frame ID and data integrity preserved across echo operation
"""
# Step 1: Create frame with parameterized values
test_frame = LinFrame(id=frame_id, data=data_payload)
# Step 2: Send and receive frame
lin.send(test_frame)
received_frame = lin.receive(id=frame_id, timeout=0.5)
# Step 3: Validate frame integrity across IDs and payload sizes
assert received_frame is not None, f"Frame with ID {frame_id:#x} should be echoed"
assert received_frame.id == frame_id, f"Frame ID should be preserved: expected {frame_id:#x}"
assert received_frame.data == data_payload, f"Frame data should be preserved for ID {frame_id:#x}"