velocity-python 0.0.109__py3-none-any.whl → 0.0.161__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- velocity/__init__.py +3 -1
- velocity/app/orders.py +3 -4
- velocity/app/tests/__init__.py +1 -0
- velocity/app/tests/test_email_processing.py +112 -0
- velocity/app/tests/test_payment_profile_sorting.py +191 -0
- velocity/app/tests/test_spreadsheet_functions.py +124 -0
- velocity/aws/__init__.py +3 -0
- velocity/aws/amplify.py +10 -6
- velocity/aws/handlers/__init__.py +2 -0
- velocity/aws/handlers/base_handler.py +248 -0
- velocity/aws/handlers/context.py +251 -2
- velocity/aws/handlers/exceptions.py +16 -0
- velocity/aws/handlers/lambda_handler.py +24 -85
- velocity/aws/handlers/mixins/__init__.py +16 -0
- velocity/aws/handlers/mixins/activity_tracker.py +181 -0
- velocity/aws/handlers/mixins/aws_session_mixin.py +192 -0
- velocity/aws/handlers/mixins/error_handler.py +192 -0
- velocity/aws/handlers/mixins/legacy_mixin.py +53 -0
- velocity/aws/handlers/mixins/standard_mixin.py +73 -0
- velocity/aws/handlers/response.py +1 -1
- velocity/aws/handlers/sqs_handler.py +28 -143
- velocity/aws/tests/__init__.py +1 -0
- velocity/aws/tests/test_lambda_handler_json_serialization.py +120 -0
- velocity/aws/tests/test_response.py +163 -0
- velocity/db/__init__.py +16 -4
- velocity/db/core/decorators.py +48 -13
- velocity/db/core/engine.py +187 -840
- velocity/db/core/result.py +33 -25
- velocity/db/core/row.py +15 -3
- velocity/db/core/table.py +493 -50
- velocity/db/core/transaction.py +28 -15
- velocity/db/exceptions.py +42 -18
- velocity/db/servers/base/__init__.py +9 -0
- velocity/db/servers/base/initializer.py +70 -0
- velocity/db/servers/base/operators.py +98 -0
- velocity/db/servers/base/sql.py +503 -0
- velocity/db/servers/base/types.py +135 -0
- velocity/db/servers/mysql/__init__.py +73 -0
- velocity/db/servers/mysql/operators.py +54 -0
- velocity/db/servers/{mysql_reserved.py → mysql/reserved.py} +2 -14
- velocity/db/servers/mysql/sql.py +718 -0
- velocity/db/servers/mysql/types.py +107 -0
- velocity/db/servers/postgres/__init__.py +59 -11
- velocity/db/servers/postgres/operators.py +34 -0
- velocity/db/servers/postgres/sql.py +474 -120
- velocity/db/servers/postgres/types.py +88 -2
- velocity/db/servers/sqlite/__init__.py +61 -0
- velocity/db/servers/sqlite/operators.py +52 -0
- velocity/db/servers/sqlite/reserved.py +20 -0
- velocity/db/servers/sqlite/sql.py +677 -0
- velocity/db/servers/sqlite/types.py +92 -0
- velocity/db/servers/sqlserver/__init__.py +73 -0
- velocity/db/servers/sqlserver/operators.py +47 -0
- velocity/db/servers/sqlserver/reserved.py +32 -0
- velocity/db/servers/sqlserver/sql.py +805 -0
- velocity/db/servers/sqlserver/types.py +114 -0
- velocity/db/servers/tablehelper.py +117 -91
- velocity/db/tests/__init__.py +1 -0
- velocity/db/tests/common_db_test.py +0 -0
- velocity/db/tests/postgres/__init__.py +1 -0
- velocity/db/tests/postgres/common.py +49 -0
- velocity/db/tests/postgres/test_column.py +29 -0
- velocity/db/tests/postgres/test_connections.py +25 -0
- velocity/db/tests/postgres/test_database.py +21 -0
- velocity/db/tests/postgres/test_engine.py +205 -0
- velocity/db/tests/postgres/test_general_usage.py +88 -0
- velocity/db/tests/postgres/test_imports.py +8 -0
- velocity/db/tests/postgres/test_result.py +19 -0
- velocity/db/tests/postgres/test_row.py +137 -0
- velocity/db/tests/postgres/test_row_comprehensive.py +720 -0
- velocity/db/tests/postgres/test_schema_locking.py +335 -0
- velocity/db/tests/postgres/test_schema_locking_unit.py +115 -0
- velocity/db/tests/postgres/test_sequence.py +34 -0
- velocity/db/tests/postgres/test_sql_comprehensive.py +462 -0
- velocity/db/tests/postgres/test_table.py +101 -0
- velocity/db/tests/postgres/test_table_comprehensive.py +646 -0
- velocity/db/tests/postgres/test_transaction.py +106 -0
- velocity/db/tests/sql/__init__.py +1 -0
- velocity/db/tests/sql/common.py +177 -0
- velocity/db/tests/sql/test_postgres_select_advanced.py +285 -0
- velocity/db/tests/sql/test_postgres_select_variances.py +517 -0
- velocity/db/tests/test_cursor_rowcount_fix.py +150 -0
- velocity/db/tests/test_db_utils.py +270 -0
- velocity/db/tests/test_postgres.py +448 -0
- velocity/db/tests/test_postgres_unchanged.py +81 -0
- velocity/db/tests/test_process_error_robustness.py +292 -0
- velocity/db/tests/test_result_caching.py +279 -0
- velocity/db/tests/test_result_sql_aware.py +117 -0
- velocity/db/tests/test_row_get_missing_column.py +72 -0
- velocity/db/tests/test_schema_locking_initializers.py +226 -0
- velocity/db/tests/test_schema_locking_simple.py +97 -0
- velocity/db/tests/test_sql_builder.py +165 -0
- velocity/db/tests/test_tablehelper.py +486 -0
- velocity/db/utils.py +129 -51
- velocity/misc/conv/__init__.py +2 -0
- velocity/misc/conv/iconv.py +5 -4
- velocity/misc/export.py +1 -4
- velocity/misc/merge.py +1 -1
- velocity/misc/tests/__init__.py +1 -0
- velocity/misc/tests/test_db.py +90 -0
- velocity/misc/tests/test_fix.py +78 -0
- velocity/misc/tests/test_format.py +64 -0
- velocity/misc/tests/test_iconv.py +203 -0
- velocity/misc/tests/test_merge.py +82 -0
- velocity/misc/tests/test_oconv.py +144 -0
- velocity/misc/tests/test_original_error.py +52 -0
- velocity/misc/tests/test_timer.py +74 -0
- velocity/misc/tools.py +0 -1
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/METADATA +2 -2
- velocity_python-0.0.161.dist-info/RECORD +129 -0
- velocity/db/core/exceptions.py +0 -70
- velocity/db/servers/mysql.py +0 -641
- velocity/db/servers/sqlite.py +0 -968
- velocity/db/servers/sqlite_reserved.py +0 -208
- velocity/db/servers/sqlserver.py +0 -921
- velocity/db/servers/sqlserver_reserved.py +0 -314
- velocity_python-0.0.109.dist-info/RECORD +0 -56
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/WHEEL +0 -0
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/licenses/LICENSE +0 -0
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
from velocity.db.servers import postgres
|
|
5
|
+
from velocity.db.exceptions import DbSchemaLockedError, DbTableMissingError
|
|
6
|
+
import env
|
|
7
|
+
env.set()
|
|
8
|
+
|
|
9
|
+
test_db = "test_db_schema_locking"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestSchemaLocking(unittest.TestCase):
|
|
13
|
+
"""Test schema locking functionality with real database connections"""
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def setUpClass(cls):
|
|
17
|
+
"""Set up test environment before all tests"""
|
|
18
|
+
# Create test database with unlocked schema for setup
|
|
19
|
+
setup_engine = postgres.initialize(database="postgres", schema_locked=False)
|
|
20
|
+
|
|
21
|
+
@setup_engine.transaction
|
|
22
|
+
def create_test_db(tx):
|
|
23
|
+
tx.execute(f"drop database if exists {test_db}", single=True)
|
|
24
|
+
tx.database(test_db).create()
|
|
25
|
+
|
|
26
|
+
create_test_db()
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def tearDownClass(cls):
|
|
30
|
+
"""Clean up test environment after all tests"""
|
|
31
|
+
# Remove test database
|
|
32
|
+
cleanup_engine = postgres.initialize(database="postgres", schema_locked=False)
|
|
33
|
+
|
|
34
|
+
@cleanup_engine.transaction
|
|
35
|
+
def cleanup_test_db(tx):
|
|
36
|
+
tx.execute(f"drop database if exists {test_db}", single=True)
|
|
37
|
+
|
|
38
|
+
cleanup_test_db()
|
|
39
|
+
|
|
40
|
+
def setUp(self):
|
|
41
|
+
"""Set up test environment before each test"""
|
|
42
|
+
# Clean up any test tables that might exist from previous runs
|
|
43
|
+
cleanup_engine = postgres.initialize(database=test_db, schema_locked=False)
|
|
44
|
+
|
|
45
|
+
@cleanup_engine.transaction
|
|
46
|
+
def cleanup(tx):
|
|
47
|
+
test_tables = [
|
|
48
|
+
'auto_created_table',
|
|
49
|
+
'definitely_nonexistent_table',
|
|
50
|
+
'runtime_test_table',
|
|
51
|
+
'context_test_table',
|
|
52
|
+
'env_test_table'
|
|
53
|
+
]
|
|
54
|
+
for table_name in test_tables:
|
|
55
|
+
table = tx.table(table_name)
|
|
56
|
+
if table.exists():
|
|
57
|
+
table.drop()
|
|
58
|
+
|
|
59
|
+
cleanup()
|
|
60
|
+
|
|
61
|
+
def test_unlocked_schema_allows_creation(self):
|
|
62
|
+
"""Test that unlocked schema allows automatic table/column creation"""
|
|
63
|
+
unlocked_engine = postgres.initialize(database=test_db, schema_locked=False)
|
|
64
|
+
|
|
65
|
+
@unlocked_engine.transaction
|
|
66
|
+
def test_auto_creation(tx):
|
|
67
|
+
# This should automatically create the table and columns
|
|
68
|
+
new_table = tx.table('auto_created_table')
|
|
69
|
+
|
|
70
|
+
new_table.insert({
|
|
71
|
+
'name': 'Test User',
|
|
72
|
+
'email': 'test@example.com',
|
|
73
|
+
'age': 25
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
# Verify the table was created and record inserted
|
|
77
|
+
self.assertTrue(new_table.exists())
|
|
78
|
+
result = new_table.select().one()
|
|
79
|
+
self.assertEqual(result['name'], 'Test User')
|
|
80
|
+
self.assertEqual(result['email'], 'test@example.com')
|
|
81
|
+
self.assertEqual(result['age'], 25)
|
|
82
|
+
|
|
83
|
+
# Test adding a new column to existing table
|
|
84
|
+
new_table.insert({
|
|
85
|
+
'name': 'Test User 2',
|
|
86
|
+
'email': 'test2@example.com',
|
|
87
|
+
'age': 30,
|
|
88
|
+
'city': 'New York' # This should create a new column
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
# Verify new column was added
|
|
92
|
+
result2 = new_table.select(where={'name': 'Test User 2'}).one()
|
|
93
|
+
self.assertEqual(result2['city'], 'New York')
|
|
94
|
+
|
|
95
|
+
test_auto_creation()
|
|
96
|
+
|
|
97
|
+
def test_locked_schema_prevents_creation(self):
|
|
98
|
+
"""Test that locked schema prevents automatic table/column creation"""
|
|
99
|
+
engine = postgres.initialize(database=test_db, schema_locked=True)
|
|
100
|
+
|
|
101
|
+
@engine.transaction
|
|
102
|
+
def test_blocked_creation(tx):
|
|
103
|
+
# This should raise DbSchemaLockedError when trying to create the table
|
|
104
|
+
nonexistent_table = tx.table('definitely_nonexistent_table')
|
|
105
|
+
|
|
106
|
+
with self.assertRaises(DbSchemaLockedError) as context:
|
|
107
|
+
nonexistent_table.insert({
|
|
108
|
+
'name': 'Test User',
|
|
109
|
+
'email': 'test@example.com'
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
# Check that the error message mentions schema locking
|
|
113
|
+
self.assertIn("schema is locked", str(context.exception))
|
|
114
|
+
|
|
115
|
+
# Verify the table was not created
|
|
116
|
+
self.assertFalse(nonexistent_table.exists())
|
|
117
|
+
|
|
118
|
+
test_blocked_creation()
|
|
119
|
+
|
|
120
|
+
def test_locked_schema_prevents_column_creation(self):
|
|
121
|
+
"""Test that locked schema prevents automatic column creation on existing tables"""
|
|
122
|
+
# First create a table with unlocked schema
|
|
123
|
+
setup_engine = postgres.initialize(database=test_db, schema_locked=False)
|
|
124
|
+
|
|
125
|
+
@setup_engine.transaction
|
|
126
|
+
def setup_table(tx):
|
|
127
|
+
table = tx.table('runtime_test_table')
|
|
128
|
+
table.insert({'name': 'Initial User', 'age': 25})
|
|
129
|
+
|
|
130
|
+
setup_table()
|
|
131
|
+
|
|
132
|
+
# Now try to add a column with locked schema
|
|
133
|
+
locked_engine = postgres.initialize(database=test_db, schema_locked=True)
|
|
134
|
+
|
|
135
|
+
@locked_engine.transaction
|
|
136
|
+
def test_blocked_column(tx):
|
|
137
|
+
table = tx.table('runtime_test_table')
|
|
138
|
+
|
|
139
|
+
with self.assertRaises(DbSchemaLockedError) as context:
|
|
140
|
+
# This should fail because 'email' column doesn't exist
|
|
141
|
+
table.insert({
|
|
142
|
+
'name': 'New User',
|
|
143
|
+
'age': 30,
|
|
144
|
+
'email': 'new@example.com' # This column doesn't exist yet
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
# Check that the error message mentions schema locking
|
|
148
|
+
self.assertIn("schema is locked", str(context.exception))
|
|
149
|
+
|
|
150
|
+
test_blocked_column()
|
|
151
|
+
|
|
152
|
+
def test_runtime_schema_locking(self):
|
|
153
|
+
"""Test locking and unlocking schema at runtime"""
|
|
154
|
+
engine = postgres.initialize(database=test_db, schema_locked=False)
|
|
155
|
+
|
|
156
|
+
@engine.transaction
|
|
157
|
+
def test_runtime_control(tx):
|
|
158
|
+
# Should work initially (unlocked)
|
|
159
|
+
table = tx.table('runtime_test_table_2')
|
|
160
|
+
|
|
161
|
+
table.insert({'name': 'Test 1', 'status': 'active'})
|
|
162
|
+
self.assertTrue(table.exists())
|
|
163
|
+
|
|
164
|
+
# Verify record exists
|
|
165
|
+
result = table.select().one()
|
|
166
|
+
self.assertEqual(result['name'], 'Test 1')
|
|
167
|
+
|
|
168
|
+
test_runtime_control()
|
|
169
|
+
|
|
170
|
+
# Lock schema at runtime
|
|
171
|
+
engine.lock_schema()
|
|
172
|
+
self.assertTrue(engine.schema_locked)
|
|
173
|
+
|
|
174
|
+
@engine.transaction
|
|
175
|
+
def test_locked_state(tx):
|
|
176
|
+
table = tx.table('runtime_test_table_2')
|
|
177
|
+
|
|
178
|
+
# Should still be able to insert into existing table with existing columns
|
|
179
|
+
table.insert({'name': 'Test 2', 'status': 'active'})
|
|
180
|
+
|
|
181
|
+
# But should fail when trying to add new column
|
|
182
|
+
with self.assertRaises(DbSchemaLockedError):
|
|
183
|
+
table.insert({'name': 'Test 3', 'status': 'active', 'new_column': 'value'})
|
|
184
|
+
|
|
185
|
+
test_locked_state()
|
|
186
|
+
|
|
187
|
+
# Unlock schema
|
|
188
|
+
engine.unlock_schema()
|
|
189
|
+
self.assertFalse(engine.schema_locked)
|
|
190
|
+
|
|
191
|
+
@engine.transaction
|
|
192
|
+
def test_unlocked_again(tx):
|
|
193
|
+
table = tx.table('runtime_test_table_2')
|
|
194
|
+
|
|
195
|
+
# Should work again (unlocked) - can add new column
|
|
196
|
+
table.insert({'name': 'Test 4', 'status': 'active', 'new_column': 'success'})
|
|
197
|
+
|
|
198
|
+
result = table.select(where={'name': 'Test 4'}).one()
|
|
199
|
+
self.assertEqual(result['new_column'], 'success')
|
|
200
|
+
|
|
201
|
+
test_unlocked_again()
|
|
202
|
+
|
|
203
|
+
def test_temporary_unlock_context_manager(self):
|
|
204
|
+
"""Test temporarily unlocking schema with context manager"""
|
|
205
|
+
engine = postgres.initialize(database=test_db, schema_locked=True)
|
|
206
|
+
|
|
207
|
+
@engine.transaction
|
|
208
|
+
def test_context_unlock(tx):
|
|
209
|
+
# Should be locked initially
|
|
210
|
+
table = tx.table('context_test_table')
|
|
211
|
+
table.drop() # Clean up first if exists
|
|
212
|
+
|
|
213
|
+
with self.assertRaises(DbSchemaLockedError):
|
|
214
|
+
table.insert({'name': 'Test 1'})
|
|
215
|
+
|
|
216
|
+
# Temporarily unlock
|
|
217
|
+
with engine.unlocked_schema():
|
|
218
|
+
# Should work inside context
|
|
219
|
+
table.insert({'name': 'Test 2'})
|
|
220
|
+
self.assertTrue(table.exists())
|
|
221
|
+
|
|
222
|
+
# Schema should be unlocked inside context
|
|
223
|
+
self.assertFalse(engine.schema_locked)
|
|
224
|
+
|
|
225
|
+
# Should be locked again after context
|
|
226
|
+
self.assertTrue(engine.schema_locked)
|
|
227
|
+
|
|
228
|
+
# Verify we can still use the table (just can't create new ones)
|
|
229
|
+
result = table.select().one()
|
|
230
|
+
self.assertEqual(result['name'], 'Test 2')
|
|
231
|
+
|
|
232
|
+
# Clean up
|
|
233
|
+
table.drop()
|
|
234
|
+
|
|
235
|
+
test_context_unlock()
|
|
236
|
+
|
|
237
|
+
def test_environment_variable_override(self):
|
|
238
|
+
"""Test that VELOCITY_SCHEMA_LOCKED environment variable works"""
|
|
239
|
+
# Set environment variable
|
|
240
|
+
os.environ['VELOCITY_SCHEMA_LOCKED'] = 'true'
|
|
241
|
+
|
|
242
|
+
try:
|
|
243
|
+
# Even though we specify schema_locked=False, env var should override
|
|
244
|
+
engine = postgres.initialize(database=test_db, schema_locked=False)
|
|
245
|
+
self.assertTrue(engine.schema_locked)
|
|
246
|
+
|
|
247
|
+
# Test that it actually blocks operations
|
|
248
|
+
@engine.transaction
|
|
249
|
+
def test_env_override(tx):
|
|
250
|
+
table = tx.table('env_test_table')
|
|
251
|
+
|
|
252
|
+
with self.assertRaises(DbSchemaLockedError):
|
|
253
|
+
table.insert({'name': 'Test', 'env_test': 'should_fail'})
|
|
254
|
+
|
|
255
|
+
test_env_override()
|
|
256
|
+
|
|
257
|
+
finally:
|
|
258
|
+
# Clean up environment variable
|
|
259
|
+
if 'VELOCITY_SCHEMA_LOCKED' in os.environ:
|
|
260
|
+
del os.environ['VELOCITY_SCHEMA_LOCKED']
|
|
261
|
+
|
|
262
|
+
def test_existing_table_operations_still_work(self):
|
|
263
|
+
"""Test that existing table operations work even with locked schema"""
|
|
264
|
+
# First, create a table with unlocked schema
|
|
265
|
+
setup_engine = postgres.initialize(database=test_db, schema_locked=False)
|
|
266
|
+
|
|
267
|
+
@setup_engine.transaction
|
|
268
|
+
def create_test_table(tx):
|
|
269
|
+
table = tx.table('existing_table_test')
|
|
270
|
+
table.insert({'name': 'User 1', 'email': 'user1@test.com', 'active': True})
|
|
271
|
+
table.insert({'name': 'User 2', 'email': 'user2@test.com', 'active': False})
|
|
272
|
+
|
|
273
|
+
create_test_table()
|
|
274
|
+
|
|
275
|
+
# Now use locked schema and verify existing operations work
|
|
276
|
+
locked_engine = postgres.initialize(database=test_db, schema_locked=True)
|
|
277
|
+
|
|
278
|
+
@locked_engine.transaction
|
|
279
|
+
def test_existing_operations(tx):
|
|
280
|
+
table = tx.table('existing_table_test')
|
|
281
|
+
|
|
282
|
+
# Reading should work
|
|
283
|
+
all_users = table.select().all()
|
|
284
|
+
self.assertEqual(len(all_users), 2)
|
|
285
|
+
|
|
286
|
+
# Inserting with existing columns should work
|
|
287
|
+
table.insert({'name': 'User 3', 'email': 'user3@test.com', 'active': True})
|
|
288
|
+
|
|
289
|
+
# Updating should work
|
|
290
|
+
table.update({'active': False}, where={'name': 'User 1'})
|
|
291
|
+
|
|
292
|
+
# Verify updates
|
|
293
|
+
user1 = table.select(where={'name': 'User 1'}).one()
|
|
294
|
+
self.assertFalse(user1['active'])
|
|
295
|
+
|
|
296
|
+
# Count should be 3 now
|
|
297
|
+
count = table.count()
|
|
298
|
+
self.assertEqual(count, 3)
|
|
299
|
+
|
|
300
|
+
# But adding new columns should still fail
|
|
301
|
+
with self.assertRaises(DbSchemaLockedError):
|
|
302
|
+
table.insert({'name': 'User 4', 'email': 'user4@test.com', 'active': True, 'new_field': 'fail'})
|
|
303
|
+
|
|
304
|
+
test_existing_operations()
|
|
305
|
+
|
|
306
|
+
def tearDown(self):
|
|
307
|
+
"""Clean up after each test"""
|
|
308
|
+
# Clean up test tables
|
|
309
|
+
engine = postgres.initialize(database=test_db, schema_locked=False)
|
|
310
|
+
|
|
311
|
+
@engine.transaction
|
|
312
|
+
def cleanup(tx):
|
|
313
|
+
test_tables = [
|
|
314
|
+
'auto_created_table',
|
|
315
|
+
'definitely_nonexistent_table',
|
|
316
|
+
'runtime_test_table',
|
|
317
|
+
'runtime_test_table_2',
|
|
318
|
+
'context_test_table',
|
|
319
|
+
'env_test_table',
|
|
320
|
+
'existing_table_test'
|
|
321
|
+
]
|
|
322
|
+
for table_name in test_tables:
|
|
323
|
+
table = tx.table(table_name)
|
|
324
|
+
if table.exists():
|
|
325
|
+
table.drop()
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
cleanup()
|
|
329
|
+
except Exception:
|
|
330
|
+
# Ignore cleanup errors
|
|
331
|
+
pass
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
if __name__ == "__main__":
|
|
335
|
+
unittest.main()
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import os
|
|
3
|
+
from velocity.db.core.engine import Engine
|
|
4
|
+
from velocity.db.exceptions import DbSchemaLockedError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MockDriver:
|
|
8
|
+
"""Mock database driver for testing"""
|
|
9
|
+
def connect(self, **kwargs):
|
|
10
|
+
return None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MockSQL:
|
|
14
|
+
"""Mock SQL dialect for testing"""
|
|
15
|
+
server = "MockDB"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestSchemaLockingUnit(unittest.TestCase):
|
|
19
|
+
"""Unit tests for schema locking functionality without database connection"""
|
|
20
|
+
|
|
21
|
+
def test_engine_schema_locked_property(self):
|
|
22
|
+
"""Test engine schema_locked property and methods"""
|
|
23
|
+
# Test default unlocked state
|
|
24
|
+
engine = Engine(MockDriver(), {}, MockSQL(), schema_locked=False)
|
|
25
|
+
self.assertFalse(engine.schema_locked)
|
|
26
|
+
|
|
27
|
+
# Test locked initialization
|
|
28
|
+
locked_engine = Engine(MockDriver(), {}, MockSQL(), schema_locked=True)
|
|
29
|
+
self.assertTrue(locked_engine.schema_locked)
|
|
30
|
+
|
|
31
|
+
def test_schema_lock_unlock_methods(self):
|
|
32
|
+
"""Test runtime locking and unlocking"""
|
|
33
|
+
engine = Engine(MockDriver(), {}, MockSQL(), schema_locked=False)
|
|
34
|
+
|
|
35
|
+
# Initially unlocked
|
|
36
|
+
self.assertFalse(engine.schema_locked)
|
|
37
|
+
|
|
38
|
+
# Lock schema
|
|
39
|
+
engine.lock_schema()
|
|
40
|
+
self.assertTrue(engine.schema_locked)
|
|
41
|
+
|
|
42
|
+
# Unlock schema
|
|
43
|
+
engine.unlock_schema()
|
|
44
|
+
self.assertFalse(engine.schema_locked)
|
|
45
|
+
|
|
46
|
+
def test_unlocked_schema_context_manager(self):
|
|
47
|
+
"""Test the context manager for temporarily unlocking schema"""
|
|
48
|
+
engine = Engine(MockDriver(), {}, MockSQL(), schema_locked=True)
|
|
49
|
+
|
|
50
|
+
# Initially locked
|
|
51
|
+
self.assertTrue(engine.schema_locked)
|
|
52
|
+
|
|
53
|
+
# Temporarily unlock
|
|
54
|
+
with engine.unlocked_schema():
|
|
55
|
+
self.assertFalse(engine.schema_locked)
|
|
56
|
+
|
|
57
|
+
# Should be locked again after context
|
|
58
|
+
self.assertTrue(engine.schema_locked)
|
|
59
|
+
|
|
60
|
+
def test_nested_unlocked_schema_context(self):
|
|
61
|
+
"""Test nested context managers"""
|
|
62
|
+
engine = Engine(MockDriver(), {}, MockSQL(), schema_locked=True)
|
|
63
|
+
|
|
64
|
+
self.assertTrue(engine.schema_locked)
|
|
65
|
+
|
|
66
|
+
with engine.unlocked_schema():
|
|
67
|
+
self.assertFalse(engine.schema_locked)
|
|
68
|
+
|
|
69
|
+
# Nested context - should stay unlocked
|
|
70
|
+
with engine.unlocked_schema():
|
|
71
|
+
self.assertFalse(engine.schema_locked)
|
|
72
|
+
|
|
73
|
+
# Still unlocked in outer context
|
|
74
|
+
self.assertFalse(engine.schema_locked)
|
|
75
|
+
|
|
76
|
+
# Back to original locked state
|
|
77
|
+
self.assertTrue(engine.schema_locked)
|
|
78
|
+
|
|
79
|
+
def test_environment_variable_parsing(self):
|
|
80
|
+
"""Test environment variable parsing for schema locking"""
|
|
81
|
+
# Test various truthy values
|
|
82
|
+
test_cases = [
|
|
83
|
+
('true', True),
|
|
84
|
+
('True', True),
|
|
85
|
+
('TRUE', True),
|
|
86
|
+
('1', True),
|
|
87
|
+
('yes', True),
|
|
88
|
+
('YES', True),
|
|
89
|
+
('false', False),
|
|
90
|
+
('0', False),
|
|
91
|
+
('no', False),
|
|
92
|
+
('', False),
|
|
93
|
+
('random', False),
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
for env_value, expected in test_cases:
|
|
97
|
+
with self.subTest(env_value=env_value):
|
|
98
|
+
# Mock the environment variable check
|
|
99
|
+
if env_value.lower() in ('true', '1', 'yes'):
|
|
100
|
+
schema_locked = True
|
|
101
|
+
else:
|
|
102
|
+
schema_locked = False
|
|
103
|
+
|
|
104
|
+
self.assertEqual(schema_locked, expected)
|
|
105
|
+
|
|
106
|
+
def test_schema_locked_error_creation(self):
|
|
107
|
+
"""Test that DbSchemaLockedError can be created and raised"""
|
|
108
|
+
with self.assertRaises(DbSchemaLockedError) as context:
|
|
109
|
+
raise DbSchemaLockedError("Test schema lock error")
|
|
110
|
+
|
|
111
|
+
self.assertIn("Test schema lock error", str(context.exception))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
unittest.main()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
from velocity.db.core.sequence import Sequence
|
|
5
|
+
from .common import CommonPostgresTest, engine, test_db
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@engine.transaction
|
|
9
|
+
@engine.transaction
|
|
10
|
+
class TestSequence(CommonPostgresTest):
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def create_test_tables(cls, tx):
|
|
14
|
+
"""No special tables needed for sequence tests."""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def test_sequence_create(self, tx):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
def test_sequence_next(self, tx):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def test_sequence_current(self, tx):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
def test_sequence_reset(self, tx):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
def test_sequence_drop(self, tx):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
unittest.main()
|