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 

22from contextlib import contextmanager 

23import secrets 

24import unittest 

25 

26try: 

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

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

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

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

31 import testing.postgresql 

32except ImportError: 

33 testing = None 

34 

35import sqlalchemy 

36 

37from lsst.daf.butler import ddl 

38from lsst.daf.butler.registry import RegistryConfig 

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

40from lsst.daf.butler.registry import Registry 

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

42 

43 

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

45class PostgresqlDatabaseTestCase(unittest.TestCase, DatabaseTests): 

46 

47 @classmethod 

48 def setUpClass(cls): 

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

50 

51 @classmethod 

52 def tearDownClass(cls): 

53 cls.server.stop() 

54 

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

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

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

58 

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

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

61 namespace=database.namespace, writeable=writeable) 

62 

63 @contextmanager 

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

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

66 

67 def testNameShrinking(self): 

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

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

70 """ 

71 db = self.makeEmptyDatabase(origin=1) 

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

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

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

75 # appear in sequences and constraints) is not. 

76 tableName = "a_table_with_a_very_very_long_42_char_name" 

77 fieldName1 = "a_column_with_a_very_very_long_43_char_name" 

78 fieldName2 = "another_column_with_a_very_very_long_49_char_name" 

79 context.addTable( 

80 tableName, 

81 ddl.TableSpec( 

82 fields=[ 

83 ddl.FieldSpec( 

84 fieldName1, 

85 dtype=sqlalchemy.BigInteger, 

86 autoincrement=True, 

87 primaryKey=True 

88 ), 

89 ddl.FieldSpec( 

90 fieldName2, 

91 dtype=sqlalchemy.String, 

92 length=16, 

93 nullable=False, 

94 ), 

95 ], 

96 unique={(fieldName2,)}, 

97 ) 

98 ) 

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

100 # first table. 

101 db.ensureTableExists( 

102 tableName + "_b", 

103 ddl.TableSpec( 

104 fields=[ 

105 ddl.FieldSpec( 

106 fieldName1 + "_b", 

107 dtype=sqlalchemy.BigInteger, 

108 autoincrement=True, 

109 primaryKey=True 

110 ), 

111 ddl.FieldSpec( 

112 fieldName2 + "_b", 

113 dtype=sqlalchemy.String, 

114 length=16, 

115 nullable=False, 

116 ), 

117 ], 

118 foreignKeys=[ 

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

120 ] 

121 ) 

122 ) 

123 

124 

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

126class PostgresqlRegistryTestCase(unittest.TestCase, RegistryTests): 

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

128 """ 

129 

130 @classmethod 

131 def setUpClass(cls): 

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

133 

134 @classmethod 

135 def tearDownClass(cls): 

136 cls.server.stop() 

137 

138 def makeRegistry(self) -> Registry: 

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

140 config = RegistryConfig() 

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

142 config["namespace"] = namespace 

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

144 

145 

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

147 unittest.main()