1515from pytest_simcore .helpers import postgres_tools
1616from pytest_simcore .helpers .faker_factories import random_user
1717from simcore_postgres_database .models .users import UserRole , UserStatus , users
18- from simcore_postgres_database .models .users_secrets import users_secrets
1918from simcore_postgres_database .utils_repos import (
2019 pass_or_acquire_connection ,
2120 transaction_context ,
@@ -247,7 +246,12 @@ def sync_engine_with_migration(
247246def test_users_secrets_migration_upgrade_downgrade (
248247 sync_engine_with_migration : sqlalchemy .engine .Engine , faker : Faker
249248):
250- """Tests the migration script that moves password_hash from users to users_secrets table."""
249+ """Tests the migration script that moves password_hash from users to users_secrets table.
250+
251+
252+ NOTE: all statements in conn.execute(...) must be sa.text(...) since at that migration point the schemas of the
253+ code models might not be the same
254+ """
251255 assert simcore_postgres_database .cli .discover .callback
252256 assert simcore_postgres_database .cli .upgrade .callback
253257 assert simcore_postgres_database .cli .downgrade .callback
@@ -264,35 +268,45 @@ def test_users_secrets_migration_upgrade_downgrade(
264268 assert "psycopg2.errors.UndefinedTable" in f"{ exc_info .value } "
265269
266270 # INSERT users with password hashes (emulates data in-place before migration)
267- users_data = [
268- random_user (
269- faker ,
270- name = "user_with_password_1" ,
271- 272- password_hash = "hashed_password_1" , # noqa: S106
273- status = UserStatus .ACTIVE ,
274- ),
275- random_user (
276- faker ,
277- name = "user_with_password_2" ,
278- 279- password_hash = "hashed_password_2" , # noqa: S106
280- status = UserStatus .ACTIVE ,
281- ),
271+ users_data_with_hashed_password = [
272+ {
273+ ** random_user (
274+ faker ,
275+ name = "user_with_password_1" ,
276+ 277+ role = UserRole .USER .value ,
278+ status = UserStatus .ACTIVE ,
279+ ),
280+ "password_hash" : "hashed_password_1" , # noqa: S106
281+ },
282+ {
283+ ** random_user (
284+ faker ,
285+ name = "user_with_password_2" ,
286+ 287+ role = UserRole .USER .value ,
288+ status = UserStatus .ACTIVE ,
289+ ),
290+ "password_hash" : "hashed_password_2" , # noqa: S106
291+ },
282292 ]
283293
284294 inserted_user_ids = []
285- for user_data in users_data :
295+ for user_data in users_data_with_hashed_password :
296+ columns = ", " .join (user_data .keys ())
297+ values_placeholders = ", " .join (f":{ key } " for key in user_data )
286298 result = conn .execute (
287- users .insert ().values (** user_data ).returning (users .c .id )
299+ sa .text (
300+ f"INSERT INTO users ({ columns } ) VALUES ({ values_placeholders } ) RETURNING id" # noqa: S608
301+ ),
302+ user_data ,
288303 )
289304 inserted_user_ids .append (result .scalar ())
290305
291306 # Verify password hashes are in users table
292307 result = conn .execute (
293- sa .select (users .c .id , users .c .password_hash ).where (
294- users .c .id .in_ (inserted_user_ids )
295- )
308+ sa .text ("SELECT id, password_hash FROM users WHERE id = ANY(:user_ids)" ),
309+ {"user_ids" : inserted_user_ids },
296310 ).fetchall ()
297311
298312 password_hashes_before = {row .id : row .password_hash for row in result }
@@ -306,9 +320,7 @@ def test_users_secrets_migration_upgrade_downgrade(
306320 with sync_engine_with_migration .connect () as conn :
307321 # Verify users_secrets table exists and contains the password hashes
308322 result = conn .execute (
309- sa .select (users_secrets .c .user_id , users_secrets .c .password_hash ).order_by (
310- users_secrets .c .user_id
311- )
323+ sa .text ("SELECT user_id, password_hash FROM users_secrets ORDER BY user_id" )
312324 ).fetchall ()
313325
314326 # Only users with non-null password hashes should be in users_secrets
@@ -319,7 +331,7 @@ def test_users_secrets_migration_upgrade_downgrade(
319331
320332 # Verify password_hash column is removed from users table
321333 with pytest .raises (sqlalchemy .exc .ProgrammingError ) as exc_info :
322- conn .execute (sa .select ( users . c . password_hash ))
334+ conn .execute (sa .text ( "SELECT password_hash FROM users" ))
323335 assert "psycopg2.errors.UndefinedColumn" in f"{ exc_info .value } "
324336
325337 # MIGRATE DOWNGRADE: this should move password hashes back to users
@@ -328,14 +340,13 @@ def test_users_secrets_migration_upgrade_downgrade(
328340 with sync_engine_with_migration .connect () as conn :
329341 # Verify users_secrets table no longer exists
330342 with pytest .raises (sqlalchemy .exc .ProgrammingError ) as exc_info :
331- conn .execute (sa .select ( sa . func . count ()). select_from ( users_secrets )).scalar ()
343+ conn .execute (sa .text ( "SELECT COUNT(*) FROM users_secrets" )).scalar ()
332344 assert "psycopg2.errors.UndefinedTable" in f"{ exc_info .value } "
333345
334346 # Verify password hashes are back in users table
335347 result = conn .execute (
336- sa .select (users .c .id , users .c .password_hash ).where (
337- users .c .id .in_ (inserted_user_ids )
338- )
348+ sa .text ("SELECT id, password_hash FROM users WHERE id = ANY(:user_ids)" ),
349+ {"user_ids" : inserted_user_ids },
339350 ).fetchall ()
340351
341352 password_hashes_after = {row .id : row .password_hash for row in result }
0 commit comments