[AZ-284] Autodev baseline + testability refactor

Phase A baseline outputs from /autodev (Steps 1-5):
- Problem & solution docs (_docs/00_problem, _docs/01_solution)
- Codebase documentation (_docs/02_document) incl. architecture,
  module-layout, glossary, system-flows, baseline compliance scan
- Test specs (blackbox, performance, resilience, security, resource,
  traceability matrix)
- Test task decomposition (_docs/02_tasks/todo): AZ-285..AZ-290
- Testability refactor (_docs/04_refactoring/01-testability-refactoring):
  - TC-01 Move DownloadedTileInfoV2 + new ExistingTileInfo to Common.DTO
  - TC-02 Replace dead ISatelliteDownloader API with real signatures
  - TC-03 GoogleMapsDownloaderV2 implements ISatelliteDownloader
  - TC-04 TileService depends on ISatelliteDownloader (mockable)
  - TC-05 DI + endpoints use ISatelliteDownloader
- Test runner scripts (scripts/run-tests.sh, run-performance-tests.sh)
- Autodev state pointer (_docs/_autodev_state.md)

Prepares the codebase for AZ-285..AZ-290 unit/integration test work.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-10 04:44:08 +03:00
parent 25a644a9bf
commit b0fffa6d42
68 changed files with 4192 additions and 11 deletions
@@ -0,0 +1,50 @@
# Testability Refactoring — List of Changes
Mode: guided
Source: autodev-testability-analysis + architecture-compliance-baseline F1/F2
## TC-01: Move DownloadedTileInfoV2 to Common
**Files**: `SatelliteProvider.Services/GoogleMapsDownloaderV2.cs``SatelliteProvider.Common/DTO/DownloadedTileInfoV2.cs`
**Problem**: `DownloadedTileInfoV2` is defined in Services alongside the concrete downloader. The interface in Common cannot reference it, blocking the interface fix.
**Change**: Move the record to `SatelliteProvider.Common.DTO`. Update namespace references in GoogleMapsDownloaderV2 and TileService.
**Risk**: Low — record has no dependencies on Services-specific types.
## TC-02: Update ISatelliteDownloader interface
**Files**: `SatelliteProvider.Common/Interfaces/ISatelliteDownloader.cs`
**Problem**: Current interface has a single method `GetTiles` with a signature that doesn't match any usage in the codebase (dead code, per baseline F2).
**Change**: Replace with the two methods actually needed by callers:
- `DownloadSingleTileAsync(double latitude, double longitude, int zoomLevel, CancellationToken token = default)`
- `GetTilesWithMetadataAsync(GeoPoint centerGeoPoint, double radiusM, int zoomLevel, IEnumerable<ExistingTileInfo> existingTiles, CancellationToken token = default)`
Introduce `ExistingTileInfo` record in Common to avoid referencing DataAccess.TileEntity from the interface.
**Risk**: Low — the old interface was unused.
## TC-03: GoogleMapsDownloaderV2 implements ISatelliteDownloader
**Files**: `SatelliteProvider.Services/GoogleMapsDownloaderV2.cs`
**Problem**: Concrete class does not implement the interface, so it cannot be swapped in tests (baseline F1).
**Change**: Add `: ISatelliteDownloader` to class declaration. Adjust `GetTilesWithMetadataAsync` parameter from `IEnumerable<TileEntity>` to `IEnumerable<ExistingTileInfo>`.
**Risk**: Medium — method signature change requires updating callers.
**Dependencies**: TC-01, TC-02
## TC-04: TileService depends on ISatelliteDownloader
**Files**: `SatelliteProvider.Services/TileService.cs`
**Problem**: Constructor takes `GoogleMapsDownloaderV2` (concrete). Cannot mock in unit tests.
**Change**: Change constructor parameter and field type from `GoogleMapsDownloaderV2` to `ISatelliteDownloader`. Map `TileEntity` to `ExistingTileInfo` before calling the interface.
**Risk**: Low — no public API change.
**Dependencies**: TC-02, TC-03
## TC-05: Update DI registration and API endpoint
**Files**: `SatelliteProvider.Api/Program.cs`
**Problem**: `GoogleMapsDownloaderV2` registered as concrete singleton. `ServeTile` endpoint injects concrete class directly.
**Change**: Register as `ISatelliteDownloader``GoogleMapsDownloaderV2`. Change `ServeTile` to inject `ISatelliteDownloader`.
**Risk**: Low — behavior unchanged, just the injection type.
**Dependencies**: TC-03
## Deferred to Step 8 Refactor
- **Medium finding: ServeTile bypasses service layer** — The endpoint directly uses `ITileRepository` and the downloader instead of `ITileService`. Moving this logic into the service layer would be cleaner but changes module boundaries (not allowed in testability step).
- **Medium finding: No physical boundaries in Services project** — All services share one project. Splitting into separate projects is a structural change beyond testability scope.
@@ -0,0 +1,38 @@
# Testability Changes Summary
## Applied Changes
### TC-01: Moved DownloadedTileInfoV2 to Common/DTO
- **Created**: `SatelliteProvider.Common/DTO/DownloadedTileInfoV2.cs`
- **Created**: `SatelliteProvider.Common/DTO/ExistingTileInfo.cs`
- **Modified**: `SatelliteProvider.Services/GoogleMapsDownloaderV2.cs` — removed inline record definition, added import
- **Why**: The return type of the downloader must be accessible from the interface in Common
### TC-02: Updated ISatelliteDownloader interface
- **Modified**: `SatelliteProvider.Common/Interfaces/ISatelliteDownloader.cs`
- **Old API**: `Task GetTiles(GeoPoint, double, int, CancellationToken)` — never implemented, dead code
- **New API**: `DownloadSingleTileAsync(...)` + `GetTilesWithMetadataAsync(...)` — matches actual usage
- **Why**: Previous interface was dead code; new interface enables mocking the downloader in tests
### TC-03: GoogleMapsDownloaderV2 implements ISatelliteDownloader
- **Modified**: `SatelliteProvider.Services/GoogleMapsDownloaderV2.cs`
- **Change**: Class declaration now includes `: ISatelliteDownloader`; `GetTilesWithMetadataAsync` parameter changed from `IEnumerable<TileEntity>` to `IEnumerable<ExistingTileInfo>`
- **Why**: Concrete class must implement the interface for DI and mocking to work
### TC-04: TileService depends on ISatelliteDownloader
- **Modified**: `SatelliteProvider.Services/TileService.cs`
- **Change**: Constructor parameter and field type changed from `GoogleMapsDownloaderV2` to `ISatelliteDownloader`; added mapping from `TileEntity` to `ExistingTileInfo` before calling the interface
- **Why**: Unit tests can now mock the downloader via the interface
### TC-05: Updated DI registration and API endpoints
- **Modified**: `SatelliteProvider.Api/Program.cs`
- **Changes**:
- DI: `AddSingleton<GoogleMapsDownloaderV2>()``AddSingleton<ISatelliteDownloader, GoogleMapsDownloaderV2>()`
- `ServeTile` endpoint: parameter `GoogleMapsDownloaderV2 downloader``ISatelliteDownloader downloader`
- `GetTileByLatLon` endpoint: parameter `GoogleMapsDownloaderV2 downloader``ISatelliteDownloader downloader`
- **Why**: Endpoints should inject the interface, not the concrete class
## Deferred to Step 8
- ServeTile and GetTileByLatLon endpoints bypass the service layer (inject repository + downloader directly)
- No physical project boundaries between logical components in the Services project