matrixone-python-sdk 0.1.0__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.
Files changed (122) hide show
  1. matrixone/__init__.py +155 -0
  2. matrixone/account.py +723 -0
  3. matrixone/async_client.py +3913 -0
  4. matrixone/async_metadata_manager.py +311 -0
  5. matrixone/async_orm.py +123 -0
  6. matrixone/async_vector_index_manager.py +633 -0
  7. matrixone/base_client.py +208 -0
  8. matrixone/client.py +4672 -0
  9. matrixone/config.py +452 -0
  10. matrixone/connection_hooks.py +286 -0
  11. matrixone/exceptions.py +89 -0
  12. matrixone/logger.py +782 -0
  13. matrixone/metadata.py +820 -0
  14. matrixone/moctl.py +219 -0
  15. matrixone/orm.py +2277 -0
  16. matrixone/pitr.py +646 -0
  17. matrixone/pubsub.py +771 -0
  18. matrixone/restore.py +411 -0
  19. matrixone/search_vector_index.py +1176 -0
  20. matrixone/snapshot.py +550 -0
  21. matrixone/sql_builder.py +844 -0
  22. matrixone/sqlalchemy_ext/__init__.py +161 -0
  23. matrixone/sqlalchemy_ext/adapters.py +163 -0
  24. matrixone/sqlalchemy_ext/dialect.py +534 -0
  25. matrixone/sqlalchemy_ext/fulltext_index.py +895 -0
  26. matrixone/sqlalchemy_ext/fulltext_search.py +1686 -0
  27. matrixone/sqlalchemy_ext/hnsw_config.py +194 -0
  28. matrixone/sqlalchemy_ext/ivf_config.py +252 -0
  29. matrixone/sqlalchemy_ext/table_builder.py +351 -0
  30. matrixone/sqlalchemy_ext/vector_index.py +1721 -0
  31. matrixone/sqlalchemy_ext/vector_type.py +948 -0
  32. matrixone/version.py +580 -0
  33. matrixone_python_sdk-0.1.0.dist-info/METADATA +706 -0
  34. matrixone_python_sdk-0.1.0.dist-info/RECORD +122 -0
  35. matrixone_python_sdk-0.1.0.dist-info/WHEEL +5 -0
  36. matrixone_python_sdk-0.1.0.dist-info/entry_points.txt +5 -0
  37. matrixone_python_sdk-0.1.0.dist-info/licenses/LICENSE +200 -0
  38. matrixone_python_sdk-0.1.0.dist-info/top_level.txt +2 -0
  39. tests/__init__.py +19 -0
  40. tests/offline/__init__.py +20 -0
  41. tests/offline/conftest.py +77 -0
  42. tests/offline/test_account.py +703 -0
  43. tests/offline/test_async_client_query_comprehensive.py +1218 -0
  44. tests/offline/test_basic.py +54 -0
  45. tests/offline/test_case_sensitivity.py +227 -0
  46. tests/offline/test_connection_hooks_offline.py +287 -0
  47. tests/offline/test_dialect_schema_handling.py +609 -0
  48. tests/offline/test_explain_methods.py +346 -0
  49. tests/offline/test_filter_logical_in.py +237 -0
  50. tests/offline/test_fulltext_search_comprehensive.py +795 -0
  51. tests/offline/test_ivf_config.py +249 -0
  52. tests/offline/test_join_methods.py +281 -0
  53. tests/offline/test_join_sqlalchemy_compatibility.py +276 -0
  54. tests/offline/test_logical_in_method.py +237 -0
  55. tests/offline/test_matrixone_version_parsing.py +264 -0
  56. tests/offline/test_metadata_offline.py +557 -0
  57. tests/offline/test_moctl.py +300 -0
  58. tests/offline/test_moctl_simple.py +251 -0
  59. tests/offline/test_model_support_offline.py +359 -0
  60. tests/offline/test_model_support_simple.py +225 -0
  61. tests/offline/test_pinecone_filter_offline.py +377 -0
  62. tests/offline/test_pitr.py +585 -0
  63. tests/offline/test_pubsub.py +712 -0
  64. tests/offline/test_query_update.py +283 -0
  65. tests/offline/test_restore.py +445 -0
  66. tests/offline/test_snapshot_comprehensive.py +384 -0
  67. tests/offline/test_sql_escaping_edge_cases.py +551 -0
  68. tests/offline/test_sqlalchemy_integration.py +382 -0
  69. tests/offline/test_sqlalchemy_vector_integration.py +434 -0
  70. tests/offline/test_table_builder.py +198 -0
  71. tests/offline/test_unified_filter.py +398 -0
  72. tests/offline/test_unified_transaction.py +495 -0
  73. tests/offline/test_vector_index.py +238 -0
  74. tests/offline/test_vector_operations.py +688 -0
  75. tests/offline/test_vector_type.py +174 -0
  76. tests/offline/test_version_core.py +328 -0
  77. tests/offline/test_version_management.py +372 -0
  78. tests/offline/test_version_standalone.py +652 -0
  79. tests/online/__init__.py +20 -0
  80. tests/online/conftest.py +216 -0
  81. tests/online/test_account_management.py +194 -0
  82. tests/online/test_advanced_features.py +344 -0
  83. tests/online/test_async_client_interfaces.py +330 -0
  84. tests/online/test_async_client_online.py +285 -0
  85. tests/online/test_async_model_insert_online.py +293 -0
  86. tests/online/test_async_orm_online.py +300 -0
  87. tests/online/test_async_simple_query_online.py +802 -0
  88. tests/online/test_async_transaction_simple_query.py +300 -0
  89. tests/online/test_basic_connection.py +130 -0
  90. tests/online/test_client_online.py +238 -0
  91. tests/online/test_config.py +90 -0
  92. tests/online/test_config_validation.py +123 -0
  93. tests/online/test_connection_hooks_new_online.py +217 -0
  94. tests/online/test_dialect_schema_handling_online.py +331 -0
  95. tests/online/test_filter_logical_in_online.py +374 -0
  96. tests/online/test_fulltext_comprehensive.py +1773 -0
  97. tests/online/test_fulltext_label_online.py +433 -0
  98. tests/online/test_fulltext_search_online.py +842 -0
  99. tests/online/test_ivf_stats_online.py +506 -0
  100. tests/online/test_logger_integration.py +311 -0
  101. tests/online/test_matrixone_query_orm.py +540 -0
  102. tests/online/test_metadata_online.py +579 -0
  103. tests/online/test_model_insert_online.py +255 -0
  104. tests/online/test_mysql_driver_validation.py +213 -0
  105. tests/online/test_orm_advanced_features.py +2022 -0
  106. tests/online/test_orm_cte_integration.py +269 -0
  107. tests/online/test_orm_online.py +270 -0
  108. tests/online/test_pinecone_filter.py +708 -0
  109. tests/online/test_pubsub_operations.py +352 -0
  110. tests/online/test_query_methods.py +225 -0
  111. tests/online/test_query_update_online.py +433 -0
  112. tests/online/test_search_vector_index.py +557 -0
  113. tests/online/test_simple_fulltext_online.py +915 -0
  114. tests/online/test_snapshot_comprehensive.py +998 -0
  115. tests/online/test_sqlalchemy_engine_integration.py +336 -0
  116. tests/online/test_sqlalchemy_integration.py +425 -0
  117. tests/online/test_transaction_contexts.py +1219 -0
  118. tests/online/test_transaction_insert_methods.py +356 -0
  119. tests/online/test_transaction_query_methods.py +288 -0
  120. tests/online/test_unified_filter_online.py +529 -0
  121. tests/online/test_vector_comprehensive.py +706 -0
  122. tests/online/test_version_management.py +291 -0
@@ -0,0 +1,445 @@
1
+ # Copyright 2021 - 2022 Matrix Origin
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Unit tests for RestoreManager
17
+ """
18
+
19
+ import unittest
20
+ from unittest.mock import Mock, patch, AsyncMock
21
+ import sys
22
+ import os
23
+
24
+ # Add the matrixone package to the path
25
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'matrixone'))
26
+
27
+ from matrixone import Client, AsyncClient, RestoreError
28
+ from matrixone.exceptions import RestoreError as RestoreErrorClass
29
+ from matrixone.restore import TransactionRestoreManager
30
+
31
+
32
+ class TestRestoreManager(unittest.TestCase):
33
+ """Test cases for RestoreManager"""
34
+
35
+ def setUp(self):
36
+ """Set up test fixtures"""
37
+ self.client = Client()
38
+ self.client._engine = Mock()
39
+ self.client._escape_identifier = lambda x: f"`{x}`"
40
+ # Initialize managers manually for testing
41
+ from matrixone.restore import RestoreManager
42
+
43
+ self.restore_manager = RestoreManager(self.client)
44
+
45
+ def test_restore_cluster_success(self):
46
+ """Test successful cluster restore"""
47
+ # Mock successful execution
48
+ mock_result = Mock()
49
+ self.client.execute = Mock(return_value=mock_result)
50
+
51
+ # Test restore cluster
52
+ result = self.restore_manager.restore_cluster("cluster_snapshot_1")
53
+
54
+ # Verify
55
+ self.assertTrue(result)
56
+ self.client.execute.assert_called_once_with("RESTORE CLUSTER FROM SNAPSHOT `cluster_snapshot_1`")
57
+
58
+ def test_restore_cluster_failure(self):
59
+ """Test cluster restore failure"""
60
+ # Mock execution failure
61
+ self.client.execute = Mock(side_effect=Exception("Connection failed"))
62
+
63
+ # Test restore cluster failure
64
+ with self.assertRaises(RestoreErrorClass):
65
+ self.restore_manager.restore_cluster("cluster_snapshot_1")
66
+
67
+ def test_restore_tenant_success(self):
68
+ """Test successful tenant restore"""
69
+ # Mock successful execution
70
+ mock_result = Mock()
71
+ self.client.execute = Mock(return_value=mock_result)
72
+
73
+ # Test restore tenant to itself
74
+ result = self.restore_manager.restore_tenant("acc1_snap1", "acc1")
75
+
76
+ # Verify
77
+ self.assertTrue(result)
78
+ self.client.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` FROM SNAPSHOT `acc1_snap1`")
79
+
80
+ def test_restore_tenant_to_new_tenant(self):
81
+ """Test restore tenant to new tenant"""
82
+ # Mock successful execution
83
+ mock_result = Mock()
84
+ self.client.execute = Mock(return_value=mock_result)
85
+
86
+ # Test restore tenant to new tenant
87
+ result = self.restore_manager.restore_tenant("acc1_snap1", "acc1", "acc2")
88
+
89
+ # Verify
90
+ self.assertTrue(result)
91
+ self.client.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` FROM SNAPSHOT `acc1_snap1` TO ACCOUNT `acc2`")
92
+
93
+ def test_restore_tenant_failure(self):
94
+ """Test tenant restore failure"""
95
+ # Mock execution failure
96
+ self.client.execute = Mock(side_effect=Exception("Permission denied"))
97
+
98
+ # Test restore tenant failure
99
+ with self.assertRaises(RestoreErrorClass):
100
+ self.restore_manager.restore_tenant("acc1_snap1", "acc1")
101
+
102
+ def test_restore_database_success(self):
103
+ """Test successful database restore"""
104
+ # Mock successful execution
105
+ mock_result = Mock()
106
+ self.client.execute = Mock(return_value=mock_result)
107
+
108
+ # Test restore database
109
+ result = self.restore_manager.restore_database("acc1_db_snap1", "acc1", "db1")
110
+
111
+ # Verify
112
+ self.assertTrue(result)
113
+ self.client.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` DATABASE `db1` FROM SNAPSHOT `acc1_db_snap1`")
114
+
115
+ def test_restore_database_to_new_tenant(self):
116
+ """Test restore database to new tenant"""
117
+ # Mock successful execution
118
+ mock_result = Mock()
119
+ self.client.execute = Mock(return_value=mock_result)
120
+
121
+ # Test restore database to new tenant
122
+ result = self.restore_manager.restore_database("acc1_db_snap1", "acc1", "db1", "acc2")
123
+
124
+ # Verify
125
+ self.assertTrue(result)
126
+ self.client.execute.assert_called_once_with(
127
+ "RESTORE ACCOUNT `acc1` DATABASE `db1` FROM SNAPSHOT `acc1_db_snap1` TO ACCOUNT `acc2`"
128
+ )
129
+
130
+ def test_restore_database_failure(self):
131
+ """Test database restore failure"""
132
+ # Mock execution failure
133
+ self.client.execute = Mock(side_effect=Exception("Database not found"))
134
+
135
+ # Test restore database failure
136
+ with self.assertRaises(RestoreErrorClass):
137
+ self.restore_manager.restore_database("acc1_db_snap1", "acc1", "db1")
138
+
139
+ def test_restore_table_success(self):
140
+ """Test successful table restore"""
141
+ # Mock successful execution
142
+ mock_result = Mock()
143
+ self.client.execute = Mock(return_value=mock_result)
144
+
145
+ # Test restore table
146
+ result = self.restore_manager.restore_table("acc1_tab_snap1", "acc1", "db1", "t1")
147
+
148
+ # Verify
149
+ self.assertTrue(result)
150
+ self.client.execute.assert_called_once_with(
151
+ "RESTORE ACCOUNT `acc1` DATABASE `db1` TABLE `t1` FROM SNAPSHOT `acc1_tab_snap1`"
152
+ )
153
+
154
+ def test_restore_table_to_new_tenant(self):
155
+ """Test restore table to new tenant"""
156
+ # Mock successful execution
157
+ mock_result = Mock()
158
+ self.client.execute = Mock(return_value=mock_result)
159
+
160
+ # Test restore table to new tenant
161
+ result = self.restore_manager.restore_table("acc1_tab_snap1", "acc1", "db1", "t1", "acc2")
162
+
163
+ # Verify
164
+ self.assertTrue(result)
165
+ self.client.execute.assert_called_once_with(
166
+ "RESTORE ACCOUNT `acc1` DATABASE `db1` TABLE `t1` FROM SNAPSHOT `acc1_tab_snap1` TO ACCOUNT `acc2`"
167
+ )
168
+
169
+ def test_restore_table_failure(self):
170
+ """Test table restore failure"""
171
+ # Mock execution failure
172
+ self.client.execute = Mock(side_effect=Exception("Table not found"))
173
+
174
+ # Test restore table failure
175
+ with self.assertRaises(RestoreErrorClass):
176
+ self.restore_manager.restore_table("acc1_tab_snap1", "acc1", "db1", "t1")
177
+
178
+ def test_restore_with_executor_cluster(self):
179
+ """Test restore cluster with custom executor"""
180
+ # Mock executor
181
+ mock_executor = Mock()
182
+ mock_result = Mock()
183
+ mock_executor.execute = Mock(return_value=mock_result)
184
+
185
+ # Test restore cluster with executor
186
+ result = self.restore_manager.restore_with_executor('cluster', 'cluster_snap1', executor=mock_executor)
187
+
188
+ # Verify
189
+ self.assertTrue(result)
190
+ mock_executor.execute.assert_called_once_with("RESTORE CLUSTER FROM SNAPSHOT `cluster_snap1`")
191
+
192
+ def test_restore_with_executor_tenant(self):
193
+ """Test restore tenant with custom executor"""
194
+ # Mock executor
195
+ mock_executor = Mock()
196
+ mock_result = Mock()
197
+ mock_executor.execute = Mock(return_value=mock_result)
198
+
199
+ # Test restore tenant with executor
200
+ result = self.restore_manager.restore_with_executor(
201
+ 'tenant', 'acc1_snap1', account_name='acc1', executor=mock_executor
202
+ )
203
+
204
+ # Verify
205
+ self.assertTrue(result)
206
+ mock_executor.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` FROM SNAPSHOT `acc1_snap1`")
207
+
208
+ def test_restore_with_executor_database(self):
209
+ """Test restore database with custom executor"""
210
+ # Mock executor
211
+ mock_executor = Mock()
212
+ mock_result = Mock()
213
+ mock_executor.execute = Mock(return_value=mock_result)
214
+
215
+ # Test restore database with executor
216
+ result = self.restore_manager.restore_with_executor(
217
+ 'database',
218
+ 'acc1_db_snap1',
219
+ account_name='acc1',
220
+ database_name='db1',
221
+ executor=mock_executor,
222
+ )
223
+
224
+ # Verify
225
+ self.assertTrue(result)
226
+ mock_executor.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` DATABASE `db1` FROM SNAPSHOT `acc1_db_snap1`")
227
+
228
+ def test_restore_with_executor_table(self):
229
+ """Test restore table with custom executor"""
230
+ # Mock executor
231
+ mock_executor = Mock()
232
+ mock_result = Mock()
233
+ mock_executor.execute = Mock(return_value=mock_result)
234
+
235
+ # Test restore table with executor
236
+ result = self.restore_manager.restore_with_executor(
237
+ 'table',
238
+ 'acc1_tab_snap1',
239
+ account_name='acc1',
240
+ database_name='db1',
241
+ table_name='t1',
242
+ executor=mock_executor,
243
+ )
244
+
245
+ # Verify
246
+ self.assertTrue(result)
247
+ mock_executor.execute.assert_called_once_with(
248
+ "RESTORE ACCOUNT `acc1` DATABASE `db1` TABLE `t1` FROM SNAPSHOT `acc1_tab_snap1`"
249
+ )
250
+
251
+ def test_restore_with_executor_invalid_type(self):
252
+ """Test restore with invalid type"""
253
+ # Test invalid restore type
254
+ with self.assertRaises(RestoreErrorClass):
255
+ self.restore_manager.restore_with_executor('invalid', 'snap1')
256
+
257
+ def test_restore_with_executor_missing_params(self):
258
+ """Test restore with missing required parameters"""
259
+ # Test missing account name for tenant restore
260
+ with self.assertRaises(RestoreErrorClass):
261
+ self.restore_manager.restore_with_executor('tenant', 'snap1')
262
+
263
+ # Test missing database name for database restore
264
+ with self.assertRaises(RestoreErrorClass):
265
+ self.restore_manager.restore_with_executor('database', 'snap1', account_name='acc1')
266
+
267
+ # Test missing table name for table restore
268
+ with self.assertRaises(RestoreErrorClass):
269
+ self.restore_manager.restore_with_executor('table', 'snap1', account_name='acc1', database_name='db1')
270
+
271
+
272
+ class TestAsyncRestoreManager(unittest.IsolatedAsyncioTestCase):
273
+ """Test cases for AsyncRestoreManager"""
274
+
275
+ async def asyncSetUp(self):
276
+ """Set up async test fixtures"""
277
+ self.client = AsyncClient()
278
+ self.client._engine = Mock()
279
+ self.client._escape_identifier = lambda x: f"`{x}`"
280
+ # Initialize managers manually for testing
281
+ from matrixone.async_client import AsyncRestoreManager
282
+
283
+ self.restore_manager = AsyncRestoreManager(self.client)
284
+
285
+ async def test_async_restore_cluster_success(self):
286
+ """Test successful async cluster restore"""
287
+ # Mock successful execution
288
+ mock_result = Mock()
289
+ self.client.execute = AsyncMock(return_value=mock_result)
290
+
291
+ # Test restore cluster
292
+ result = await self.restore_manager.restore_cluster("cluster_snapshot_1")
293
+
294
+ # Verify
295
+ self.assertTrue(result)
296
+ self.client.execute.assert_called_once_with("RESTORE CLUSTER FROM SNAPSHOT `cluster_snapshot_1`")
297
+
298
+ async def test_async_restore_cluster_failure(self):
299
+ """Test async cluster restore failure"""
300
+ # Mock execution failure
301
+ self.client.execute = AsyncMock(side_effect=Exception("Connection failed"))
302
+
303
+ # Test restore cluster failure
304
+ with self.assertRaises(RestoreErrorClass):
305
+ await self.restore_manager.restore_cluster("cluster_snapshot_1")
306
+
307
+ async def test_async_restore_tenant_success(self):
308
+ """Test successful async tenant restore"""
309
+ # Mock successful execution
310
+ mock_result = Mock()
311
+ self.client.execute = AsyncMock(return_value=mock_result)
312
+
313
+ # Test restore tenant
314
+ result = await self.restore_manager.restore_tenant("acc1_snap1", "acc1")
315
+
316
+ # Verify
317
+ self.assertTrue(result)
318
+ self.client.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` FROM SNAPSHOT `acc1_snap1`")
319
+
320
+ async def test_async_restore_tenant_to_new_tenant(self):
321
+ """Test async restore tenant to new tenant"""
322
+ # Mock successful execution
323
+ mock_result = Mock()
324
+ self.client.execute = AsyncMock(return_value=mock_result)
325
+
326
+ # Test restore tenant to new tenant
327
+ result = await self.restore_manager.restore_tenant("acc1_snap1", "acc1", "acc2")
328
+
329
+ # Verify
330
+ self.assertTrue(result)
331
+ self.client.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` FROM SNAPSHOT `acc1_snap1` TO ACCOUNT `acc2`")
332
+
333
+ async def test_async_restore_database_success(self):
334
+ """Test successful async database restore"""
335
+ # Mock successful execution
336
+ mock_result = Mock()
337
+ self.client.execute = AsyncMock(return_value=mock_result)
338
+
339
+ # Test restore database
340
+ result = await self.restore_manager.restore_database("acc1_db_snap1", "acc1", "db1")
341
+
342
+ # Verify
343
+ self.assertTrue(result)
344
+ self.client.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` DATABASE `db1` FROM SNAPSHOT `acc1_db_snap1`")
345
+
346
+ async def test_async_restore_table_success(self):
347
+ """Test successful async table restore"""
348
+ # Mock successful execution
349
+ mock_result = Mock()
350
+ self.client.execute = AsyncMock(return_value=mock_result)
351
+
352
+ # Test restore table
353
+ result = await self.restore_manager.restore_table("acc1_tab_snap1", "acc1", "db1", "t1")
354
+
355
+ # Verify
356
+ self.assertTrue(result)
357
+ self.client.execute.assert_called_once_with(
358
+ "RESTORE ACCOUNT `acc1` DATABASE `db1` TABLE `t1` FROM SNAPSHOT `acc1_tab_snap1`"
359
+ )
360
+
361
+
362
+ class TestTransactionRestoreManager(unittest.TestCase):
363
+ """Test cases for TransactionRestoreManager"""
364
+
365
+ def setUp(self):
366
+ """Set up test fixtures"""
367
+ self.client = Client()
368
+ self.client._engine = Mock()
369
+ self.client._escape_identifier = lambda x: f"`{x}`"
370
+ self.transaction_wrapper = Mock()
371
+ self.transaction_restore_manager = TransactionRestoreManager(self.client, self.transaction_wrapper)
372
+
373
+ def test_transaction_restore_cluster(self):
374
+ """Test restore cluster within transaction"""
375
+ # Mock successful execution
376
+ mock_result = Mock()
377
+ self.transaction_wrapper.execute = Mock(return_value=mock_result)
378
+
379
+ # Test restore cluster
380
+ result = self.transaction_restore_manager.restore_cluster("cluster_snap1")
381
+
382
+ # Verify
383
+ self.assertTrue(result)
384
+ self.transaction_wrapper.execute.assert_called_once_with("RESTORE CLUSTER FROM SNAPSHOT `cluster_snap1`")
385
+
386
+ def test_transaction_restore_tenant(self):
387
+ """Test restore tenant within transaction"""
388
+ # Mock successful execution
389
+ mock_result = Mock()
390
+ self.transaction_wrapper.execute = Mock(return_value=mock_result)
391
+
392
+ # Test restore tenant
393
+ result = self.transaction_restore_manager.restore_tenant("acc1_snap1", "acc1")
394
+
395
+ # Verify
396
+ self.assertTrue(result)
397
+ self.transaction_wrapper.execute.assert_called_once_with("RESTORE ACCOUNT `acc1` FROM SNAPSHOT `acc1_snap1`")
398
+
399
+ def test_transaction_restore_database(self):
400
+ """Test restore database within transaction"""
401
+ # Mock successful execution
402
+ mock_result = Mock()
403
+ self.transaction_wrapper.execute = Mock(return_value=mock_result)
404
+
405
+ # Test restore database
406
+ result = self.transaction_restore_manager.restore_database("acc1_db_snap1", "acc1", "db1")
407
+
408
+ # Verify
409
+ self.assertTrue(result)
410
+ self.transaction_wrapper.execute.assert_called_once_with(
411
+ "RESTORE ACCOUNT `acc1` DATABASE `db1` FROM SNAPSHOT `acc1_db_snap1`"
412
+ )
413
+
414
+ def test_transaction_restore_table(self):
415
+ """Test restore table within transaction"""
416
+ # Mock successful execution
417
+ mock_result = Mock()
418
+ self.transaction_wrapper.execute = Mock(return_value=mock_result)
419
+
420
+ # Test restore table
421
+ result = self.transaction_restore_manager.restore_table("acc1_tab_snap1", "acc1", "db1", "t1")
422
+
423
+ # Verify
424
+ self.assertTrue(result)
425
+ self.transaction_wrapper.execute.assert_called_once_with(
426
+ "RESTORE ACCOUNT `acc1` DATABASE `db1` TABLE `t1` FROM SNAPSHOT `acc1_tab_snap1`"
427
+ )
428
+
429
+
430
+ if __name__ == '__main__':
431
+ # Create test suite
432
+ loader = unittest.TestLoader()
433
+ suite = unittest.TestSuite()
434
+
435
+ # Add test cases
436
+ suite.addTests(loader.loadTestsFromTestCase(TestRestoreManager))
437
+ suite.addTests(loader.loadTestsFromTestCase(TestAsyncRestoreManager))
438
+ suite.addTests(loader.loadTestsFromTestCase(TestTransactionRestoreManager))
439
+
440
+ # Run tests
441
+ runner = unittest.TextTestRunner(verbosity=2)
442
+ result = runner.run(suite)
443
+
444
+ # Exit with appropriate code
445
+ sys.exit(0 if result.wasSuccessful() else 1)