Coverage for tests/test_server.py: 37%
71 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-03 16:25 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-03 16:25 +0000
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
28import os.path
29import unittest
30import uuid
32try:
33 # Failing to import any of these should disable the tests.
34 from fastapi.testclient import TestClient
35 from lsst.daf.butler.remote_butler import RemoteButler
36 from lsst.daf.butler.remote_butler.server import Factory, app, factory_dependency
37except ImportError:
38 TestClient = None
39 app = None
41from lsst.daf.butler import Butler, DataCoordinate, DatasetRef, MissingDatasetTypeError, StorageClassFactory
42from lsst.daf.butler.tests import DatastoreMock
43from lsst.daf.butler.tests.utils import MetricTestRepo, makeTestTempDir, removeTestTempDir
45TESTDIR = os.path.abspath(os.path.dirname(__file__))
48def _make_remote_butler(http_client):
49 return RemoteButler(
50 config={
51 "remote_butler": {
52 # This URL is ignored because we override the HTTP client, but
53 # must be valid to satisfy the config validation
54 "url": "https://test.example"
55 }
56 },
57 http_client=http_client,
58 )
61@unittest.skipIf(TestClient is None or app is None, "FastAPI not installed.")
62class ButlerClientServerTestCase(unittest.TestCase):
63 """Test for Butler client/server."""
65 @classmethod
66 def setUpClass(cls):
67 cls.storageClassFactory = StorageClassFactory()
69 # First create a butler and populate it.
70 cls.root = makeTestTempDir(TESTDIR)
71 cls.repo = MetricTestRepo(root=cls.root, configFile=os.path.join(TESTDIR, "config/basic/butler.yaml"))
72 # Override the server's Butler initialization to point at our test repo
73 server_butler = Butler.from_config(cls.root, writeable=True)
75 # Not yet testing butler.get()
76 DatastoreMock.apply(server_butler)
78 def create_factory_dependency():
79 return Factory(butler=server_butler)
81 app.dependency_overrides[factory_dependency] = create_factory_dependency
83 # Set up the RemoteButler that will connect to the server
84 cls.client = TestClient(app)
85 cls.butler = _make_remote_butler(cls.client)
87 # Populate the test server.
88 server_butler.import_(filename=os.path.join(TESTDIR, "data", "registry", "base.yaml"))
89 server_butler.import_(filename=os.path.join(TESTDIR, "data", "registry", "datasets-uuid.yaml"))
91 @classmethod
92 def tearDownClass(cls):
93 del app.dependency_overrides[factory_dependency]
94 removeTestTempDir(cls.root)
96 def test_simple(self):
97 response = self.client.get("/butler/v1/universe")
98 self.assertEqual(response.status_code, 200)
99 self.assertIn("namespace", response.json())
101 def test_remote_butler(self):
102 universe = self.butler.dimensions
103 self.assertEqual(universe.namespace, "daf_butler")
104 self.assertFalse(self.butler.isWriteable())
106 def test_get_dataset_type(self):
107 bias_type = self.butler.get_dataset_type("bias")
108 self.assertEqual(bias_type.name, "bias")
110 with self.assertRaises(MissingDatasetTypeError):
111 self.butler.get_dataset_type("not_bias")
113 def test_find_dataset(self):
114 storage_class = self.storageClassFactory.getStorageClass("Exposure")
116 ref = self.butler.find_dataset("bias", collections="imported_g", detector=1, instrument="Cam1")
117 self.assertIsInstance(ref, DatasetRef)
118 self.assertEqual(ref.id, uuid.UUID("e15ab039-bc8b-4135-87c5-90902a7c0b22"))
119 self.assertFalse(ref.dataId.hasRecords())
121 # Try again with variation of parameters.
122 ref_new = self.butler.find_dataset(
123 "bias",
124 {"detector": 1},
125 collections="imported_g",
126 instrument="Cam1",
127 dimension_records=True,
128 )
129 self.assertEqual(ref_new, ref)
130 self.assertTrue(ref_new.dataId.hasRecords())
132 ref_new = self.butler.find_dataset(
133 ref.datasetType,
134 DataCoordinate.standardize(detector=1, instrument="Cam1", universe=self.butler.dimensions),
135 collections="imported_g",
136 storage_class=storage_class,
137 )
138 self.assertEqual(ref_new, ref)
140 ref2 = self.butler.get_dataset(ref.id)
141 self.assertEqual(ref2, ref)
143 # Use detector name to find it.
144 ref3 = self.butler.find_dataset(
145 ref.datasetType,
146 collections="imported_g",
147 instrument="Cam1",
148 full_name="Aa",
149 )
150 self.assertEqual(ref2, ref3)
152 # Try expanded refs.
153 self.assertFalse(ref.dataId.hasRecords())
154 expanded = self.butler.get_dataset(ref.id, dimension_records=True)
155 self.assertTrue(expanded.dataId.hasRecords())
157 # The test datasets are all Exposure so storage class conversion
158 # can not be tested until we fix that. For now at least test the
159 # code paths.
160 bias = self.butler.get_dataset(ref.id, storage_class=storage_class)
161 self.assertEqual(bias.datasetType.storageClass, storage_class)
163 # Unknown dataset should not fail.
164 self.assertIsNone(self.butler.get_dataset(uuid.uuid4()))
165 self.assertIsNone(self.butler.get_dataset(uuid.uuid4(), storage_class="NumpyArray"))
168if __name__ == "__main__":
169 unittest.main()