diff --git a/docker-compose/lofar-device-base/Dockerfile b/docker-compose/lofar-device-base/Dockerfile index 77818acac2a9954d2fd6177d1948ce4e84c7619d..efa54992e02b49e6a6d2a2de03ca4421c58b9f01 100644 --- a/docker-compose/lofar-device-base/Dockerfile +++ b/docker-compose/lofar-device-base/Dockerfile @@ -32,9 +32,7 @@ RUN if [ $TANGO_STATION_CONTROL ]; then \ # install and use ephimerides and geodetic ("measures") tables for casacore. # we install a _stub_ since the tables need to be deployed explicitly from within the software. RUN sudo mkdir -p /opt/IERS && sudo chmod a+rwx /opt/IERS -ARG IERS_DIRNAME=IERS-1970-01-01T00:00:00-stub -COPY lofar-device-base/WSRT_Measures_stub /opt/IERS/${IERS_DIRNAME} -RUN ln -sfT /opt/IERS/${IERS_DIRNAME} /opt/IERS/current +COPY lofar-device-base/WSRT_Measures_stub /opt/IERS COPY lofar-device-base/casarc /home/tango/.casarc diff --git a/docker-compose/lofar-device-base/WSRT_Measures_stub/geodetic/TAI_UTC/table.dat b/docker-compose/lofar-device-base/WSRT_Measures_stub/geodetic/TAI_UTC/table.dat index bc00ed3ee6d2eed34d9b02f755c07429a78a0980..1798e8a55e4426db178dbdd8faf3afa3d88e1248 100644 Binary files a/docker-compose/lofar-device-base/WSRT_Measures_stub/geodetic/TAI_UTC/table.dat and b/docker-compose/lofar-device-base/WSRT_Measures_stub/geodetic/TAI_UTC/table.dat differ diff --git a/docker-compose/lofar-device-base/casarc b/docker-compose/lofar-device-base/casarc index 78e7a19ed26fd4aa5b2fd7aad6f0b3bd4179f6f8..61acc8b4efaeb1699540b14dbdbda99f64d4595e 100644 --- a/docker-compose/lofar-device-base/casarc +++ b/docker-compose/lofar-device-base/casarc @@ -1 +1 @@ -measures.directory: /opt/IERS/current +measures.directory: /opt/IERS diff --git a/docker-compose/object-storage.yml b/docker-compose/object-storage.yml index 4fc5f038b19a6c775866cbb167cc3139295b509d..66dd059e4cc0d2e2fc672c862d0ec796f29673d6 100644 --- a/docker-compose/object-storage.yml +++ b/docker-compose/object-storage.yml @@ -20,8 +20,12 @@ services: entrypoint: '' command: > sh -c "mc alias set object-storage http://s3.service.consul:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD + echo 'Initialising caltables' mc mb --with-versioning object-storage/caltables mc cp --recursive /opt/lofar/tango/docker-compose/object-storage/caltables/ object-storage/caltables/ + echo 'Initialising IERS tables' + mc mb --with-versioning object-storage/iers + mc cp --recursive /opt/lofar/tango/docker-compose/object-storage/iers/ object-storage/iers/ date +'%F %T' echo 'Initialisation completed'" diff --git a/docker-compose/object-storage/iers/ephemerides/DE200/table.dat b/docker-compose/object-storage/iers/ephemerides/DE200/table.dat new file mode 100644 index 0000000000000000000000000000000000000000..1f7869a8f1af1f6d4089128eeed130c78d5c6ae2 Binary files /dev/null and b/docker-compose/object-storage/iers/ephemerides/DE200/table.dat differ diff --git a/docker-compose/object-storage/iers/ephemerides/DE200/table.f0 b/docker-compose/object-storage/iers/ephemerides/DE200/table.f0 new file mode 100644 index 0000000000000000000000000000000000000000..5c14b2d3c72812c815005ec6fbd10110c7ceab70 Binary files /dev/null and b/docker-compose/object-storage/iers/ephemerides/DE200/table.f0 differ diff --git a/docker-compose/object-storage/iers/ephemerides/DE200/table.f0i b/docker-compose/object-storage/iers/ephemerides/DE200/table.f0i new file mode 100644 index 0000000000000000000000000000000000000000..d50b1bdd28ae76847df63f335bcbdd1bd1e7cc9f Binary files /dev/null and b/docker-compose/object-storage/iers/ephemerides/DE200/table.f0i differ diff --git a/docker-compose/object-storage/iers/ephemerides/DE200/table.info b/docker-compose/object-storage/iers/ephemerides/DE200/table.info new file mode 100644 index 0000000000000000000000000000000000000000..d1fa70b4e608c03fc4f6da5a213c36d568f9fbc4 Binary files /dev/null and b/docker-compose/object-storage/iers/ephemerides/DE200/table.info differ diff --git a/docker-compose/object-storage/iers/ephemerides/DE200/table.lock b/docker-compose/object-storage/iers/ephemerides/DE200/table.lock new file mode 100644 index 0000000000000000000000000000000000000000..dab1a78a5dec98a99cad64cd140e1308abf761a8 Binary files /dev/null and b/docker-compose/object-storage/iers/ephemerides/DE200/table.lock differ diff --git a/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.dat b/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.dat new file mode 100644 index 0000000000000000000000000000000000000000..1798e8a55e4426db178dbdd8faf3afa3d88e1248 Binary files /dev/null and b/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.dat differ diff --git a/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.f0 b/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.f0 new file mode 100644 index 0000000000000000000000000000000000000000..60f2139e506a2e278c9600170c1013488aa42201 Binary files /dev/null and b/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.f0 differ diff --git a/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.info b/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.info new file mode 100644 index 0000000000000000000000000000000000000000..62db44592e98cff62f07dbc6c4c9092dd1ab81d6 Binary files /dev/null and b/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.info differ diff --git a/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.lock b/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.lock new file mode 100644 index 0000000000000000000000000000000000000000..87dc3b3fdb54598a55a3cedcb6ca1b35081d70d4 Binary files /dev/null and b/docker-compose/object-storage/iers/geodetic/TAI_UTC/table.lock differ diff --git a/infra/jobs/station/device-server.levant.nomad b/infra/jobs/station/device-server.levant.nomad index 98083ec80b6a339c3b47764ef59f8c0bfaea4dd6..ed0074d107338b3614fdc1658cabdec20db4261b 100644 --- a/infra/jobs/station/device-server.levant.nomad +++ b/infra/jobs/station/device-server.levant.nomad @@ -8,6 +8,56 @@ job "device-servers" { delay_function = "constant" } + group "sync-IERS" { + count = 1 + + network { + mode = "bridge" + + port "metrics" { + to = 8081 + } + } + + service { + tags = ["scrape"] + name = "sync-IERS" + port = "sync-IERS" + meta { + metrics_address = "${NOMAD_ADDR_metrics}" + metrics_path = "/" + } + } + + volume "IERS" { + type = "host" + read_only = false + source = "IERS" + } + + task "sync-IERS" { + driver = "docker" + + volume_mount { + volume = "IERS" + destination = "/opt/IERS" + read_only = false + } + + config { + image = "minio/mc:latest" + entrypoint = "" + command = "/bin/bash" + args = ["-c", "mc alias set object-storage http://s3.service.consul:9000 [[.object_storage.user.name]] [[.object_storage.user.pass]] && mc mirror --preserve --watch object-storage/iers/ /opt/IERS/" ] + } + + resources { + cpu = 10 + memory = 128 + } + } + } + [[ range $device := $.devices ]] [[ with $device ]] [[ $class := .class ]] @@ -31,6 +81,12 @@ job "device-servers" { [[ end ]] } + volume "IERS" { + type = "host" + read_only = true + source = "IERS" + } + service { tags = ["scrape"] name = "device-[[ $name ]]" @@ -44,6 +100,12 @@ job "device-servers" { task "device-[[ $name ]]" { driver = "docker" + volume_mount { + volume = "IERS" + destination = "/opt/IERS" + read_only = true + } + config { image = "[[ $.registry.astron.url ]]/lofar-device-base:[[ $.image_tag ]]" ports = [ diff --git a/infra/jobs/station/nomad-client.nomad b/infra/jobs/station/nomad-client.nomad index 80869738b76c62a3ffd1699668b0bab466b5d356..1d82d38c66545846392a8122ea471317ba77888c 100644 --- a/infra/jobs/station/nomad-client.nomad +++ b/infra/jobs/station/nomad-client.nomad @@ -69,6 +69,7 @@ job "nomad-client" { - mkdir -p /localdata/volumes/monitoring-loki-data - mkdir -p /localdata/volumes/tango-database - mkdir -p /localdata/volumes/object-storage-data + - mkdir -p /localdata/volumes/IERS-data - chmod 0777 /localdata/volumes/* - [systemctl, enable, consul.service] - [systemctl, start, consul.service] @@ -157,6 +158,10 @@ job "nomad-client" { path = "/localdata/volumes/object-storage-data" } + host_volume "IERS" { + path = "/localdata/volumes/IERS-data" + } + host_volume "jupyter-notebooks" { path = "/localdata/volumes/jupyter-notebooks" } diff --git a/infra/jobs/station/object-storage.levant.nomad b/infra/jobs/station/object-storage.levant.nomad index 52acbca7e70d783127f09b9bbb5dd7ca4b74ab71..1852e26cc8635e3c0e730aa622258c94a7969aa0 100644 --- a/infra/jobs/station/object-storage.levant.nomad +++ b/infra/jobs/station/object-storage.levant.nomad @@ -59,8 +59,11 @@ job "object-storage" { } env { + MINIO_REGION = "[[.station]]" MINIO_ROOT_USER = "[[.object_storage.user.name]]" MINIO_ROOT_PASSWORD = "[[.object_storage.user.pass]]" + MINIO_PROMETHEUS_URL = "http://prometheus.service.consul:9090" + MINIO_PROMETHEUS_JOBID = "consul_services" MINIO_PROMETHEUS_AUTH_TYPE = "public" #MINIO_BROWSER_REDIRECT_URL = "http://[[.station]]c.control.lofar/minio" } diff --git a/tangostationcontrol/tangostationcontrol/beam/delays.py b/tangostationcontrol/tangostationcontrol/beam/delays.py index 160ecdc810bb33992f21ec860299b9dbae7ab6c9..177ee5a773cc0c2f6aebaf76dc39792b35d78aa6 100644 --- a/tangostationcontrol/tangostationcontrol/beam/delays.py +++ b/tangostationcontrol/tangostationcontrol/beam/delays.py @@ -6,8 +6,37 @@ from functools import lru_cache from typing import TypedDict import casacore.measures +import casacore.tables import numpy +""" +The 'measures' tables contain the ephemerides and geodetic calibrations +as input for its time and space calculations. These tables are externally +available at ftp://ftp.astron.nl/outgoing/Measures/WSRT_Measures.ztar. + +Casacore is expected to be configured to look in /opt/IERS for +its 'measures' tables, through setting this in the ~/.casarc file as: + + measures.directory: /opt/IERS + +This can be verified by running the 'findmeastable' utility, which +is part of the 'casacore-tools' package. + +The measures +""" + +# Where to store the measures table sets +IERS_ROOTDIR = "/opt/IERS" + + +def get_IERS_timestamp() -> datetime.datetime: + """Return the date of the currently installed IERS tables.""" + + with casacore.tables.table(f"{IERS_ROOTDIR}/geodetic/TAI_UTC") as t: + return datetime.datetime.strptime(t.VS_DATE, "%Y/%m/%d/%H:%M").replace( + tzinfo=datetime.timezone.utc + ) + class CasacoreQuantum(TypedDict): """A casacore::Quantum object as returned by casacore.measures.""" diff --git a/tangostationcontrol/tangostationcontrol/common/entrypoint.py b/tangostationcontrol/tangostationcontrol/common/entrypoint.py index 7d771c716357cb17f4b48d9a72c142ad2795f180..fe6e5138ca40754eba9a23a00443d47813c6d6a6 100644 --- a/tangostationcontrol/tangostationcontrol/common/entrypoint.py +++ b/tangostationcontrol/tangostationcontrol/common/entrypoint.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 import sys +import os +from pathlib import Path from tango.server import run from tangostationcontrol.common.lofar_logging import configure_logger @@ -21,3 +23,14 @@ def entry(Device, **kwargs): return run(Device, args=args, **kwargs) else: return run((Device,), args=args, **kwargs) + + +def restart_python(): + """Force a restart this python program. + + This function does not return.""" + + exe_path = Path(sys.executable) + + # NOTE: Python 3.4+ closes all file descriptors > 2 automatically, see https://www.python.org/dev/peps/pep-0446/ + os.execv(exe_path, [exe_path.name] + sys.argv) diff --git a/tangostationcontrol/tangostationcontrol/common/measures.py b/tangostationcontrol/tangostationcontrol/common/measures.py deleted file mode 100644 index 4eb86fdfe6a9f79464e1c21075710a369db28d2d..0000000000000000000000000000000000000000 --- a/tangostationcontrol/tangostationcontrol/common/measures.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) -# SPDX-License-Identifier: Apache-2.0 - -""" Utility functions for managing the casacore 'measures' tables. - -The 'measures' tables contain the ephemerides and geodetic calibrations -as input for its time and space calculations. These tables are externally -available (see MEASURES_URL). - -Casacore is expected to be configured to look in /opt/IERS/current for -its 'measures' tables, through setting this in the ~/.casarc file as: - - measures.directory: /opt/IERS/current - -This can be verified by running the 'findmeastable' utility, which -is part of the 'casacore-tools' package. - -Periodically new measures need to be installed, especially if a leap -second is introduced. Measures are maintained in directories called -/opt/IERS/IERS-YYYY-MM-DDTHH:MM:SS, and /opt/IERS/current is a symlink -to the active set. - -Usage: - -The download_measures() function can be used to download new measures, -which can then be activated using use_measures_directory(). If -casacore.measures already accessed the measures, the python program -needs to be restarted in order to clear the cache. - -""" - -import datetime -import os -import pathlib -import shutil -import sys -import tarfile -import urllib.request - -# Where to store the measures table sets -IERS_ROOTDIR = "/opt/IERS" - -# Where to download files to -DOWNLOAD_DIR = "/tmp" - -# Where new measures can be downloaded -MEASURES_URL = "ftp://ftp.astron.nl/outgoing/Measures/WSRT_Measures.ztar" - - -def get_measures_directory(): - """Return the directory of the current measures table in use.""" - - return str(pathlib.Path(IERS_ROOTDIR, "current").resolve()) - - -def use_measures_directory(newdir): - """Select a new set of measures tables to use. - - NOTE: Python must be restarted if the 'casacore.measures' module - already loaded the measures table before this switch. - - The 'restart_python()' function can be used for this purpose. - """ - - newdir = pathlib.Path(newdir) - - # newdir must be one of the available measures - if str(newdir) not in get_available_measures_directories(): - raise ValueError(f"Target is not an available measures directory: {newdir}") - - # be sure newdir must point to a directory containing measures - for subdir in ["ephemerides", "geodetic"]: - subdir = pathlib.Path(newdir, subdir) - - if not subdir.is_dir(): - raise ValueError(f"Subdirectory {subdir} does not exist") - - # switch to new directory - current_symlink = pathlib.Path(IERS_ROOTDIR, "current") - if current_symlink.exists(): - current_symlink.unlink() - current_symlink.symlink_to(newdir) - - -def restart_python(): - """Force a restart this python program. - - This function does not return.""" - - exe_path = pathlib.Path(sys.executable) - - # NOTE: Python 3.4+ closes all file descriptors > 2 automatically, see https://www.python.org/dev/peps/pep-0446/ - os.execv(exe_path, [exe_path.name] + sys.argv) - - -def get_available_measures_directories() -> list: - """Returns the set of installed measures tables.""" - return [ - str(d) - for d in pathlib.Path(IERS_ROOTDIR).glob("IERS-*") - if d.is_dir() and not d.is_symlink() - ] - - -def download_measures() -> str: - """Download new measures and return the directory in which they were installed.""" - - # create target directory for new measures - now = datetime.datetime.now() - iers_dir_download = pathlib.Path(now.strftime(f"{IERS_ROOTDIR}/IERS-%FT%T")) - iers_dir_download.mkdir() - - try: - measures_filename = pathlib.Path(DOWNLOAD_DIR, "WSRT_Measures.ztar") - - # download measures - urllib.request.urlretrieve(MEASURES_URL, str(measures_filename)) - - # untar measures - tarball = tarfile.open(str(measures_filename)) - tarball.extractall(path=str(iers_dir_download)) - - # remove download - measures_filename.unlink() - except Exception as e: - # don't linger our new directory if we could not install measures in it - iers_dir_download.rmdir() - - raise - - # update the timestamp used in the directory name to reflect the time of the measures, - # not the time of download. - file_with_final_timestamp = pathlib.Path(iers_dir_download, "geodetic", "TAI_UTC") - mtime = datetime.datetime.fromtimestamp(file_with_final_timestamp.stat().st_mtime) - - iers_dir_final = pathlib.Path(mtime.strftime(f"{IERS_ROOTDIR}/IERS-%FT%T")) - - if iers_dir_final.exists(): - # these measures were already downloaded earlier, delete them and use ours, - # which allows the user to fix previously broken downloads. - try: - shutil.rmtree(iers_dir_final) - except Exception as e: - # move out of the way instead then - iers_dir_final.rename(iers_dir_final.with_suffix("delete-me")) - - # update our name to reflect the correct timestamp - iers_dir_download.rename(iers_dir_final) - - return str(iers_dir_final) diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py index a6d3dab2a643701a187bc06abc779101c00c87c0..8f9351d61849f6eb3a56907c688de58fe1742bfd 100644 --- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py @@ -26,7 +26,7 @@ from tango import ( # PyTango imports from tango.server import attribute, command, device_property -from tangostationcontrol.beam.delays import Delays, pointing_to_str +from tangostationcontrol.beam.delays import Delays, pointing_to_str, get_IERS_timestamp from tangostationcontrol.beam.managers import AbstractBeamManager from tangostationcontrol.common.constants import MAX_POINTINGS, N_point_prop from tangostationcontrol.common.device_decorators import ( @@ -36,13 +36,6 @@ from tangostationcontrol.common.device_decorators import ( # Additional import from tangostationcontrol.common.lofar_logging import log_exceptions, exception_to_str -from tangostationcontrol.common.measures import ( - download_measures, - get_available_measures_directories, - get_measures_directory, - restart_python, - use_measures_directory, -) from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES from tangostationcontrol.devices.base_device_classes.async_device import AsyncDevice @@ -400,50 +393,14 @@ class BeamDevice(AsyncDevice): # -------- # Directory where the casacore measures that we use, reside. We configure ~/.casarc to - # use the symlink /opt/IERS/current, which we switch to the actual set of files to use. - measures_directory_R = attribute( - dtype=str, access=AttrWriteType.READ, fget=lambda self: get_measures_directory() - ) - - # List of dowloaded measures (the latest 64, anyway) - measures_directories_available_R = attribute( - dtype=(str,), - max_dim_x=64, + # use the symlink /opt/IERS, which we switch to the actual set of files to use. + IERS_timestamp_R = attribute( + doc="Timestamp of the IERS tables used.", + dtype=numpy.float64, access=AttrWriteType.READ, - fget=lambda self: sorted(get_available_measures_directories())[-64:], + fget=lambda self: get_IERS_timestamp().timestamp(), ) - @command(dtype_out=str, doc_out="Name of newly installed measures directory") - @DebugIt() - @log_exceptions() - def download_measures(self): - """Download new measures tables into /opt/IERS, but do not activate them. - - NOTE: This may take a while to complete. You are advised to increase - the timeout of the proxy using `my_device.set_timeout_millis(10000)`.""" - - return download_measures() - - @command(dtype_in=str, doc_in="Measures directory to activate") - @DebugIt() - @log_exceptions() - def use_measures(self, newdir): - """Activate a downloaded set of measures tables. - - NOTE: This will turn off and restart this device!!""" - - # switch to requested measures - use_measures_directory(newdir) - logger.info("Switched measures table to %s", newdir) - - # turn off our device, to prepare for a python restart - self.Off() - - # restart this program to force casacore to adopt - # the new tables - logger.warning("Restarting device to activate new measures tables") - restart_python() - # ---------- # Beam Tracker diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/lofar_device.py index 08fb8c73b093aa79a6baac0cd7c31fe325d2949c..7f9ebe79d035acfe06b0aa0da36678cd2c95b9b0 100644 --- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/lofar_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/lofar_device.py @@ -28,6 +28,7 @@ from tango.server import attribute, command, Device, device_property # Additional import from tangostationcontrol import __version__ as version from tangostationcontrol.common.device_decorators import only_in_states, fault_on_error +from tangostationcontrol.common.entrypoint import restart_python from tangostationcontrol.common.lofar_logging import log_exceptions from tangostationcontrol.common.proxy import create_device_proxy from tangostationcontrol.common.states import ( @@ -583,6 +584,16 @@ class LOFARDevice(Device): self.set_state(DevState.DISABLE) self.set_status("Device is in the DISABLE state.") + @command() + @DebugIt() + @log_exceptions() + def restart_device_server(self): + """Restart the device server. Needed to reload casacore, and maybe for nasty bugs.""" + + logger.warning("Restarting Device Server") + restart_python() + logger.error("Failed to restart Device Server") + @only_in_states(DEFAULT_COMMAND_STATES) @fault_on_error() @command() diff --git a/tangostationcontrol/test/common/test_measures.py b/tangostationcontrol/test/common/test_measures.py deleted file mode 100644 index 808ba0a892184fd86f3da437c74b1d3c3c8b5fc4..0000000000000000000000000000000000000000 --- a/tangostationcontrol/test/common/test_measures.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) -# SPDX-License-Identifier: Apache-2.0 - -import os.path -import shutil -import tempfile -import urllib.request -from unittest import mock - -from tangostationcontrol.common import measures - -from test import base - -# where our WSRT_Measures.ztar surrogate is located -# two versions with different timestamps are provided -FAKE_MEASURES = os.path.dirname(__file__) + "/fake_measures.ztar" -FAKE_MEASURES_NEWER = os.path.dirname(__file__) + "/fake_measures_newer.ztar" - - -class TestMeasures(base.TestCase): - @mock.patch.object(urllib.request, "urlretrieve") - def test_download_and_use(self, m_urlretrieve): - """Test downloading and using new measures tables.""" - - with tempfile.TemporaryDirectory() as tmpdirname, mock.patch( - "tangostationcontrol.common.measures.IERS_ROOTDIR", tmpdirname - ) as rootdir, mock.patch( - "tangostationcontrol.common.measures.DOWNLOAD_DIR", tmpdirname - ) as downloaddir: - # emulate the download - m_urlretrieve.side_effect = lambda *args, **kw: shutil.copyfile( - FAKE_MEASURES, tmpdirname + "/WSRT_Measures.ztar" - ) - - # 'download' and process our fake measures - newdir = measures.download_measures() - - # active them - measures.use_measures_directory(newdir) - - # check if they're activated - self.assertIn(newdir, measures.get_available_measures_directories()) - self.assertEqual(newdir, measures.get_measures_directory()) - - @mock.patch.object(urllib.request, "urlretrieve") - def test_switch_tables(self, m_urlretrieve): - """Test switching between available sets of measures tables.""" - - with tempfile.TemporaryDirectory() as tmpdirname, mock.patch( - "tangostationcontrol.common.measures.IERS_ROOTDIR", tmpdirname - ) as rootdir, mock.patch( - "tangostationcontrol.common.measures.DOWNLOAD_DIR", tmpdirname - ) as downloaddir: - # 'download' two measures with different timestamps - m_urlretrieve.side_effect = lambda *args, **kw: shutil.copyfile( - FAKE_MEASURES, tmpdirname + "/WSRT_Measures.ztar" - ) - newdir1 = measures.download_measures() - m_urlretrieve.side_effect = lambda *args, **kw: shutil.copyfile( - FAKE_MEASURES_NEWER, tmpdirname + "/WSRT_Measures.ztar" - ) - newdir2 = measures.download_measures() - - # check if both are available - self.assertIn(newdir1, measures.get_available_measures_directories()) - self.assertIn(newdir2, measures.get_available_measures_directories()) - - # switch between the two - measures.use_measures_directory(newdir1) - self.assertEqual(newdir1, measures.get_measures_directory()) - measures.use_measures_directory(newdir2) - self.assertEqual(newdir2, measures.get_measures_directory()) - measures.use_measures_directory(newdir1) - self.assertEqual(newdir1, measures.get_measures_directory())