ctao-bdms-clients 0.2.0rc1__py3-none-any.whl → 0.3.0rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -124,7 +124,6 @@ def test_replication(test_vo, test_scope, tmp_path):
124
124
  rule_client,
125
125
  rule_id=rule,
126
126
  expected_status="OK",
127
- timeout=600,
128
127
  poll_interval=5,
129
128
  )
130
129
  replicas = next(replica_client.list_replicas(dids))
@@ -88,3 +88,9 @@ def test_retrieve_by_lfn(test_scope, generic_data_product, tmp_path):
88
88
  expected_path = tmp_path / test_scope / test_lfn.lstrip("/")
89
89
  assert expected_path.is_file(), "File not downloaded to expected location"
90
90
  assert expected_path.read_text() == expected_content
91
+
92
+
93
+ @pytest.mark.verifies_usecase("DPPS-UC-110-1.3.1")
94
+ @pytest.mark.xfail
95
+ def test_retrieve_by_lfn_with_iam(test_scope, generic_data_product, tmp_path):
96
+ raise NotImplementedError
@@ -0,0 +1,97 @@
1
+ from astropy.io import fits
2
+
3
+ from bdms.extract_fits_metadata import (
4
+ extract_metadata_from_data,
5
+ extract_metadata_from_headers,
6
+ )
7
+
8
+
9
+ def test_extraction_correct_value_subarray_file(subarray_test_file):
10
+ """Test the extraction of metadata from a FITS file."""
11
+ with fits.open(subarray_test_file) as hdul:
12
+ metadata_header = extract_metadata_from_headers(hdul)
13
+
14
+ metadata_payload = extract_metadata_from_data(subarray_test_file)
15
+ metadata_fits = {**metadata_header, **metadata_payload}
16
+
17
+ assert len(metadata_fits) > 0, "No metadata found in the SUBARRAY FITS"
18
+
19
+ expected_keys_in_fits_file = {
20
+ "observatory": "CTA",
21
+ "start_time": "2025-02-04T21:34:05",
22
+ "end_time": "2025-02-04T21:43:12",
23
+ "subarray_id": 0,
24
+ "sb_id": 2000000066,
25
+ "obs_id": 2000000200,
26
+ }
27
+
28
+ for key, value in expected_keys_in_fits_file.items():
29
+ assert metadata_fits[key] == value, f"Expected key '{key}' not found."
30
+
31
+
32
+ def test_extraction_correct_value_tel_trigger_file(tel_trigger_test_file):
33
+ """Test the extraction of metadata from a FITS file."""
34
+ with fits.open(tel_trigger_test_file) as hdul:
35
+ metadata_header = extract_metadata_from_headers(hdul)
36
+
37
+ metadata_payload = extract_metadata_from_data(tel_trigger_test_file)
38
+ metadata_fits = {**metadata_header, **metadata_payload}
39
+
40
+ assert len(metadata_fits) > 0, "No metadata found in the Telescope TRIGGER FITS"
41
+
42
+ expected_keys_in_fits_file = {
43
+ "observatory": "CTA",
44
+ "start_time": "2025-02-04T21:34:05",
45
+ "end_time": "2025-02-04T21:43:11",
46
+ "tel_ids": [1],
47
+ "sb_id": 2000000066,
48
+ "obs_id": 2000000200,
49
+ }
50
+
51
+ for key, value in expected_keys_in_fits_file.items():
52
+ assert metadata_fits[key] == value, f"Expected key '{key}' not found."
53
+
54
+
55
+ def test_extraction_correct_value_tel_events_file(tel_events_test_file):
56
+ """Test the extraction of metadata from a FITS file."""
57
+ with fits.open(tel_events_test_file) as hdul:
58
+ metadata_header = extract_metadata_from_headers(hdul)
59
+
60
+ metadata_payload = extract_metadata_from_data(tel_events_test_file)
61
+ metadata_fits = {**metadata_header, **metadata_payload}
62
+
63
+ assert len(metadata_fits) > 0, "No metadata found in the Telescope EVENTS FITS"
64
+
65
+ expected_keys_in_fits_file = {
66
+ "observatory": "CTA",
67
+ "start_time": "2025-04-01T15:25:02",
68
+ "end_time": "2025-04-01T15:25:03",
69
+ "sb_id": 0,
70
+ "obs_id": 0,
71
+ }
72
+
73
+ for key, value in expected_keys_in_fits_file.items():
74
+ assert metadata_fits[key] == value, f"Expected key '{key}' not found."
75
+
76
+
77
+ def test_extract_metadata_from_data_incorrect_header(tmp_path):
78
+ """Test the extraction of metadata from an empty FITS file header."""
79
+ fits_file_path = tmp_path / "empty_fits.fits.fz"
80
+ hdul = fits.HDUList([fits.PrimaryHDU()])
81
+ hdul.writeto(fits_file_path, checksum=True)
82
+
83
+ with fits.open(fits_file_path) as hdul:
84
+ metadata = extract_metadata_from_headers(hdul)
85
+
86
+ assert metadata == {}, "Expected empty metadata in the header"
87
+
88
+
89
+ def test_extract_metadata_from_data_incorrect_data(tmp_path):
90
+ """Test the extraction of metadata from an empty FITS file data."""
91
+ fits_file_path = tmp_path / "empty_fits.fits.fz"
92
+ hdul = fits.HDUList([fits.PrimaryHDU()])
93
+ hdul.writeto(fits_file_path, checksum=True)
94
+
95
+ metadata = extract_metadata_from_data(fits_file_path)
96
+
97
+ assert metadata == {}, "Expected empty metadata in the payload"
@@ -1,8 +1,5 @@
1
- import os
2
1
  import subprocess as sp
3
- from datetime import datetime
4
2
  from pathlib import Path
5
- from secrets import token_hex
6
3
 
7
4
  import pytest
8
5
  from rucio.client.rseclient import RSEClient
@@ -24,41 +21,25 @@ def test_shared_storage(storage_mount_path: Path) -> Path:
24
21
  ), f"Shared storage {storage_mount_path} is not available on the client"
25
22
 
26
23
 
27
- @pytest.fixture(scope="session")
28
- def test_file(storage_mount_path, test_scope) -> tuple[Path, str]:
29
- """Create a test file in the shared storage and return its path and content"""
30
- unique_id = f"{datetime.now():%Y%m%d_%H%M%S}_{token_hex(8)}"
31
- test_file_name = f"/ctao.dpps.test/{test_scope}/testfile_{unique_id}.txt"
32
- test_file_path = storage_mount_path / test_file_name.lstrip("/")
33
- test_file_content = f"This is a test file {unique_id}"
34
- test_file_path.parent.mkdir(parents=True, exist_ok=True)
35
- test_file_path.write_text(test_file_content)
36
- assert test_file_path.exists(), f"Test file {test_file_path} was not created successfully at {storage_mount_path}"
37
-
38
- return test_file_name, test_file_content
39
-
40
-
41
- def test_file_access_from_onsite_storage_using_gfal(test_file: tuple[Path, str]):
24
+ def test_file_access_from_onsite_storage_using_gfal(
25
+ storage_mount_path: Path, onsite_test_file: tuple[Path, str]
26
+ ):
42
27
  """Verify that the file is accessible from the onsite storage pod using gfal-ls"""
43
- test_file_lfn, _ = test_file
44
- test_file_name = os.path.basename(test_file_lfn)
28
+ test_file_path, _ = onsite_test_file
29
+ test_file_lfn = f"/{test_file_path.relative_to(storage_mount_path)}"
30
+ test_file_name = test_file_path.name
45
31
 
46
- gfal_url = f"{STORAGE_PROTOCOL}://{STORAGE_HOSTNAME}/rucio{test_file_lfn}"
32
+ gfal_url = f"{STORAGE_PROTOCOL}://{STORAGE_HOSTNAME}/rucio/{test_file_lfn}"
47
33
  cmd = ["gfal-ls", gfal_url]
48
- try:
49
- output = sp.run(cmd, capture_output=True, text=True, check=True)
50
- debug = True # Adjust as needed
51
- if debug:
52
- print(f"GFAL Output: {output.stdout.strip()}")
53
- stdout = output.stdout.strip()
54
- except sp.CalledProcessError as e:
55
- pytest.fail(
56
- f"gfal-ls failed for {gfal_url}:\nSTDERR: {e.stderr.strip()}\nSTDOUT: {e.stdout.strip()}"
57
- )
58
-
59
- assert any(
60
- test_file_name in line for line in stdout.splitlines()
61
- ), f"File {test_file_name} not accessible; gfal-ls output: {stdout!r}"
34
+
35
+ ret = sp.run(cmd, capture_output=True, text=True)
36
+ stdout = ret.stdout.strip()
37
+ stderr = ret.stderr.strip()
38
+ msg = f"gfal-ls failed for {gfal_url}:\nSTDERR: {stderr}\nSTDOUT: {stderr}"
39
+ assert ret.returncode == 0, msg
40
+
41
+ msg = f"File {test_file_name} not accessible; gfal-ls output: {stdout!r}"
42
+ assert any(test_file_name in line for line in stdout.splitlines()), msg
62
43
 
63
44
 
64
45
  @pytest.mark.usefixtures("_auth_proxy")
bdms/tests/utils.py CHANGED
@@ -13,9 +13,37 @@ from rucio.common.exception import RucioException
13
13
  # Default timeout and polling interval (in seconds) for waiting for replication
14
14
  DEFAULT_TIMEOUT = 1000
15
15
  DEFAULT_POLL_INTERVAL = 30
16
+ XROOTD_UID = int(os.getenv("XROOTD_UID", 994))
17
+ XROOTD_GID = int(os.getenv("XROOTD_GID", 994))
16
18
  LOGGER = logging.getLogger(__name__)
17
19
 
18
20
 
21
+ def reset_xrootd_permissions(path):
22
+ recursive_chown(path, uid=XROOTD_UID, gid=XROOTD_GID)
23
+
24
+
25
+ def recursive_chown(path: Path, uid: int, gid: int):
26
+ """Equivalent of unix chmod -R <uid>:<gid> <path>."""
27
+ os.chown(path, uid, gid)
28
+
29
+ for root, dirs, files in os.walk(path):
30
+ root = Path(root)
31
+ for d in dirs:
32
+ os.chown(root / d, uid, gid)
33
+
34
+ for f in files:
35
+ # skip temporary files created by rucio
36
+ # they should already have correct ownership and might go away
37
+ # between finding them and executing chown
38
+ if f.endswith(".rucio.upload"):
39
+ continue
40
+
41
+ try:
42
+ os.chown(root / f, uid, gid)
43
+ except Exception as e:
44
+ LOGGER.warning("Failed to chown file %s: %s", root / f, e)
45
+
46
+
19
47
  def wait_for_replication_status(
20
48
  rule_client: RuleClient,
21
49
  rule_id: str,
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ctao-bdms-clients
3
- Version: 0.2.0rc1
3
+ Version: 0.3.0rc1
4
4
  Summary: Client module for the CTAO DPPS Bulk Data Management System
5
5
  Author-email: Georgios Zacharis <georgios.zacharis@inaf.it>, Stefano Gallozzi <Stefano.gallozzi@inaf.it>, Michele Mastropietro <michele.mastropietro@inaf.it>, Syed Anwar Ul Hasan <syedanwarul.hasan@cta-consortium.org>, Maximilian Linhoff <maximilian.linhoff@cta-observatory.org>, Volodymyr Savchenko <Volodymyr.Savchenko@epfl.ch>
6
- License: BSD-3-Clause
6
+ License-Expression: BSD-3-Clause
7
7
  Project-URL: repository, https://gitlab.cta-observatory.org/cta-computing/dpps/bdms/bdms
8
8
  Project-URL: documentation, http://cta-computing.gitlab-pages.cta-observatory.org/dpps/bdms/bdms
9
9
  Requires-Python: >=3.9
@@ -12,12 +12,18 @@ License-File: LICENSE
12
12
  Requires-Dist: astropy<8.0.0a0,>=6.0.1
13
13
  Requires-Dist: ctao-bdms-rucio-policy~=0.1.0
14
14
  Requires-Dist: rucio-clients~=35.7.0
15
+ Requires-Dist: protozfits>=2.7.2
16
+ Requires-Dist: watchdog>=6.0.0
17
+ Requires-Dist: filelock>=3.18.0
18
+ Requires-Dist: prometheus-client>=0.22.1
19
+ Requires-Dist: ruamel.yaml
15
20
  Provides-Extra: test
16
21
  Requires-Dist: pytest; extra == "test"
17
22
  Requires-Dist: pytest-cov; extra == "test"
18
23
  Requires-Dist: pytest-requirements; extra == "test"
19
24
  Requires-Dist: python-dotenv; extra == "test"
20
25
  Requires-Dist: minio; extra == "test"
26
+ Requires-Dist: pytest-xdist; extra == "test"
21
27
  Provides-Extra: doc
22
28
  Requires-Dist: sphinx; extra == "doc"
23
29
  Requires-Dist: numpydoc; extra == "doc"
@@ -0,0 +1,23 @@
1
+ bdms/__init__.py,sha256=7btE6tNhFqXSv2eUhZ-0m1J3nTTs4Xo6HWcQI4eh5Do,142
2
+ bdms/_version.py,sha256=ymwdyKB404aMzKXrx7y01ltePvHS_nIJjfh_zAIIN44,521
3
+ bdms/acada_ingest_cli.py,sha256=xkf9nT5Lk7SjcbxVeBpKJWuJ-8Luze5-MSq4yki-7_k,12866
4
+ bdms/acada_ingestion.py,sha256=mB5ilvzJbPblFp94Jcca-IzYvrMuQlroDZxuujpFB_I,36373
5
+ bdms/extract_fits_metadata.py,sha256=ZGJQCFJCXkWg8N3CAb17GB-wwPj-wTvNg0JOS-MemZ0,3431
6
+ bdms/version.py,sha256=mTfi1WzbIs991NyImM6mcMg1R39a6U1W2pKnk-Tt5Vw,765
7
+ bdms/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ bdms/tests/conftest.py,sha256=n7KN9foojCXDxFuZinI0MvhnSvLk5Mn7aFmjQKmO8eI,7364
9
+ bdms/tests/test_acada_ingest_cli.py,sha256=SYVt1xlEDsrbPX0C5Isf0thjUcaxr7cjflyZSwpPBaw,8314
10
+ bdms/tests/test_acada_ingestion.py,sha256=xQN07Qbx00IW_w0vCcR5r5H3qvvl_JNYmCUuWJX9xrc,59485
11
+ bdms/tests/test_basic_rucio_functionality.py,sha256=9GIX8IO6wBJm40LKFEH2StS-fMKvC07sxFHPVR7dftU,3583
12
+ bdms/tests/test_dpps_rel_0_0.py,sha256=2NhxpdhXQg_8lmK-tRrPQ_FcijsIEfv07x-kVlT8Zik,3138
13
+ bdms/tests/test_extract_fits_metadata.py,sha256=A935WD2TF3lBcaeDmzGSlH2IXUF1v8qslrsW30lnEAA,3490
14
+ bdms/tests/test_file_replicas.py,sha256=NqutrSJa5ME50JpmyATNPSLqq1AOq1ruv84XSY3PKLI,2635
15
+ bdms/tests/test_metadata.py,sha256=f0tSqNGlYe-ydoSDJw0k1De2kHoPl6g-GYBj_jP6kCY,3728
16
+ bdms/tests/test_onsite_storage.py,sha256=waK7t9kBquzJbuLLYcpeNU9YuA70XTRS88RMxBWxawI,3765
17
+ bdms/tests/utils.py,sha256=PUayWe60JGVDs5mkWmHVjFV_yqg5XUQlxoAvhT1P0OM,4101
18
+ ctao_bdms_clients-0.3.0rc1.dist-info/licenses/LICENSE,sha256=Py9riZY_f0CmXbrZ5JreE3WgglyWkRnwUfqydvX6jxE,1556
19
+ ctao_bdms_clients-0.3.0rc1.dist-info/METADATA,sha256=NRkliF-xYd9V8Vfkdgj2MEFQI9ee67wmUVKxhFD9tMo,2517
20
+ ctao_bdms_clients-0.3.0rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ ctao_bdms_clients-0.3.0rc1.dist-info/entry_points.txt,sha256=YZCIOePi_xXaJunA6lAQxAKh1tn3wOd4pmqymFRvah4,60
22
+ ctao_bdms_clients-0.3.0rc1.dist-info/top_level.txt,sha256=ao0U8aA33KRHpcqmr7yrK8y2AQ6ahSu514tfaN4hDV8,5
23
+ ctao_bdms_clients-0.3.0rc1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ acada-ingest = bdms.acada_ingest_cli:main
@@ -1,18 +0,0 @@
1
- bdms/__init__.py,sha256=7btE6tNhFqXSv2eUhZ-0m1J3nTTs4Xo6HWcQI4eh5Do,142
2
- bdms/_version.py,sha256=6j6NVXRMR-dX2osPsF0-SkvP1-ofWxEz6ew_4VL2kCY,521
3
- bdms/acada_ingestion.py,sha256=bKnXbAYvtYHYQk6ir5Sw1YIjCXGZTyk3IpZz-XGkkPo,16248
4
- bdms/version.py,sha256=mTfi1WzbIs991NyImM6mcMg1R39a6U1W2pKnk-Tt5Vw,765
5
- bdms/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- bdms/tests/conftest.py,sha256=lArkd8Kn7Ef19_BhqXq77taei9LKggWUu3FDUhrt9M4,3009
7
- bdms/tests/test_acada_ingestion.py,sha256=A0G9-ssHN3dx0Jz_eIN72dQp21gfZqdQnyAgLY3BDF4,17738
8
- bdms/tests/test_basic_rucio_functionality.py,sha256=GFUCq2QlM0M_5k5Qz9iPXPftE6nGuGYbW_IVS76T978,3604
9
- bdms/tests/test_dpps_rel_0_0.py,sha256=MnbuBoS_kUUiMcHE3-jqOzekQNUa-wcsjCJqJQ2J9S4,2957
10
- bdms/tests/test_file_replicas.py,sha256=NqutrSJa5ME50JpmyATNPSLqq1AOq1ruv84XSY3PKLI,2635
11
- bdms/tests/test_metadata.py,sha256=f0tSqNGlYe-ydoSDJw0k1De2kHoPl6g-GYBj_jP6kCY,3728
12
- bdms/tests/test_onsite_storage.py,sha256=xBwVbr2q0KHnesIrF0I8ova_hfDXDs3CBya2Sxi6VWM,4633
13
- bdms/tests/utils.py,sha256=fh23X6iN2-lsoRBU3WSeWkweiHZlOtIUK5xzHbWyP6c,3185
14
- ctao_bdms_clients-0.2.0rc1.dist-info/licenses/LICENSE,sha256=Py9riZY_f0CmXbrZ5JreE3WgglyWkRnwUfqydvX6jxE,1556
15
- ctao_bdms_clients-0.2.0rc1.dist-info/METADATA,sha256=88TkbmaMgsbU1dwCRzPHKWK-yYb323BT1HqFgsQboEg,2297
16
- ctao_bdms_clients-0.2.0rc1.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
17
- ctao_bdms_clients-0.2.0rc1.dist-info/top_level.txt,sha256=ao0U8aA33KRHpcqmr7yrK8y2AQ6ahSu514tfaN4hDV8,5
18
- ctao_bdms_clients-0.2.0rc1.dist-info/RECORD,,