21 KiB
Blackbox Tests
Positive Scenarios
FT-P-01: Health check returns status before engine initialization
Summary: Verify the health endpoint responds correctly when the inference engine has not yet been initialized. Traces to: AC-API-1, AC-EL-1 Category: API, Engine Lifecycle
Preconditions:
- Detections service is running
- No detection requests have been made (engine is not initialized)
Input data: None
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | GET /health |
200 OK with {"status": "healthy", "aiAvailability": "None"} |
Expected outcome: Health endpoint returns status: "healthy" and aiAvailability: "None" (engine not yet loaded).
Max execution time: 2s
FT-P-02: Health check reflects engine availability after initialization
Summary: Verify the health endpoint reports the correct engine state after the engine has been initialized by a detection request. Traces to: AC-API-1, AC-EL-2 Category: API, Engine Lifecycle
Preconditions:
- Detections service is running
- Mock-loader serves the ONNX model file
- At least one successful detection has been performed (engine initialized)
Input data: small-image
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with small-image (trigger engine init) |
200 OK with detection results |
| 2 | GET /health |
200 OK with aiAvailability set to "Enabled" or "Warning" |
Expected outcome: aiAvailability reflects an initialized engine state (not "None" or "Downloading").
Max execution time: 30s (includes engine init on first call)
FT-P-03: Single image detection returns detections
Summary: Verify that a valid small image submitted via POST /detect returns structured detection results. Traces to: AC-DA-1, AC-API-2 Category: Detection Accuracy, API
Preconditions:
- Engine is initialized (or will be on this call)
- Mock-loader serves the model
Input data: small-image (640×480, contains detectable objects)
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with small-image as multipart file |
200 OK |
| 2 | Parse response JSON | Array of detection objects, each with x, y, width, height, label, confidence |
| 3 | Verify all confidence values | Every detection has confidence >= 0.25 (default probability_threshold) |
Expected outcome: Non-empty array of DetectionDto objects. All confidences meet threshold. Each detection has valid bounding box coordinates (0.0–1.0 range). Max execution time: 30s
FT-P-04: Large image triggers GSD-based tiling
Summary: Verify that an image exceeding 1.5× model dimensions is tiled and processed with tile-level detection results merged. Traces to: AC-IP-1, AC-IP-2 Category: Image Processing
Preconditions:
- Engine is initialized
- Config includes altitude, focal_length, sensor_width for GSD calculation
Input data: large-image (4000×3000)
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with large-image and config {"altitude": 400, "focal_length": 24, "sensor_width": 23.5} |
200 OK |
| 2 | Parse response JSON | Array of detections |
| 3 | Verify detection coordinates | Bounding box coordinates are in 0.0–1.0 range relative to the full original image |
Expected outcome: Detections returned for the full image. Coordinates are normalized to original image dimensions (not tile dimensions). Processing time is longer than small-image due to tiling. Max execution time: 60s
FT-P-05: Detection confidence filtering respects threshold
Summary: Verify that detections below the configured probability_threshold are filtered out. Traces to: AC-DA-1 Category: Detection Accuracy
Preconditions:
- Engine is initialized
Input data: small-image
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with small-image and config {"probability_threshold": 0.8} |
200 OK |
| 2 | Parse response JSON | All returned detections have confidence >= 0.8 |
| 3 | POST /detect with same image and config {"probability_threshold": 0.1} |
200 OK |
| 4 | Compare result counts | Step 3 returns >= number of detections from Step 1 |
Expected outcome: Higher threshold produces fewer or equal detections. No detection below threshold appears in results. Max execution time: 30s
FT-P-06: Overlapping detections are deduplicated
Summary: Verify that overlapping detections with containment ratio above threshold are deduplicated, keeping the higher-confidence one. Traces to: AC-DA-2 Category: Detection Accuracy
Preconditions:
- Engine is initialized
- Image produces overlapping detections (dense scene)
Input data: small-image (scene with clustered objects)
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with small-image and config {"tracking_intersection_threshold": 0.6} |
200 OK |
| 2 | Collect detections | No two detections of the same class overlap by more than 60% containment ratio |
| 3 | POST /detect with same image and config {"tracking_intersection_threshold": 0.01} |
200 OK |
| 4 | Compare result counts | Step 3 returns fewer or equal detections (more aggressive dedup) |
Expected outcome: No pair of returned detections exceeds the configured overlap threshold. Max execution time: 30s
FT-P-07: Physical size filtering removes oversized detections
Summary: Verify that detections exceeding the MaxSizeM for their class (given GSD) are removed. Traces to: AC-DA-4 Category: Detection Accuracy
Preconditions:
- Engine is initialized
- classes.json loaded with MaxSizeM values
Input data: small-image, config with known GSD parameters
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with small-image and config {"altitude": 400, "focal_length": 24, "sensor_width": 23.5} |
200 OK |
| 2 | For each detection, compute physical size from bounding box + GSD | No detection's physical size exceeds the MaxSizeM defined for its class in classes.json |
Expected outcome: All returned detections have plausible physical dimensions for their class. Max execution time: 30s
FT-P-08: Async media detection returns "started" immediately
Summary: Verify that POST /detect/{media_id} returns immediately with status "started" while processing continues in background. Traces to: AC-API-3 Category: API
Preconditions:
- Engine is initialized
- Media file paths are available via config
Input data: jwt-token, test-video path in config
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect/test-media-001 with config paths and auth headers |
200 OK, {"status": "started"} |
| 2 | Measure response time | Response arrives within 1s (before video processing completes) |
Expected outcome: Immediate response with {"status": "started"}. Processing continues asynchronously.
Max execution time: 2s (response only; processing continues in background)
FT-P-09: SSE streaming delivers detection events during async processing
Summary: Verify that SSE clients receive real-time detection events during async media detection. Traces to: AC-API-4, AC-API-3 Category: API
Preconditions:
- Engine is initialized
- SSE client connected before triggering detection
Input data: jwt-token, test-video path in config
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Open SSE connection: GET /detect/stream |
Connection established |
| 2 | POST /detect/test-media-002 with config and auth headers |
{"status": "started"} |
| 3 | Listen on SSE connection | Receive events with mediaStatus: "AIProcessing" as frames are processed |
| 4 | Wait for completion | Final event with mediaStatus: "AIProcessed" and percent: 100 |
Expected outcome: Multiple SSE events received. Events include detection data. Final event signals completion. Max execution time: 120s
FT-P-10: Video frame sampling processes every Nth frame
Summary: Verify that video processing respects the frame_period_recognition setting.
Traces to: AC-VP-1
Category: Video Processing
Preconditions:
- Engine is initialized
- SSE client connected
Input data: test-video (10s, 30fps = 300 frames), config {"frame_period_recognition": 4}
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Open SSE connection | Connection established |
| 2 | POST /detect/test-media-003 with config {"frame_period_recognition": 4, "paths": ["/media/test-video.mp4"]} |
{"status": "started"} |
| 3 | Count distinct SSE events with detection data | Number of processed frames ≈ 300/4 = 75 (±10% tolerance for start/end frames) |
Expected outcome: Approximately 75 frames processed (not all 300). The count scales proportionally with frame_period_recognition. Max execution time: 120s
FT-P-11: Video annotation interval enforcement
Summary: Verify that annotations are not reported more frequently than frame_recognition_seconds.
Traces to: AC-VP-2
Category: Video Processing
Preconditions:
- Engine is initialized
- SSE client connected
Input data: test-video, config {"frame_recognition_seconds": 2}
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Open SSE connection | Connection established |
| 2 | POST /detect/test-media-004 with config {"frame_recognition_seconds": 2, "paths": ["/media/test-video.mp4"]} |
{"status": "started"} |
| 3 | Record timestamps of consecutive SSE detection events | Minimum gap between consecutive annotation events ≥ 2 seconds |
Expected outcome: No two annotation events are closer than 2 seconds apart. Max execution time: 120s
FT-P-12: Video tracking accepts new annotations on movement
Summary: Verify that new annotations are accepted when detections move beyond the tracking threshold. Traces to: AC-VP-3 Category: Video Processing
Preconditions:
- Engine is initialized
- SSE client connected
- Video contains moving objects
Input data: test-video, config with tracking_distance_confidence > 0
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Open SSE connection | Connection established |
| 2 | POST /detect/test-media-005 with config {"tracking_distance_confidence": 0.05, "paths": ["/media/test-video.mp4"]} |
{"status": "started"} |
| 3 | Collect SSE events | Annotations are emitted when object positions change between frames |
Expected outcome: Annotations contain updated positions reflecting object movement. Static objects do not generate redundant annotations. Max execution time: 120s
FT-P-13: Weather mode class variants
Summary: Verify that the system supports detection across different weather mode class variants (Norm, Wint, Night). Traces to: AC-OC-1 Category: Object Classes
Preconditions:
- Engine is initialized
- classes.json includes weather-mode variants
Input data: small-image
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with small-image |
200 OK |
| 2 | Inspect returned detection labels | Labels correspond to valid class names from classes.json (base or weather-variant) |
Expected outcome: All returned labels are valid entries from the 19-class × 3-mode registry. Max execution time: 30s
FT-P-14: Engine lazy initialization on first detection request
Summary: Verify that the engine is not initialized at startup but is initialized on the first detection request. Traces to: AC-EL-1, AC-EL-2 Category: Engine Lifecycle
Preconditions:
- Fresh service start, no prior requests
Input data: small-image
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | GET /health immediately after service starts |
aiAvailability: "None" — engine not loaded |
| 2 | POST /detect with small-image |
200 OK (may take longer — engine initializing) |
| 3 | GET /health |
aiAvailability changed to "Enabled" or status indicating engine is active |
Expected outcome: Engine transitions from "None" to an active state only after a detection request. Max execution time: 60s
FT-P-15: ONNX fallback when GPU unavailable
Summary: Verify that the system falls back to ONNX Runtime when no compatible GPU is available. Traces to: AC-EL-2, RESTRICT-HW-1 Category: Engine Lifecycle
Preconditions:
- Detections service running WITHOUT GPU runtime (CPU-only Docker profile)
- Mock-loader serves ONNX model
Input data: small-image
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with small-image |
200 OK with detection results |
| 2 | GET /health |
aiAvailability indicates engine is active (ONNX fallback) |
Expected outcome: Detection succeeds via ONNX Runtime. No TensorRT-related errors. Max execution time: 60s
FT-P-16: Tile deduplication removes duplicate detections at tile boundaries
Summary: Verify that detections appearing in overlapping tile regions are deduplicated. Traces to: AC-DA-3 Category: Detection Accuracy
Preconditions:
- Engine is initialized
- Large image that triggers tiling
Input data: large-image with config including GSD parameters and big_image_tile_overlap_percent: 20
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with large-image and tiling config |
200 OK |
| 2 | Inspect detections near tile boundaries | No two detections of the same class are within 0.01 coordinate difference of each other (TILE_DUPLICATE_CONFIDENCE_THRESHOLD) |
Expected outcome: Tile boundary detections are merged. No duplicates with near-identical coordinates remain. Max execution time: 60s
Negative Scenarios
FT-N-01: Empty image returns 400
Summary: Verify that submitting an empty file to POST /detect returns a 400 error. Traces to: AC-API-2 (negative case) Category: API
Preconditions:
- Detections service is running
Input data: empty-image (zero-byte file)
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with empty-image as multipart file |
400 Bad Request |
Expected outcome: HTTP 400 with error message indicating empty or invalid image. Max execution time: 5s
FT-N-02: Invalid image data returns 400
Summary: Verify that submitting a corrupt/non-image file returns a 400 error. Traces to: AC-API-2 (negative case) Category: API
Preconditions:
- Detections service is running
Input data: corrupt-image (random binary data)
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect with corrupt-image as multipart file |
400 Bad Request |
Expected outcome: HTTP 400. Image decoding fails gracefully with an error response (not a 500). Max execution time: 5s
FT-N-03: Detection when engine unavailable returns 503
Summary: Verify that a detection request returns 503 when the engine cannot be initialized. Traces to: AC-API-2 (negative case), AC-EL-2 Category: API, Engine Lifecycle
Preconditions:
- Mock-loader configured to return errors (model download fails)
- Engine has not been previously initialized
Input data: small-image
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Configure mock-loader to return 503 on model requests | — |
| 2 | POST /detect with small-image |
503 Service Unavailable or 422 |
Expected outcome: HTTP 503 or 422 error indicating engine is not available. No crash or unhandled exception. Max execution time: 30s
FT-N-04: Duplicate media_id returns 409
Summary: Verify that submitting a second async detection request with an already-active media_id returns 409. Traces to: AC-API-3 (negative case) Category: API
Preconditions:
- Engine is initialized
- An async detection is already in progress for media_id "dup-test"
Input data: jwt-token, test-video
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | POST /detect/dup-test with config and auth headers |
{"status": "started"} |
| 2 | Immediately POST /detect/dup-test again (same media_id) |
409 Conflict |
Expected outcome: Second request is rejected with 409. First detection continues normally. Max execution time: 5s
FT-N-05: Missing classes.json prevents startup
Summary: Verify that the service fails or returns no detections when classes.json is not present. Traces to: RESTRICT-SW-4 Category: Restrictions
Preconditions:
- Detections service started WITHOUT classes.json volume mount
Input data: None
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Attempt to start detections service without classes.json | Service fails to start OR starts with empty class registry |
| 2 | If started: POST /detect with small-image |
Empty detections or error response |
Expected outcome: Service either fails to start or returns no detections. No unhandled crash. Max execution time: 30s
FT-N-06: Loader service unreachable during model download
Summary: Verify that the system handles Loader service being unreachable during engine initialization. Traces to: RESTRICT-ENV-1, AC-EL-2 Category: Resilience, Engine Lifecycle
Preconditions:
- Mock-loader is stopped or unreachable
- Engine not yet initialized
Input data: small-image
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Stop mock-loader service | — |
| 2 | POST /detect with small-image |
Error response (503 or 422) |
| 3 | GET /health |
aiAvailability reflects error state |
Expected outcome: Detection fails gracefully. Health endpoint reflects the engine error state. Max execution time: 30s
FT-N-07: Annotations service unreachable — detection continues
Summary: Verify that async detection continues even when the Annotations service is unreachable. Traces to: RESTRICT-ENV-2 Category: Resilience
Preconditions:
- Engine is initialized
- Mock-annotations is stopped or returns errors
- SSE client connected
Input data: jwt-token, test-video
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Stop mock-annotations service | — |
| 2 | POST /detect/test-media-006 with config and auth |
{"status": "started"} |
| 3 | Listen on SSE | Detection events still arrive (annotations POST failure is silently caught) |
| 4 | Wait for completion | Final AIProcessed event received |
Expected outcome: Detection processing completes. SSE events are delivered. Annotations POST failure does not stop the detection pipeline. Max execution time: 120s
FT-N-08: SSE queue overflow is silently dropped
Summary: Verify that when an SSE client's queue reaches 100 events, additional events are dropped without error. Traces to: AC-API-4 Category: API
Preconditions:
- Engine is initialized
- SSE client connected but NOT consuming events (stalled reader)
Input data: test-video (generates many events)
Steps:
| Step | Consumer Action | Expected System Response |
|---|---|---|
| 1 | Open SSE connection but pause reading | Connection established |
| 2 | POST /detect/test-media-007 with config that generates > 100 events |
{"status": "started"} |
| 3 | Wait for processing to complete | No error on the detection side |
| 4 | Resume reading SSE | Receive ≤ 100 events (queue max depth) |
Expected outcome: No crash or error. Overflow events are silently dropped. Detection completes normally. Max execution time: 120s