Skip to content
Snippets Groups Projects
MetadataDatabaseFactory_test.py 14.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • import datetime
    import unittest
    from dateutil import tz
    from unittest.mock import AsyncMock, patch
    from databases import Database
    
    from obspy import UTCDateTime
    
    from geomagio.api.db import MetadataDatabaseFactory
    from geomagio.metadata import Metadata, MetadataCategory
    
    
    class TestMetadataDatabaseFactory(unittest.IsolatedAsyncioTestCase):
    
        @patch("databases.Database.execute", new_callable=AsyncMock)
        async def test_create_metadata_defaults(self, mock_execute):
            test_data = Metadata(
                category=MetadataCategory.INSTRUMENT,
                created_by="test_metadata.py",
                network="NT",
                station="BDT",
                metadata={
                    "type": "FGE",
                    "channels": {
                        "U": [{"channel": "U_Volt", "offset": 0, "scale": 313.2}],
                        "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.3}],
                        "W": [{"channel": "W_Volt", "offset": 0, "scale": 312.0}],
                    },
                    "electronics": {
                        "serial": "E0542",
                        "x-scale": 313.2,
                        "y-scale": 312.3,
                        "z-scale": 312.0,
                        "temperature-scale": 0.01,
                    },
                    "sensor": {
                        "serial": "S0419",
                        "x-constant": 36958,
                        "y-constant": 36849,
                        "z-constant": 36811,
                    },
                },
            )
    
            db = Database("sqlite:///:memory:")
    
            await MetadataDatabaseFactory(database=db).create_metadata(test_data)
    
            # assert data_valid, priority, and status are set to the correct defaults
            expected_values = {
                "category": "instrument",
                "created_by": "test_metadata.py",
                "network": "NT",
                "station": "BDT",
                "metadata": {
                    "type": "FGE",
                    "channels": {
                        "U": [{"channel": "U_Volt", "offset": 0, "scale": 313.2}],
                        "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.3}],
                        "W": [{"channel": "W_Volt", "offset": 0, "scale": 312.0}],
                    },
                    "electronics": {
                        "serial": "E0542",
                        "x-scale": 313.2,
                        "y-scale": 312.3,
                        "z-scale": 312.0,
                        "temperature-scale": 0.01,
                    },
                    "sensor": {
                        "serial": "S0419",
                        "x-constant": 36958,
                        "y-constant": 36849,
                        "z-constant": 36811,
                    },
                },
                "data_valid": True,
                "priority": 1,
                "status": "new",
            }
    
            mock_execute.assert_called_once()
            called_params = mock_execute.call_args.args[0].compile().params
    
            assert called_params == expected_values
    
        @patch("databases.Database.execute", new_callable=AsyncMock)
    
        async def test_create_metadata_created_time(self, mock_execute):
    
            now = UTCDateTime()
            test_data = Metadata(
                created_time=now,
                category=MetadataCategory.INSTRUMENT,
                created_by="test_metadata.py",
                network="NT",
                station="BDT",
                metadata={
                    "type": "FGE",
                    "channels": {
                        "U": [{"channel": "U_Volt", "offset": 0, "scale": 313.2}],
                        "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.3}],
                        "W": [{"channel": "W_Volt", "offset": 0, "scale": 312.0}],
                    },
                    "electronics": {
                        "serial": "E0542",
                        "x-scale": 313.2,
                        "y-scale": 312.3,
                        "z-scale": 312.0,
                        "temperature-scale": 0.01,
                    },
                    "sensor": {
                        "serial": "S0419",
                        "x-constant": 36958,
                        "y-constant": 36849,
                        "z-constant": 36811,
                    },
                },
            )
    
            db = Database("sqlite:///:memory:")
    
            await MetadataDatabaseFactory(database=db).create_metadata(test_data)
    
    
            # assert data_valid, priority, and status are set to the correct defaults
    
            expected_values = {
                "created_time": datetime.datetime(
                    year=now.year,
                    month=now.month,
                    day=now.day,
                    hour=now.hour,
                    minute=now.minute,
                    second=now.second,
                    microsecond=now.microsecond,
                    tzinfo=tz.tzutc(),
                ),
                "category": "instrument",
                "created_by": "test_metadata.py",
                "network": "NT",
                "station": "BDT",
                "metadata": {
                    "type": "FGE",
                    "channels": {
                        "U": [{"channel": "U_Volt", "offset": 0, "scale": 313.2}],
                        "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.3}],
                        "W": [{"channel": "W_Volt", "offset": 0, "scale": 312.0}],
                    },
                    "electronics": {
                        "serial": "E0542",
                        "x-scale": 313.2,
                        "y-scale": 312.3,
                        "z-scale": 312.0,
                        "temperature-scale": 0.01,
                    },
                    "sensor": {
                        "serial": "S0419",
                        "x-constant": 36958,
                        "y-constant": 36849,
                        "z-constant": 36811,
                    },
                },
                "data_valid": True,
                "priority": 1,
                "status": "new",
            }
    
            mock_execute.assert_called_once()
            called_params = mock_execute.call_args.args[0].compile().params
    
            assert called_params == expected_values
    
        @patch("databases.Database.execute", new_callable=AsyncMock)
    
        async def test_create_metadata_with_ids(self, mock_execute):
    
                metadata_id=5678,
                category=MetadataCategory.INSTRUMENT,
                created_by="test_metadata.py",
                network="NT",
                station="BDT",
                metadata={
                    "type": "FGE",
                    "channels": {
                        "U": [{"channel": "U_Volt", "offset": 0, "scale": 313.2}],
                        "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.3}],
                        "W": [{"channel": "W_Volt", "offset": 0, "scale": 312.0}],
                    },
                    "electronics": {
                        "serial": "E0542",
                        "x-scale": 313.2,
                        "y-scale": 312.3,
                        "z-scale": 312.0,
                        "temperature-scale": 0.01,
                    },
                    "sensor": {
                        "serial": "S0419",
                        "x-constant": 36958,
                        "y-constant": 36849,
                        "z-constant": 36811,
                    },
                },
            )
    
            db = Database("sqlite:///:memory:")
    
            await MetadataDatabaseFactory(database=db).create_metadata(test_data)
    
    
            # assert id and metadata_id are removed
            expected_values = {
                "category": "instrument",
                "created_by": "test_metadata.py",
                "network": "NT",
                "station": "BDT",
                "metadata": {
                    "type": "FGE",
                    "channels": {
                        "U": [{"channel": "U_Volt", "offset": 0, "scale": 313.2}],
                        "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.3}],
                        "W": [{"channel": "W_Volt", "offset": 0, "scale": 312.0}],
                    },
                    "electronics": {
                        "serial": "E0542",
                        "x-scale": 313.2,
                        "y-scale": 312.3,
                        "z-scale": 312.0,
                        "temperature-scale": 0.01,
                    },
                    "sensor": {
                        "serial": "S0419",
                        "x-constant": 36958,
                        "y-constant": 36849,
                        "z-constant": 36811,
                    },
                },
                "data_valid": True,
                "priority": 1,
                "status": "new",
            }
    
    
            mock_execute.assert_called_once()
            called_params = mock_execute.call_args.args[0].compile().params
    
    
            assert called_params == expected_values
    
    
        @patch("databases.Database.execute", new_callable=AsyncMock)
        async def test_create_metadata_with_starttime_and_endtime(self, mock_execute):
            now = UTCDateTime()
            t = UTCDateTime(2020, 1, 3, 17, 24, 40)
            test_data = Metadata(
                created_by="test_metadata.py",
                created_time=now,
                starttime=t,
                endtime=t,
                network="NT",
                station="BOU",
                channel=None,
                location=None,
                category=MetadataCategory.READING,
                priority=1,
                data_valid=True,
                metadata={},
            )
    
            db = Database("sqlite:///:memory:")
    
            await MetadataDatabaseFactory(database=db).create_metadata(test_data)
    
            # assert starttime and endtime are strings of expected UTCDateTime
            expected_values = {
                "category": "reading",
                "created_time": datetime.datetime(
                    year=now.year,
                    month=now.month,
                    day=now.day,
                    hour=now.hour,
                    minute=now.minute,
                    second=now.second,
                    microsecond=now.microsecond,
                    tzinfo=tz.tzutc(),
                ),
                "created_by": "test_metadata.py",
                "starttime": datetime.datetime(
                    year=t.year,
                    month=t.month,
                    day=t.day,
                    hour=t.hour,
                    minute=t.minute,
                    second=t.second,
                    microsecond=t.microsecond,
                    tzinfo=tz.tzutc(),
                ),
                "endtime": datetime.datetime(
                    year=t.year,
                    month=t.month,
                    day=t.day,
                    hour=t.hour,
                    minute=t.minute,
                    second=t.second,
                    microsecond=t.microsecond,
                    tzinfo=tz.tzutc(),
                ),
                "network": "NT",
                "station": "BOU",
                "metadata": {},
                "data_valid": True,
                "priority": 1,
                "status": "new",
            }
    
            mock_execute.assert_called_once()
            called_params = mock_execute.call_args.args[0].compile().params
    
            assert called_params == expected_values
    
        @patch("databases.Database.execute", new_callable=AsyncMock)
        async def test_create_metadata_with_times_as_datetime(self, mock_execute):
            # assert datetime is aware if not explicitly set by the user
            s = datetime.datetime(2020, 1, 3, 17, 24, 40)
            e = datetime.datetime(2020, 1, 3, 17, 24, 40, tzinfo=tz.tzutc())
            test_data = Metadata(
                created_by="test_metadata.py",
                starttime=s,
                endtime=e,
                network="NT",
                station="BOU",
                channel=None,
                location=None,
                category=MetadataCategory.READING,
                priority=1,
                data_valid=True,
                metadata={},
            )
    
            db = Database("sqlite:///:memory:")
    
            await MetadataDatabaseFactory(database=db).create_metadata(test_data)
    
            mock_execute.assert_called_once()
            called_params = mock_execute.call_args.args[0].compile().params
    
            assert called_params["starttime"] == datetime.datetime(
                year=s.year,
                month=s.month,
                day=s.day,
                hour=s.hour,
                minute=s.minute,
                second=s.second,
                microsecond=s.microsecond,
                tzinfo=tz.tzutc(),
            )
            assert called_params["endtime"] == datetime.datetime(
                year=e.year,
                month=e.month,
                day=e.day,
                hour=e.hour,
                minute=e.minute,
                second=e.second,
                microsecond=e.microsecond,
                tzinfo=tz.tzutc(),
            )
    
    
        @patch("databases.Database.execute", new_callable=AsyncMock)
        @patch("databases.Database.fetch_all", new_callable=AsyncMock)
        async def test_update_metadata_defaults(self, mock_fetch_all, mock_execute):
            test_data = Metadata(
                category=MetadataCategory.INSTRUMENT,
                network="NT",
                station="BDT",
                metadata={
                    "type": "FGE",
                    "channels": {
                        "U": [{"channel": "U_Volt", "offset": 0, "scale": 313.2}],
                        "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.3}],
                        "W": [{"channel": "W_Volt", "offset": 0, "scale": 312.0}],
                    },
                    "electronics": {
                        "serial": "E0542",
                        "x-scale": 313.2,
                        "y-scale": 312.3,
                        "z-scale": 312.0,
                        "temperature-scale": 0.01,
                    },
                    "sensor": {
                        "serial": "S0419",
                        "x-constant": 36958,
                        "y-constant": 36849,
                        "z-constant": 36811,
                    },
                },
            )
    
            db = Database("sqlite:///:memory:")
            yesterday = datetime.datetime(2024, 11, 1, 8, 15, tzinfo=tz.tzutc())
    
    
    Hobbs, Alexandra (Contractor)'s avatar
    Hobbs, Alexandra (Contractor) committed
            mock_fetch_all.return_value = (
                {
                    "id": 1234,
                    "created_time": yesterday,
                    "category": "instrument",
                    "network": "NT",
                    "station": "BDT",
                    "metadata": {
                        "foo": "bar",
                    },
    
    Hobbs, Alexandra (Contractor)'s avatar
    Hobbs, Alexandra (Contractor) committed
            )
    
    Hobbs, Alexandra (Contractor)'s avatar
    Hobbs, Alexandra (Contractor) committed
            await MetadataDatabaseFactory(database=db).update_metadata(
                meta=test_data, updated_by="test_user"
            )
    
    
            assert mock_fetch_all.call_count == 2
            assert mock_execute.call_count == 2
    
            first_called_params = mock_execute.call_args_list[0].args[0].compile().params
            second_called_params = mock_execute.call_args_list[1].args[0].compile().params
    
            assert first_called_params["metadata_id"] == 1234
            assert first_called_params["created_time"] == yesterday
            assert first_called_params["metadata"] == {"foo": "bar"}
    
            assert second_called_params["updated_by"] == "test_user"
            assert second_called_params["updated_time"] is not None
            assert second_called_params["metadata"] == test_data.metadata