Developer Guide
===============
This document complements the guidelines set out in the
`SKA telescope developer portal `_.
Clone the repository and its submodules:
.. code-block:: bash
git clone --recursive git@gitlab.com:ska-telescope/sdp/ska-sdp-global-sky-model.git
The repository is integrated with the `ska-cicd-makefile `_
submodule, which provides standardised ``make`` commands, for example, for linting and testing.
The GSM code is based on `FastAPI `_ and `SQLAlchemy `_.
It connects to two database backends to provide its full functionality:
- **PostgreSQL Database**
Stores the global sky model catalogue data in the following tables:
- ``SkyComponent`` table: Contains all sky component properties
- ``GlobalSkyModelMetadata`` table: Stores catalogue version information and reference frequency
The schema is dynamically generated from the ``ska-sdp-datamodels`` package to ensure
consistency with the canonical data model. See :ref:`db_design`.
- **etcd**
A distributed key-value store used by the SKA SDP Configuration database.
The application uses ``etcd`` to watch for flow requests (data processing workflows)
(see :ref:`sdp_request`).
The ``request_responder.py`` module starts a background thread that watches etcd for
flow entries requesting local sky models. When a flow is detected, it processes the
request and writes the results to the specified location.
The FastAPI service provides REST endpoints for:
- Querying the Global Sky Model database (see :ref:`lsm_browser`)
- Uploding new catalogue data (see :ref:`upload_api`)
- Monitoring the upload process (see :ref:`upload_api`)
Running the application tests
-----------------------------
The API is tested using the pytest framework alongside FastAPI's TestClient. The tests can be run with:
.. code-block:: bash
$ make python-tests
Test database setup
^^^^^^^^^^^^^^^^^^^
The tests use an in-memory SQLite database instead of PostgreSQL to avoid the need for a running
database instance during testing.
Database Mocking Strategy
.........................
The test suite implements several key mocking strategies:
1. In-memory SQLite database: Tests use ``sqlite:///:memory:`` instead of PostgreSQL, with
``StaticPool`` to maintain a single connection across tests.
2. Q3C function mocking: PostgreSQL's Q3C extension for spherical coordinate searches is
mocked for SQLite using a simple box check approximation:
.. code-block:: python
@event.listens_for(engine, "connect")
def register_q3c_mock(dbapi_conn, connection_record):
def q3c_radial_query_mock(ra1, dec1, ra2, dec2, radius):
# Simple box check - not accurate but sufficient for testing
ra_diff = abs(ra1 - ra2)
dec_diff = abs(dec1 - dec2)
return 1 if (ra_diff <= radius and dec_diff <= radius) else 0
dbapi_conn.create_function("q3c_radial_query", 5, q3c_radial_query_mock)
3. JSONB compatibility: PostgreSQL's JSONB type is replaced with JSON for SQLite compatibility:
.. code-block:: python
@event.listens_for(Base.metadata, "before_create")
def replace_jsonb_sqlite(target, connection, **kw):
if connection.dialect.name == "sqlite":
for table in target.tables.values():
table.schema = None
for column in table.columns:
if isinstance(column.type, JSONB):
column.type = JSON()
4. Startup function mocking: Database connection checks and background threads are mocked to
prevent actual connections during tests:
.. code-block:: python
with patch("ska_sdp_global_sky_model.api.app.main.wait_for_db"), \\
patch("ska_sdp_global_sky_model.api.app.main.start_thread"), \\
patch("ska_sdp_global_sky_model.api.app.main.q3c_index"), \\
patch("ska_sdp_global_sky_model.api.app.main.engine", engine):
# Test code here