1111# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212# See the License for the specific language governing permissions and
1313# limitations under the License.
14+ from typing import List
15+ from unittest import mock
16+
1417from synapse .app .generic_worker import GenericWorkerServer
1518from synapse .storage .database import LoggingDatabaseConnection
1619from synapse .storage .prepare_database import PrepareDatabaseException , prepare_database
1922from tests .unittest import HomeserverTestCase
2023
2124
25+ def fake_listdir (filepath : str ) -> List [str ]:
26+ """
27+ A fake implementation of os.listdir which we can use to mock out the filesystem.
28+
29+ Args:
30+ filepath: The directory to list files for.
31+
32+ Returns:
33+ A list of files and folders in the directory.
34+ """
35+ if filepath .endswith ("full_schemas" ):
36+ return [SCHEMA_VERSION ]
37+
38+ return ["99_add_unicorn_to_database.sql" ]
39+
40+
2241class WorkerSchemaTests (HomeserverTestCase ):
2342 def make_homeserver (self , reactor , clock ):
2443 hs = self .setup_test_homeserver (
@@ -51,7 +70,7 @@ def test_rolling_back(self):
5170
5271 prepare_database (db_conn , db_pool .engine , self .hs .config )
5372
54- def test_not_upgraded (self ):
73+ def test_not_upgraded_old_schema_version (self ):
5574 """Test that workers don't start if the DB has an older schema version"""
5675 db_pool = self .hs .get_datastore ().db_pool
5776 db_conn = LoggingDatabaseConnection (
@@ -67,3 +86,34 @@ def test_not_upgraded(self):
6786
6887 with self .assertRaises (PrepareDatabaseException ):
6988 prepare_database (db_conn , db_pool .engine , self .hs .config )
89+
90+ def test_not_upgraded_current_schema_version_with_outstanding_deltas (self ):
91+ """
92+ Test that workers don't start if the DB is on the current schema version,
93+ but there are still outstanding delta migrations to run.
94+ """
95+ db_pool = self .hs .get_datastore ().db_pool
96+ db_conn = LoggingDatabaseConnection (
97+ db_pool ._db_pool .connect (),
98+ db_pool .engine ,
99+ "tests" ,
100+ )
101+
102+ # Set the schema version of the database to the current version
103+ cur = db_conn .cursor ()
104+ cur .execute ("UPDATE schema_version SET version = ?" , (SCHEMA_VERSION ,))
105+
106+ db_conn .commit ()
107+
108+ # Path `os.listdir` here to make synapse think that there is a migration
109+ # file ready to be run.
110+ # Note that we can't patch this function for the whole method, else Synapse
111+ # will try to find the file when building the database initially.
112+ with mock .patch ("os.listdir" , mock .Mock (side_effect = fake_listdir )):
113+ with self .assertRaises (PrepareDatabaseException ):
114+ # Synapse should think that there is an outstanding migration file due to
115+ # patching 'os.listdir' in the function decorator.
116+ #
117+ # We expect Synapse to raise an exception to indicate the master process
118+ # needs to apply this migration file.
119+ prepare_database (db_conn , db_pool .engine , self .hs .config )
0 commit comments