Coverage for tests/test_postgresql.py : 60%

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/>.
22from contextlib import contextmanager
23import secrets
24import unittest
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
35import sqlalchemy
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
44@unittest.skipUnless(testing is not None, "testing.postgresql module not found")
45class PostgresqlDatabaseTestCase(unittest.TestCase, DatabaseTests):
47 @classmethod
48 def setUpClass(cls):
49 cls.server = testing.postgresql.Postgresql()
51 @classmethod
52 def tearDownClass(cls):
53 cls.server.stop()
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)
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)
63 @contextmanager
64 def asReadOnly(self, database: PostgresqlDatabase) -> PostgresqlDatabase:
65 yield self.getNewConnection(database, writeable=False)
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 )
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 """
130 @classmethod
131 def setUpClass(cls):
132 cls.server = testing.postgresql.Postgresql()
134 @classmethod
135 def tearDownClass(cls):
136 cls.server.stop()
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)
146if __name__ == "__main__": 146 ↛ 147line 146 didn't jump to line 147, because the condition on line 146 was never true
147 unittest.main()