diff --git a/_docs/02_document/tests/test-data.md b/_docs/02_document/tests/test-data.md index fd4af12..1abe0cc 100644 --- a/_docs/02_document/tests/test-data.md +++ b/_docs/02_document/tests/test-data.md @@ -8,12 +8,9 @@ | classes-json | `classes.json` (repo root) | 19 detection classes with Id, Name, Color, MaxSizeM | All tests | Volume mount to detections `/app/classes.json` | Container restart | | image-small | `input_data/image_small.jpg` | JPEG 1280×720 — below tiling threshold (1920×1920) | FT-P-01..03, 05, 07, 13..15, FT-N-03, 06, NFT-PERF-01..02, NFT-RES-01, 03, NFT-SEC-01, NFT-RES-LIM-01 | Volume mount to consumer `/media/` | N/A (read-only) | | image-large | `input_data/image_large.JPG` | JPEG 6252×4168 — above tiling threshold, triggers GSD tiling | FT-P-04, 16, NFT-PERF-03 | Volume mount to consumer `/media/` | N/A (read-only) | -| image-dense-01 | `input_data/image_dense01.jpg` | JPEG 1280×720 — dense scene with many clustered objects | FT-P-06, NFT-RES-LIM-03 | Volume mount to consumer `/media/` | N/A (read-only) | -| image-dense-02 | `input_data/image_dense02.jpg` | JPEG 1920×1080 — dense scene variant, borderline tiling | FT-P-06 (variant) | Volume mount to consumer `/media/` | N/A (read-only) | | image-different-types | `input_data/image_different_types.jpg` | JPEG 900×1600 — varied object classes for class variant tests | FT-P-13 | Volume mount to consumer `/media/` | N/A (read-only) | | image-empty-scene | `input_data/image_empty_scene.jpg` | JPEG 1920×1080 — clean scene with no detectable objects | Edge case (zero detections) | Volume mount to consumer `/media/` | N/A (read-only) | | video-test-01 | `input_data/video_test01.mp4` | MP4 video — standard async/SSE/video detection tests | FT-P-08..12, FT-N-04, 07, NFT-PERF-04, NFT-RES-02, NFT-SEC-03 | Volume mount to consumer `/media/` | N/A (read-only) | -| video-1 | `input_data/video_1.mp4` | MP4 video — local variant for concurrent and resilience-style tests | NFT-RES-02 (variant), NFT-RES-04 | Volume mount to consumer `/media/` | N/A (read-only) | | video-1-faststart | `input_data/video_1_faststart.mp4` | MP4 video — faststart/local streaming variant | Streaming compatibility checks | Volume mount to consumer `/media/` | N/A (read-only) | | empty-image | Generated at build time | Zero-byte file | FT-N-01 | Generated in e2e/fixtures/ | N/A | | corrupt-image | Generated at build time | Random binary garbage (not valid image format) | FT-N-02 | Generated in e2e/fixtures/ | N/A | @@ -31,12 +28,9 @@ Each test run starts with fresh containers (`docker compose down -v && docker co | azaion.onnx | `_docs/00_problem/input_data/azaion.onnx` | YOLO ONNX detection model | All detection tests | | image_small.jpg | `_docs/00_problem/input_data/image_small.jpg` | 1280×720 aerial image | Single-frame detection, health, negative, perf tests | | image_large.JPG | `_docs/00_problem/input_data/image_large.JPG` | 6252×4168 aerial image | Tiling tests | -| image_dense01.jpg | `_docs/00_problem/input_data/image_dense01.jpg` | Dense scene 1280×720 | Dedup, detection cap tests | -| image_dense02.jpg | `_docs/00_problem/input_data/image_dense02.jpg` | Dense scene 1920×1080 | Dedup variant | | image_different_types.jpg | `_docs/00_problem/input_data/image_different_types.jpg` | Varied classes 900×1600 | Class variant tests | | image_empty_scene.jpg | `_docs/00_problem/input_data/image_empty_scene.jpg` | Empty scene 1920×1080 | Zero-detection edge case | | video_test01.mp4 | `_docs/00_problem/input_data/video_test01.mp4` | Standard video | Async, SSE, video, perf tests | -| video_1.mp4 | `_docs/00_problem/input_data/video_1.mp4` | Video variant | Resilience, concurrent tests | | video_1_faststart.mp4 | `_docs/00_problem/input_data/video_1_faststart.mp4` | Faststart video variant | Streaming compatibility checks | | classes.json | repo root `classes.json` | 19 detection classes | All tests | diff --git a/_docs/02_tasks/done/AZ-138_test_infrastructure.md b/_docs/02_tasks/done/AZ-138_test_infrastructure.md index 7800846..c830fd4 100644 --- a/_docs/02_tasks/done/AZ-138_test_infrastructure.md +++ b/_docs/02_tasks/done/AZ-138_test_infrastructure.md @@ -27,8 +27,6 @@ e2e/ ├── fixtures/ │ ├── image_small.jpg (1280×720 JPEG, aerial, detectable objects) │ ├── image_large.JPG (6252×4168 JPEG, triggers tiling) -│ ├── image_dense01.jpg (1280×720 JPEG, dense scene, clustered objects) -│ ├── image_dense02.jpg (1920×1080 JPEG, dense scene variant) │ ├── image_different_types.jpg (900×1600 JPEG, varied object classes) │ ├── image_empty_scene.jpg (1920×1080 JPEG, no detectable objects) │ ├── video_short01.mp4 (short MP4 with moving objects) @@ -130,8 +128,6 @@ Two Docker Compose profiles: | `reset_mocks` | function (autouse) | Calls `POST /mock/reset` on both mocks before each test | | `image_small` | session | Reads `image_small.jpg` from `/media/` volume | | `image_large` | session | Reads `image_large.JPG` from `/media/` volume | -| `image_dense` | session | Reads `image_dense01.jpg` from `/media/` volume | -| `image_dense_02` | session | Reads `image_dense02.jpg` from `/media/` volume | | `image_different_types` | session | Reads `image_different_types.jpg` from `/media/` volume | | `image_empty_scene` | session | Reads `image_empty_scene.jpg` from `/media/` volume | | `video_short_path` | session | Path to `video_short01.mp4` on `/media/` volume | @@ -150,8 +146,6 @@ Two Docker Compose profiles: | classes.json | repo root `classes.json` | JSON (19 objects with Id, Name, Color, MaxSizeM) | All tests (volume mount to detections) | | image_small.jpg | `input_data/image_small.jpg` | JPEG 1280×720 | Health, single image, filtering, negative, performance tests | | image_large.JPG | `input_data/image_large.JPG` | JPEG 6252×4168 | Tiling tests, performance tests | -| image_dense01.jpg | `input_data/image_dense01.jpg` | JPEG 1280×720 dense scene | Dedup tests, detection cap tests | -| image_dense02.jpg | `input_data/image_dense02.jpg` | JPEG 1920×1080 dense scene | Dedup variant | | image_different_types.jpg | `input_data/image_different_types.jpg` | JPEG 900×1600 varied classes | Weather mode class variant tests | | image_empty_scene.jpg | `input_data/image_empty_scene.jpg` | JPEG 1920×1080 empty | Zero-detection edge case | | video_short01.mp4 | `input_data/video_short01.mp4` | MP4 short video | Async, SSE, video processing tests | diff --git a/e2e/conftest.py b/e2e/conftest.py index df9f772..eea9ab8 100644 --- a/e2e/conftest.py +++ b/e2e/conftest.py @@ -228,17 +228,6 @@ def image_small(): def image_large(): return _read_media("image_large.JPG") - -@pytest.fixture(scope="session") -def image_dense(): - return _read_media("image_dense01.jpg") - - -@pytest.fixture(scope="session") -def image_dense_02(): - return _read_media("image_dense02.jpg") - - @pytest.fixture(scope="session") def image_different_types(): return _read_media("image_different_types.jpg") diff --git a/src/annotation.pxd b/src/annotation.pxd index 795220b..1281de9 100644 --- a/src/annotation.pxd +++ b/src/annotation.pxd @@ -7,6 +7,6 @@ cdef class Detection: cdef class Annotation: cdef public str name cdef public str original_media_name - cdef long time + cdef public long time cdef public list[Detection] detections cdef public bytes image diff --git a/src/main.py b/src/main.py index 3d91020..5217704 100644 --- a/src/main.py +++ b/src/main.py @@ -15,6 +15,7 @@ import cv2 import jwt as pyjwt import numpy as np import requests as http_requests +from loguru import logger from fastapi import Body, Depends, FastAPI, File, Form, HTTPException, Request, UploadFile from fastapi.responses import Response, StreamingResponse from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer @@ -270,7 +271,8 @@ def _post_media_record(payload: dict, bearer: str) -> bool: timeout=30, ) return r.status_code in (200, 201) - except Exception: + except Exception as exc: + logger.warning(f"Failed to create media record in annotations service: {exc}") return False @@ -284,7 +286,8 @@ def _put_media_status(media_id: str, media_status: int, bearer: str) -> bool: timeout=30, ) return r.status_code in (200, 204) - except Exception: + except Exception as exc: + logger.warning(f"Failed to update media status in annotations service for {media_id}: {exc}") return False @@ -332,10 +335,13 @@ def _post_annotation_to_service(token_mgr: TokenManager, media_id: str, try: token = token_mgr.get_valid_token() image_b64 = base64.b64encode(annotation.image).decode() if annotation.image else None + total_seconds = int(annotation.time // 1000) if annotation.time else 0 + hours, remainder = divmod(total_seconds, 3600) + minutes, seconds = divmod(remainder, 60) payload = { "mediaId": media_id, "source": 0, - "videoTime": f"00:00:{annotation.time // 1000:02d}" if annotation.time else "00:00:00", + "videoTime": f"{hours:02d}:{minutes:02d}:{seconds:02d}", "detections": [d.model_dump() for d in dtos], } if image_b64: @@ -346,8 +352,10 @@ def _post_annotation_to_service(token_mgr: TokenManager, media_id: str, headers={"Authorization": f"Bearer {token}"}, timeout=30, ) - except Exception: - pass + except Exception as exc: + logger.warning( + f"Failed to post annotation to annotations service for media {media_id}: {exc}" + ) def _cleanup_channel(channel_id: str):