Coverage for tests/test_postgresql.py : 61%

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/>.
22import os
23from contextlib import contextmanager
24import secrets
25import unittest
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
36import sqlalchemy
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
45@unittest.skipUnless(testing is not None, "testing.postgresql module not found")
46class PostgresqlDatabaseTestCase(unittest.TestCase, DatabaseTests):
48 @classmethod
49 def setUpClass(cls):
50 cls.server = testing.postgresql.Postgresql()
52 @classmethod
53 def tearDownClass(cls):
54 cls.server.stop()
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)
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)
64 @contextmanager
65 def asReadOnly(self, database: PostgresqlDatabase) -> PostgresqlDatabase:
66 yield self.getNewConnection(database, writeable=False)
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 )
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 """
131 @classmethod
132 def setUpClass(cls):
133 cls.server = testing.postgresql.Postgresql()
135 @classmethod
136 def tearDownClass(cls):
137 cls.server.stop()
139 @classmethod
140 def getDataDir(cls) -> str:
141 return os.path.normpath(os.path.join(os.path.dirname(__file__), "data", "registry"))
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)
151if __name__ == "__main__": 151 ↛ 152line 151 didn't jump to line 152, because the condition on line 151 was never true
152 unittest.main()