Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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 program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21 

22import os 

23from contextlib import contextmanager 

24import secrets 

25import unittest 

26 

27try: 

28 # It's possible but silly to have testing.postgresql installed without 

29 # having the postgresql server installed (because then nothing in 

30 # testing.postgresql would work), so we use the presence of that module 

31 # to test whether we can expect the server to be available. 

32 import testing.postgresql 

33except ImportError: 

34 testing = None 

35 

36import sqlalchemy 

37 

38from lsst.daf.butler import ddl 

39from lsst.daf.butler.registry import RegistryConfig 

40from lsst.daf.butler.registry.databases.postgresql import PostgresqlDatabase 

41from lsst.daf.butler.registry import Registry 

42from lsst.daf.butler.registry.tests import DatabaseTests, RegistryTests 

43 

44 

45@unittest.skipUnless(testing is not None, "testing.postgresql module not found") 

46class PostgresqlDatabaseTestCase(unittest.TestCase, DatabaseTests): 

47 

48 @classmethod 

49 def setUpClass(cls): 

50 cls.server = testing.postgresql.Postgresql() 

51 

52 @classmethod 

53 def tearDownClass(cls): 

54 cls.server.stop() 

55 

56 def makeEmptyDatabase(self, origin: int = 0) -> PostgresqlDatabase: 

57 namespace = f"namespace_{secrets.token_hex(8).lower()}" 

58 return PostgresqlDatabase.fromUri(origin=origin, uri=self.server.url(), namespace=namespace) 

59 

60 def getNewConnection(self, database: PostgresqlDatabase, *, writeable: bool) -> PostgresqlDatabase: 

61 return PostgresqlDatabase.fromUri(origin=database.origin, uri=self.server.url(), 

62 namespace=database.namespace, writeable=writeable) 

63 

64 @contextmanager 

65 def asReadOnly(self, database: PostgresqlDatabase) -> PostgresqlDatabase: 

66 yield self.getNewConnection(database, writeable=False) 

67 

68 def testNameShrinking(self): 

69 """Test that too-long names for database entities other than tables 

70 and columns (which we preserve, and just expect to fit) are shrunk. 

71 """ 

72 db = self.makeEmptyDatabase(origin=1) 

73 with db.declareStaticTables(create=True) as context: 

74 # Table and field names are each below the 63-char limit even when 

75 # accounting for the prefix, but their combination (which will 

76 # appear in sequences and constraints) is not. 

77 tableName = "a_table_with_a_very_very_long_42_char_name" 

78 fieldName1 = "a_column_with_a_very_very_long_43_char_name" 

79 fieldName2 = "another_column_with_a_very_very_long_49_char_name" 

80 context.addTable( 

81 tableName, 

82 ddl.TableSpec( 

83 fields=[ 

84 ddl.FieldSpec( 

85 fieldName1, 

86 dtype=sqlalchemy.BigInteger, 

87 autoincrement=True, 

88 primaryKey=True 

89 ), 

90 ddl.FieldSpec( 

91 fieldName2, 

92 dtype=sqlalchemy.String, 

93 length=16, 

94 nullable=False, 

95 ), 

96 ], 

97 unique={(fieldName2,)}, 

98 ) 

99 ) 

100 # Add another table, this time dynamically, with a foreign key to the 

101 # first table. 

102 db.ensureTableExists( 

103 tableName + "_b", 

104 ddl.TableSpec( 

105 fields=[ 

106 ddl.FieldSpec( 

107 fieldName1 + "_b", 

108 dtype=sqlalchemy.BigInteger, 

109 autoincrement=True, 

110 primaryKey=True 

111 ), 

112 ddl.FieldSpec( 

113 fieldName2 + "_b", 

114 dtype=sqlalchemy.String, 

115 length=16, 

116 nullable=False, 

117 ), 

118 ], 

119 foreignKeys=[ 

120 ddl.ForeignKeySpec(tableName, source=(fieldName2 + "_b",), target=(fieldName2,)), 

121 ] 

122 ) 

123 ) 

124 

125 

126@unittest.skipUnless(testing is not None, "testing.postgresql module not found") 

127class PostgresqlRegistryTestCase(unittest.TestCase, RegistryTests): 

128 """Tests for `Registry` backed by a PostgreSQL database. 

129 """ 

130 

131 @classmethod 

132 def setUpClass(cls): 

133 cls.server = testing.postgresql.Postgresql() 

134 

135 @classmethod 

136 def tearDownClass(cls): 

137 cls.server.stop() 

138 

139 @classmethod 

140 def getDataDir(cls) -> str: 

141 return os.path.normpath(os.path.join(os.path.dirname(__file__), "data", "registry")) 

142 

143 def makeRegistry(self) -> Registry: 

144 namespace = f"namespace_{secrets.token_hex(8).lower()}" 

145 config = RegistryConfig() 

146 config["db"] = self.server.url() 

147 config["namespace"] = namespace 

148 return Registry.fromConfig(config, create=True) 

149 

150 

151if __name__ == "__main__": 151 ↛ 152line 151 didn't jump to line 152, because the condition on line 151 was never true

152 unittest.main()