Coverage for tests/test_server.py: 30%

78 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-10-02 07:59 +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/>. 

27 

28import os.path 

29import unittest 

30 

31try: 

32 # Failing to import any of these should disable the tests. 

33 import lsst.daf.butler.server 

34 from fastapi.testclient import TestClient 

35 from lsst.daf.butler.server import app 

36except ImportError: 

37 TestClient = None 

38 app = None 

39 

40from lsst.daf.butler import Butler, CollectionType, Config, DataCoordinate, DatasetRef 

41from lsst.daf.butler.tests import addDatasetType 

42from lsst.daf.butler.tests.utils import MetricTestRepo, makeTestTempDir, removeTestTempDir 

43 

44TESTDIR = os.path.abspath(os.path.dirname(__file__)) 

45 

46 

47@unittest.skipIf(TestClient is None or app is None, "FastAPI not installed.") 

48class ButlerClientServerTestCase(unittest.TestCase): 

49 """Test for Butler client/server.""" 

50 

51 @classmethod 

52 def setUpClass(cls): 

53 # First create a butler and populate it. 

54 cls.root = makeTestTempDir(TESTDIR) 

55 cls.repo = MetricTestRepo(root=cls.root, configFile=os.path.join(TESTDIR, "config/basic/butler.yaml")) 

56 

57 # Add a collection chain. 

58 cls.repo.butler.registry.registerCollection("chain", CollectionType.CHAINED) 

59 cls.repo.butler.registry.setCollectionChain("chain", ["ingest"]) 

60 

61 # Globally change where the server thinks its butler repository 

62 # is located. This will prevent any other server tests and is 

63 # not a long term fix. 

64 lsst.daf.butler.server.BUTLER_ROOT = cls.root 

65 cls.client = TestClient(app) 

66 

67 # Create a client butler. We need to modify the contents of the 

68 # server configuration to reflect the use of the test client. 

69 response = cls.client.get("/butler/butler.json") 

70 config = Config(response.json()) 

71 config["registry", "db"] = cls.client 

72 

73 # Since there is no client datastore we also need to specify 

74 # the datastore root. 

75 config["datastore", "root"] = cls.root 

76 cls.butler = Butler(config) 

77 

78 @classmethod 

79 def tearDownClass(cls): 

80 removeTestTempDir(cls.root) 

81 

82 def test_simple(self): 

83 response = self.client.get("/butler/") 

84 self.assertEqual(response.status_code, 200) 

85 self.assertIn("Butler Server", response.json()) 

86 

87 response = self.client.get("/butler/butler.json") 

88 self.assertEqual(response.status_code, 200) 

89 self.assertIn("registry", response.json()) 

90 

91 response = self.client.get("/butler/v1/universe") 

92 self.assertEqual(response.status_code, 200) 

93 self.assertIn("namespace", response.json()) 

94 

95 def test_registry(self): 

96 universe = self.butler.dimensions 

97 self.assertEqual(universe.namespace, "daf_butler") 

98 

99 dataset_type = self.butler.registry.getDatasetType("test_metric_comp") 

100 self.assertEqual(dataset_type.name, "test_metric_comp") 

101 

102 dataset_types = list(self.butler.registry.queryDatasetTypes(...)) 

103 self.assertIn("test_metric_comp", [ds.name for ds in dataset_types]) 

104 dataset_types = list(self.butler.registry.queryDatasetTypes("test_*")) 

105 self.assertEqual(len(dataset_types), 1) 

106 

107 collections = self.butler.registry.queryCollections( 

108 ..., collectionTypes={CollectionType.RUN, CollectionType.TAGGED} 

109 ) 

110 self.assertEqual(len(collections), 2, collections) 

111 

112 collection_type = self.butler.registry.getCollectionType("ingest") 

113 self.assertEqual(collection_type.name, "TAGGED") 

114 

115 chain = self.butler.registry.getCollectionChain("chain") 

116 self.assertEqual(list(chain), ["ingest"]) 

117 

118 datasets = list(self.butler.registry.queryDatasets("test_metric_comp", collections=...)) 

119 self.assertEqual(len(datasets), 2) 

120 

121 ref = self.butler.registry.getDataset(datasets[0].id) 

122 self.assertEqual(ref, datasets[0]) 

123 

124 locations = self.butler.registry.getDatasetLocations(ref) 

125 self.assertEqual(locations[0], "FileDatastore@<butlerRoot>") 

126 

127 fake_ref = DatasetRef( 

128 dataset_type, 

129 dataId={"instrument": "DummyCamComp", "physical_filter": "d-r", "visit": 424}, 

130 run="missing", 

131 ) 

132 locations = self.butler.registry.getDatasetLocations(fake_ref) 

133 self.assertEqual(locations, []) 

134 

135 dataIds = list(self.butler.registry.queryDataIds("visit", dataId={"instrument": "DummyCamComp"})) 

136 self.assertEqual(len(dataIds), 2) 

137 

138 # Create a DataCoordinate to test the alternate path for specifying 

139 # a data ID. 

140 data_id = DataCoordinate.standardize({"instrument": "DummyCamComp"}, universe=self.butler.dimensions) 

141 records = list(self.butler.registry.queryDimensionRecords("physical_filter", dataId=data_id)) 

142 self.assertEqual(len(records), 1) 

143 

144 def test_experimental(self): 

145 """Experimental interfaces.""" 

146 # Got URI testing we can not yet support disassembly so must 

147 # add a dataset with a different dataset type. 

148 datasetType = addDatasetType( 

149 self.repo.butler, "metric", {"instrument", "visit"}, "StructuredCompositeReadCompNoDisassembly" 

150 ) 

151 

152 self.repo.addDataset({"instrument": "DummyCamComp", "visit": 424}, datasetType=datasetType) 

153 self.butler.registry.refresh() 

154 

155 # Need a DatasetRef. 

156 datasets = list(self.butler.registry.queryDatasets("metric", collections=...)) 

157 

158 response = self.client.get(f"/butler/v1/uri/{datasets[0].id}") 

159 self.assertEqual(response.status_code, 200) 

160 self.assertIn("file://", response.json()) 

161 

162 

163if __name__ == "__main__": 

164 unittest.main()