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.
- matrixone/__init__.py +155 -0
- matrixone/account.py +723 -0
- matrixone/async_client.py +3913 -0
- matrixone/async_metadata_manager.py +311 -0
- matrixone/async_orm.py +123 -0
- matrixone/async_vector_index_manager.py +633 -0
- matrixone/base_client.py +208 -0
- matrixone/client.py +4672 -0
- matrixone/config.py +452 -0
- matrixone/connection_hooks.py +286 -0
- matrixone/exceptions.py +89 -0
- matrixone/logger.py +782 -0
- matrixone/metadata.py +820 -0
- matrixone/moctl.py +219 -0
- matrixone/orm.py +2277 -0
- matrixone/pitr.py +646 -0
- matrixone/pubsub.py +771 -0
- matrixone/restore.py +411 -0
- matrixone/search_vector_index.py +1176 -0
- matrixone/snapshot.py +550 -0
- matrixone/sql_builder.py +844 -0
- matrixone/sqlalchemy_ext/__init__.py +161 -0
- matrixone/sqlalchemy_ext/adapters.py +163 -0
- matrixone/sqlalchemy_ext/dialect.py +534 -0
- matrixone/sqlalchemy_ext/fulltext_index.py +895 -0
- matrixone/sqlalchemy_ext/fulltext_search.py +1686 -0
- matrixone/sqlalchemy_ext/hnsw_config.py +194 -0
- matrixone/sqlalchemy_ext/ivf_config.py +252 -0
- matrixone/sqlalchemy_ext/table_builder.py +351 -0
- matrixone/sqlalchemy_ext/vector_index.py +1721 -0
- matrixone/sqlalchemy_ext/vector_type.py +948 -0
- matrixone/version.py +580 -0
- matrixone_python_sdk-0.1.0.dist-info/METADATA +706 -0
- matrixone_python_sdk-0.1.0.dist-info/RECORD +122 -0
- matrixone_python_sdk-0.1.0.dist-info/WHEEL +5 -0
- matrixone_python_sdk-0.1.0.dist-info/entry_points.txt +5 -0
- matrixone_python_sdk-0.1.0.dist-info/licenses/LICENSE +200 -0
- matrixone_python_sdk-0.1.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +19 -0
- tests/offline/__init__.py +20 -0
- tests/offline/conftest.py +77 -0
- tests/offline/test_account.py +703 -0
- tests/offline/test_async_client_query_comprehensive.py +1218 -0
- tests/offline/test_basic.py +54 -0
- tests/offline/test_case_sensitivity.py +227 -0
- tests/offline/test_connection_hooks_offline.py +287 -0
- tests/offline/test_dialect_schema_handling.py +609 -0
- tests/offline/test_explain_methods.py +346 -0
- tests/offline/test_filter_logical_in.py +237 -0
- tests/offline/test_fulltext_search_comprehensive.py +795 -0
- tests/offline/test_ivf_config.py +249 -0
- tests/offline/test_join_methods.py +281 -0
- tests/offline/test_join_sqlalchemy_compatibility.py +276 -0
- tests/offline/test_logical_in_method.py +237 -0
- tests/offline/test_matrixone_version_parsing.py +264 -0
- tests/offline/test_metadata_offline.py +557 -0
- tests/offline/test_moctl.py +300 -0
- tests/offline/test_moctl_simple.py +251 -0
- tests/offline/test_model_support_offline.py +359 -0
- tests/offline/test_model_support_simple.py +225 -0
- tests/offline/test_pinecone_filter_offline.py +377 -0
- tests/offline/test_pitr.py +585 -0
- tests/offline/test_pubsub.py +712 -0
- tests/offline/test_query_update.py +283 -0
- tests/offline/test_restore.py +445 -0
- tests/offline/test_snapshot_comprehensive.py +384 -0
- tests/offline/test_sql_escaping_edge_cases.py +551 -0
- tests/offline/test_sqlalchemy_integration.py +382 -0
- tests/offline/test_sqlalchemy_vector_integration.py +434 -0
- tests/offline/test_table_builder.py +198 -0
- tests/offline/test_unified_filter.py +398 -0
- tests/offline/test_unified_transaction.py +495 -0
- tests/offline/test_vector_index.py +238 -0
- tests/offline/test_vector_operations.py +688 -0
- tests/offline/test_vector_type.py +174 -0
- tests/offline/test_version_core.py +328 -0
- tests/offline/test_version_management.py +372 -0
- tests/offline/test_version_standalone.py +652 -0
- tests/online/__init__.py +20 -0
- tests/online/conftest.py +216 -0
- tests/online/test_account_management.py +194 -0
- tests/online/test_advanced_features.py +344 -0
- tests/online/test_async_client_interfaces.py +330 -0
- tests/online/test_async_client_online.py +285 -0
- tests/online/test_async_model_insert_online.py +293 -0
- tests/online/test_async_orm_online.py +300 -0
- tests/online/test_async_simple_query_online.py +802 -0
- tests/online/test_async_transaction_simple_query.py +300 -0
- tests/online/test_basic_connection.py +130 -0
- tests/online/test_client_online.py +238 -0
- tests/online/test_config.py +90 -0
- tests/online/test_config_validation.py +123 -0
- tests/online/test_connection_hooks_new_online.py +217 -0
- tests/online/test_dialect_schema_handling_online.py +331 -0
- tests/online/test_filter_logical_in_online.py +374 -0
- tests/online/test_fulltext_comprehensive.py +1773 -0
- tests/online/test_fulltext_label_online.py +433 -0
- tests/online/test_fulltext_search_online.py +842 -0
- tests/online/test_ivf_stats_online.py +506 -0
- tests/online/test_logger_integration.py +311 -0
- tests/online/test_matrixone_query_orm.py +540 -0
- tests/online/test_metadata_online.py +579 -0
- tests/online/test_model_insert_online.py +255 -0
- tests/online/test_mysql_driver_validation.py +213 -0
- tests/online/test_orm_advanced_features.py +2022 -0
- tests/online/test_orm_cte_integration.py +269 -0
- tests/online/test_orm_online.py +270 -0
- tests/online/test_pinecone_filter.py +708 -0
- tests/online/test_pubsub_operations.py +352 -0
- tests/online/test_query_methods.py +225 -0
- tests/online/test_query_update_online.py +433 -0
- tests/online/test_search_vector_index.py +557 -0
- tests/online/test_simple_fulltext_online.py +915 -0
- tests/online/test_snapshot_comprehensive.py +998 -0
- tests/online/test_sqlalchemy_engine_integration.py +336 -0
- tests/online/test_sqlalchemy_integration.py +425 -0
- tests/online/test_transaction_contexts.py +1219 -0
- tests/online/test_transaction_insert_methods.py +356 -0
- tests/online/test_transaction_query_methods.py +288 -0
- tests/online/test_unified_filter_online.py +529 -0
- tests/online/test_vector_comprehensive.py +706 -0
- tests/online/test_version_management.py +291 -0
@@ -0,0 +1,585 @@
|
|
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 PitrManager
|
17
|
+
"""
|
18
|
+
|
19
|
+
import unittest
|
20
|
+
from unittest.mock import Mock, patch, AsyncMock
|
21
|
+
import sys
|
22
|
+
import os
|
23
|
+
from datetime import datetime
|
24
|
+
|
25
|
+
# Add the matrixone package to the path
|
26
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'matrixone'))
|
27
|
+
|
28
|
+
from matrixone import Client, AsyncClient, PitrError, Pitr
|
29
|
+
from matrixone.exceptions import PitrError as PitrErrorClass
|
30
|
+
from matrixone.pitr import TransactionPitrManager
|
31
|
+
|
32
|
+
|
33
|
+
class TestPitrManager(unittest.TestCase):
|
34
|
+
"""Test cases for PitrManager"""
|
35
|
+
|
36
|
+
def setUp(self):
|
37
|
+
"""Set up test fixtures"""
|
38
|
+
self.client = Client()
|
39
|
+
self.client._engine = Mock()
|
40
|
+
self.client._escape_identifier = lambda x: f"`{x}`"
|
41
|
+
self.client._escape_string = lambda x: f"'{x}'"
|
42
|
+
# Initialize managers manually for testing
|
43
|
+
from matrixone.pitr import PitrManager
|
44
|
+
|
45
|
+
self.pitr_manager = PitrManager(self.client)
|
46
|
+
|
47
|
+
def test_create_cluster_pitr_success(self):
|
48
|
+
"""Test successful cluster PITR creation"""
|
49
|
+
# Mock successful execution
|
50
|
+
mock_result = Mock()
|
51
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd')]
|
52
|
+
self.client.execute = Mock(return_value=mock_result)
|
53
|
+
|
54
|
+
# Test create cluster PITR
|
55
|
+
pitr = self.pitr_manager.create_cluster_pitr("cluster_pitr1", 1, "d")
|
56
|
+
|
57
|
+
# Verify
|
58
|
+
self.assertIsInstance(pitr, Pitr)
|
59
|
+
self.assertEqual(pitr.name, "cluster_pitr1")
|
60
|
+
self.assertEqual(pitr.level, "cluster")
|
61
|
+
self.assertEqual(pitr.range_value, 1)
|
62
|
+
self.assertEqual(pitr.range_unit, "d")
|
63
|
+
# Should be called twice: once for CREATE, once for SHOW
|
64
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
65
|
+
self.client.execute.assert_any_call("CREATE PITR `cluster_pitr1` FOR CLUSTER RANGE 1 'd'")
|
66
|
+
|
67
|
+
def test_create_cluster_pitr_failure(self):
|
68
|
+
"""Test cluster PITR creation failure"""
|
69
|
+
# Mock execution failure
|
70
|
+
self.client.execute = Mock(side_effect=Exception("Permission denied"))
|
71
|
+
|
72
|
+
# Test create cluster PITR failure
|
73
|
+
with self.assertRaises(PitrErrorClass):
|
74
|
+
self.pitr_manager.create_cluster_pitr("cluster_pitr1", 1, "d")
|
75
|
+
|
76
|
+
def test_create_account_pitr_success(self):
|
77
|
+
"""Test successful account PITR creation"""
|
78
|
+
# Mock successful execution
|
79
|
+
mock_result = Mock()
|
80
|
+
mock_result.rows = [('account_pitr1', datetime.now(), datetime.now(), 'account', 'acc1', '*', '*', 2, 'h')]
|
81
|
+
self.client.execute = Mock(return_value=mock_result)
|
82
|
+
|
83
|
+
# Test create account PITR for current account
|
84
|
+
pitr = self.pitr_manager.create_account_pitr("account_pitr1", range_value=2, range_unit="h")
|
85
|
+
|
86
|
+
# Verify
|
87
|
+
self.assertIsInstance(pitr, Pitr)
|
88
|
+
self.assertEqual(pitr.name, "account_pitr1")
|
89
|
+
self.assertEqual(pitr.level, "account")
|
90
|
+
self.assertEqual(pitr.range_value, 2)
|
91
|
+
self.assertEqual(pitr.range_unit, "h")
|
92
|
+
# Should be called twice: once for CREATE, once for SHOW
|
93
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
94
|
+
self.client.execute.assert_any_call("CREATE PITR `account_pitr1` FOR ACCOUNT RANGE 2 'h'")
|
95
|
+
|
96
|
+
def test_create_account_pitr_for_specific_account(self):
|
97
|
+
"""Test create account PITR for specific account"""
|
98
|
+
# Mock successful execution
|
99
|
+
mock_result = Mock()
|
100
|
+
mock_result.rows = [('account_pitr1', datetime.now(), datetime.now(), 'account', 'acc1', '*', '*', 1, 'd')]
|
101
|
+
self.client.execute = Mock(return_value=mock_result)
|
102
|
+
|
103
|
+
# Test create account PITR for specific account
|
104
|
+
pitr = self.pitr_manager.create_account_pitr("account_pitr1", "acc1", 1, "d")
|
105
|
+
|
106
|
+
# Verify
|
107
|
+
self.assertIsInstance(pitr, Pitr)
|
108
|
+
# Should be called twice: once for CREATE, once for SHOW
|
109
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
110
|
+
self.client.execute.assert_any_call("CREATE PITR `account_pitr1` FOR ACCOUNT `acc1` RANGE 1 'd'")
|
111
|
+
|
112
|
+
def test_create_database_pitr_success(self):
|
113
|
+
"""Test successful database PITR creation"""
|
114
|
+
# Mock successful execution
|
115
|
+
mock_result = Mock()
|
116
|
+
mock_result.rows = [('db_pitr1', datetime.now(), datetime.now(), 'database', 'acc1', 'db1', '*', 1, 'y')]
|
117
|
+
self.client.execute = Mock(return_value=mock_result)
|
118
|
+
|
119
|
+
# Test create database PITR
|
120
|
+
pitr = self.pitr_manager.create_database_pitr("db_pitr1", "db1", 1, "y")
|
121
|
+
|
122
|
+
# Verify
|
123
|
+
self.assertIsInstance(pitr, Pitr)
|
124
|
+
self.assertEqual(pitr.name, "db_pitr1")
|
125
|
+
self.assertEqual(pitr.level, "database")
|
126
|
+
self.assertEqual(pitr.database_name, "db1")
|
127
|
+
self.assertEqual(pitr.range_value, 1)
|
128
|
+
self.assertEqual(pitr.range_unit, "y")
|
129
|
+
# Should be called twice: once for CREATE, once for SHOW
|
130
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
131
|
+
self.client.execute.assert_any_call("CREATE PITR `db_pitr1` FOR DATABASE `db1` RANGE 1 'y'")
|
132
|
+
|
133
|
+
def test_create_table_pitr_success(self):
|
134
|
+
"""Test successful table PITR creation"""
|
135
|
+
# Mock successful execution
|
136
|
+
mock_result = Mock()
|
137
|
+
mock_result.rows = [('tab_pitr1', datetime.now(), datetime.now(), 'table', 'acc1', 'db1', 't1', 1, 'y')]
|
138
|
+
self.client.execute = Mock(return_value=mock_result)
|
139
|
+
|
140
|
+
# Test create table PITR
|
141
|
+
pitr = self.pitr_manager.create_table_pitr("tab_pitr1", "db1", "t1", 1, "y")
|
142
|
+
|
143
|
+
# Verify
|
144
|
+
self.assertIsInstance(pitr, Pitr)
|
145
|
+
self.assertEqual(pitr.name, "tab_pitr1")
|
146
|
+
self.assertEqual(pitr.level, "table")
|
147
|
+
self.assertEqual(pitr.database_name, "db1")
|
148
|
+
self.assertEqual(pitr.table_name, "t1")
|
149
|
+
self.assertEqual(pitr.range_value, 1)
|
150
|
+
self.assertEqual(pitr.range_unit, "y")
|
151
|
+
# Should be called twice: once for CREATE, once for SHOW
|
152
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
153
|
+
self.client.execute.assert_any_call("CREATE PITR `tab_pitr1` FOR TABLE `db1` `t1` RANGE 1 'y'")
|
154
|
+
|
155
|
+
def test_get_pitr_success(self):
|
156
|
+
"""Test successful PITR retrieval"""
|
157
|
+
# Mock successful execution
|
158
|
+
mock_result = Mock()
|
159
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd')]
|
160
|
+
self.client.execute = Mock(return_value=mock_result)
|
161
|
+
|
162
|
+
# Test get PITR
|
163
|
+
pitr = self.pitr_manager.get("cluster_pitr1")
|
164
|
+
|
165
|
+
# Verify
|
166
|
+
self.assertIsInstance(pitr, Pitr)
|
167
|
+
self.assertEqual(pitr.name, "cluster_pitr1")
|
168
|
+
self.client.execute.assert_called_with("SHOW PITR WHERE pitr_name = 'cluster_pitr1'")
|
169
|
+
|
170
|
+
def test_get_pitr_not_found(self):
|
171
|
+
"""Test PITR not found"""
|
172
|
+
# Mock empty result
|
173
|
+
mock_result = Mock()
|
174
|
+
mock_result.rows = []
|
175
|
+
self.client.execute = Mock(return_value=mock_result)
|
176
|
+
|
177
|
+
# Test get PITR not found
|
178
|
+
with self.assertRaises(PitrErrorClass):
|
179
|
+
self.pitr_manager.get("nonexistent_pitr")
|
180
|
+
|
181
|
+
def test_list_pitrs_success(self):
|
182
|
+
"""Test successful PITR listing"""
|
183
|
+
# Mock successful execution
|
184
|
+
mock_result = Mock()
|
185
|
+
mock_result.rows = [
|
186
|
+
('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd'),
|
187
|
+
('account_pitr1', datetime.now(), datetime.now(), 'account', 'acc1', '*', '*', 2, 'h'),
|
188
|
+
]
|
189
|
+
self.client.execute = Mock(return_value=mock_result)
|
190
|
+
|
191
|
+
# Test list PITRs
|
192
|
+
pitrs = self.pitr_manager.list()
|
193
|
+
|
194
|
+
# Verify
|
195
|
+
self.assertEqual(len(pitrs), 2)
|
196
|
+
self.assertIsInstance(pitrs[0], Pitr)
|
197
|
+
self.assertIsInstance(pitrs[1], Pitr)
|
198
|
+
self.client.execute.assert_called_with("SHOW PITR")
|
199
|
+
|
200
|
+
def test_list_pitrs_with_filters(self):
|
201
|
+
"""Test PITR listing with filters"""
|
202
|
+
# Mock successful execution
|
203
|
+
mock_result = Mock()
|
204
|
+
mock_result.rows = [('account_pitr1', datetime.now(), datetime.now(), 'account', 'acc1', '*', '*', 2, 'h')]
|
205
|
+
self.client.execute = Mock(return_value=mock_result)
|
206
|
+
|
207
|
+
# Test list PITRs with filters
|
208
|
+
pitrs = self.pitr_manager.list(level="account", account_name="acc1")
|
209
|
+
|
210
|
+
# Verify
|
211
|
+
self.assertEqual(len(pitrs), 1)
|
212
|
+
self.client.execute.assert_called_with("SHOW PITR WHERE pitr_level = 'account' AND account_name = 'acc1'")
|
213
|
+
|
214
|
+
def test_alter_pitr_success(self):
|
215
|
+
"""Test successful PITR alteration"""
|
216
|
+
# Mock successful execution
|
217
|
+
mock_result = Mock()
|
218
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 2, 'h')]
|
219
|
+
self.client.execute = Mock(return_value=mock_result)
|
220
|
+
|
221
|
+
# Test alter PITR
|
222
|
+
pitr = self.pitr_manager.alter("cluster_pitr1", 2, "h")
|
223
|
+
|
224
|
+
# Verify
|
225
|
+
self.assertIsInstance(pitr, Pitr)
|
226
|
+
self.assertEqual(pitr.range_value, 2)
|
227
|
+
self.assertEqual(pitr.range_unit, "h")
|
228
|
+
# Should be called twice: once for ALTER, once for SHOW
|
229
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
230
|
+
self.client.execute.assert_any_call("ALTER PITR `cluster_pitr1` RANGE 2 'h'")
|
231
|
+
|
232
|
+
def test_delete_pitr_success(self):
|
233
|
+
"""Test successful PITR deletion"""
|
234
|
+
# Mock successful execution
|
235
|
+
mock_result = Mock()
|
236
|
+
self.client.execute = Mock(return_value=mock_result)
|
237
|
+
|
238
|
+
# Test delete PITR
|
239
|
+
result = self.pitr_manager.delete("cluster_pitr1")
|
240
|
+
|
241
|
+
# Verify
|
242
|
+
self.assertTrue(result)
|
243
|
+
self.client.execute.assert_called_with("DROP PITR `cluster_pitr1`")
|
244
|
+
|
245
|
+
def test_validate_range_invalid_value(self):
|
246
|
+
"""Test range validation with invalid value"""
|
247
|
+
# Test invalid range value
|
248
|
+
with self.assertRaises(PitrErrorClass):
|
249
|
+
self.pitr_manager.create_cluster_pitr("test", 0, "d")
|
250
|
+
|
251
|
+
with self.assertRaises(PitrErrorClass):
|
252
|
+
self.pitr_manager.create_cluster_pitr("test", 101, "d")
|
253
|
+
|
254
|
+
def test_validate_range_invalid_unit(self):
|
255
|
+
"""Test range validation with invalid unit"""
|
256
|
+
# Test invalid range unit
|
257
|
+
with self.assertRaises(PitrErrorClass):
|
258
|
+
self.pitr_manager.create_cluster_pitr("test", 1, "invalid")
|
259
|
+
|
260
|
+
|
261
|
+
class TestAsyncPitrManager(unittest.IsolatedAsyncioTestCase):
|
262
|
+
"""Test cases for AsyncPitrManager"""
|
263
|
+
|
264
|
+
async def asyncSetUp(self):
|
265
|
+
"""Set up async test fixtures"""
|
266
|
+
self.client = AsyncClient()
|
267
|
+
self.client._engine = Mock()
|
268
|
+
self.client._escape_identifier = lambda x: f"`{x}`"
|
269
|
+
self.client._escape_string = lambda x: f"'{x}'"
|
270
|
+
# Initialize managers manually for testing
|
271
|
+
from matrixone.async_client import AsyncPitrManager
|
272
|
+
|
273
|
+
self.pitr_manager = AsyncPitrManager(self.client)
|
274
|
+
|
275
|
+
async def test_async_create_cluster_pitr_success(self):
|
276
|
+
"""Test successful async cluster PITR creation"""
|
277
|
+
# Mock successful execution
|
278
|
+
mock_result = Mock()
|
279
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd')]
|
280
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
281
|
+
|
282
|
+
# Test create cluster PITR
|
283
|
+
pitr = await self.pitr_manager.create_cluster_pitr("cluster_pitr1", 1, "d")
|
284
|
+
|
285
|
+
# Verify
|
286
|
+
self.assertIsInstance(pitr, Pitr)
|
287
|
+
self.assertEqual(pitr.name, "cluster_pitr1")
|
288
|
+
self.assertEqual(pitr.level, "cluster")
|
289
|
+
self.assertEqual(pitr.range_value, 1)
|
290
|
+
self.assertEqual(pitr.range_unit, "d")
|
291
|
+
# Should be called twice: once for CREATE, once for SHOW
|
292
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
293
|
+
self.client.execute.assert_any_call("CREATE PITR `cluster_pitr1` FOR CLUSTER RANGE 1 'd'")
|
294
|
+
|
295
|
+
async def test_async_create_account_pitr_success(self):
|
296
|
+
"""Test successful async account PITR creation"""
|
297
|
+
# Mock successful execution
|
298
|
+
mock_result = Mock()
|
299
|
+
mock_result.rows = [('account_pitr1', datetime.now(), datetime.now(), 'account', 'acc1', '*', '*', 2, 'h')]
|
300
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
301
|
+
|
302
|
+
# Test create account PITR
|
303
|
+
pitr = await self.pitr_manager.create_account_pitr("account_pitr1", range_value=2, range_unit="h")
|
304
|
+
|
305
|
+
# Verify
|
306
|
+
self.assertIsInstance(pitr, Pitr)
|
307
|
+
self.assertEqual(pitr.name, "account_pitr1")
|
308
|
+
self.assertEqual(pitr.level, "account")
|
309
|
+
self.assertEqual(pitr.range_value, 2)
|
310
|
+
self.assertEqual(pitr.range_unit, "h")
|
311
|
+
# Should be called twice: once for CREATE, once for SHOW
|
312
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
313
|
+
self.client.execute.assert_any_call("CREATE PITR `account_pitr1` FOR ACCOUNT RANGE 2 'h'")
|
314
|
+
|
315
|
+
async def test_async_create_database_pitr_success(self):
|
316
|
+
"""Test successful async database PITR creation"""
|
317
|
+
# Mock successful execution
|
318
|
+
mock_result = Mock()
|
319
|
+
mock_result.rows = [('db_pitr1', datetime.now(), datetime.now(), 'database', 'acc1', 'db1', '*', 1, 'y')]
|
320
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
321
|
+
|
322
|
+
# Test create database PITR
|
323
|
+
pitr = await self.pitr_manager.create_database_pitr("db_pitr1", "db1", 1, "y")
|
324
|
+
|
325
|
+
# Verify
|
326
|
+
self.assertIsInstance(pitr, Pitr)
|
327
|
+
self.assertEqual(pitr.name, "db_pitr1")
|
328
|
+
self.assertEqual(pitr.level, "database")
|
329
|
+
self.assertEqual(pitr.database_name, "db1")
|
330
|
+
self.assertEqual(pitr.range_value, 1)
|
331
|
+
self.assertEqual(pitr.range_unit, "y")
|
332
|
+
# Should be called twice: once for CREATE, once for SHOW
|
333
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
334
|
+
self.client.execute.assert_any_call("CREATE PITR `db_pitr1` FOR DATABASE `db1` RANGE 1 'y'")
|
335
|
+
|
336
|
+
async def test_async_create_table_pitr_success(self):
|
337
|
+
"""Test successful async table PITR creation"""
|
338
|
+
# Mock successful execution
|
339
|
+
mock_result = Mock()
|
340
|
+
mock_result.rows = [('tab_pitr1', datetime.now(), datetime.now(), 'table', 'acc1', 'db1', 't1', 1, 'y')]
|
341
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
342
|
+
|
343
|
+
# Test create table PITR
|
344
|
+
pitr = await self.pitr_manager.create_table_pitr("tab_pitr1", "db1", "t1", 1, "y")
|
345
|
+
|
346
|
+
# Verify
|
347
|
+
self.assertIsInstance(pitr, Pitr)
|
348
|
+
self.assertEqual(pitr.name, "tab_pitr1")
|
349
|
+
self.assertEqual(pitr.level, "table")
|
350
|
+
self.assertEqual(pitr.database_name, "db1")
|
351
|
+
self.assertEqual(pitr.table_name, "t1")
|
352
|
+
self.assertEqual(pitr.range_value, 1)
|
353
|
+
self.assertEqual(pitr.range_unit, "y")
|
354
|
+
# Should be called twice: once for CREATE, once for SHOW
|
355
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
356
|
+
self.client.execute.assert_any_call("CREATE PITR `tab_pitr1` FOR TABLE `db1` `t1` RANGE 1 'y'")
|
357
|
+
|
358
|
+
async def test_async_get_pitr_success(self):
|
359
|
+
"""Test successful async PITR retrieval"""
|
360
|
+
# Mock successful execution
|
361
|
+
mock_result = Mock()
|
362
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd')]
|
363
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
364
|
+
|
365
|
+
# Test get PITR
|
366
|
+
pitr = await self.pitr_manager.get("cluster_pitr1")
|
367
|
+
|
368
|
+
# Verify
|
369
|
+
self.assertIsInstance(pitr, Pitr)
|
370
|
+
self.assertEqual(pitr.name, "cluster_pitr1")
|
371
|
+
self.client.execute.assert_called_with("SHOW PITR WHERE pitr_name = 'cluster_pitr1'")
|
372
|
+
|
373
|
+
async def test_async_list_pitrs_success(self):
|
374
|
+
"""Test successful async PITR listing"""
|
375
|
+
# Mock successful execution
|
376
|
+
mock_result = Mock()
|
377
|
+
mock_result.rows = [
|
378
|
+
('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd'),
|
379
|
+
('account_pitr1', datetime.now(), datetime.now(), 'account', 'acc1', '*', '*', 2, 'h'),
|
380
|
+
]
|
381
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
382
|
+
|
383
|
+
# Test list PITRs
|
384
|
+
pitrs = await self.pitr_manager.list()
|
385
|
+
|
386
|
+
# Verify
|
387
|
+
self.assertEqual(len(pitrs), 2)
|
388
|
+
self.assertIsInstance(pitrs[0], Pitr)
|
389
|
+
self.assertIsInstance(pitrs[1], Pitr)
|
390
|
+
self.client.execute.assert_called_with("SHOW PITR")
|
391
|
+
|
392
|
+
async def test_async_alter_pitr_success(self):
|
393
|
+
"""Test successful async PITR alteration"""
|
394
|
+
# Mock successful execution
|
395
|
+
mock_result = Mock()
|
396
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 2, 'h')]
|
397
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
398
|
+
|
399
|
+
# Test alter PITR
|
400
|
+
pitr = await self.pitr_manager.alter("cluster_pitr1", 2, "h")
|
401
|
+
|
402
|
+
# Verify
|
403
|
+
self.assertIsInstance(pitr, Pitr)
|
404
|
+
self.assertEqual(pitr.range_value, 2)
|
405
|
+
self.assertEqual(pitr.range_unit, "h")
|
406
|
+
# Should be called twice: once for ALTER, once for SHOW
|
407
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
408
|
+
self.client.execute.assert_any_call("ALTER PITR `cluster_pitr1` RANGE 2 'h'")
|
409
|
+
|
410
|
+
async def test_async_delete_pitr_success(self):
|
411
|
+
"""Test successful async PITR deletion"""
|
412
|
+
# Mock successful execution
|
413
|
+
mock_result = Mock()
|
414
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
415
|
+
|
416
|
+
# Test delete PITR
|
417
|
+
result = await self.pitr_manager.delete("cluster_pitr1")
|
418
|
+
|
419
|
+
# Verify
|
420
|
+
self.assertTrue(result)
|
421
|
+
self.client.execute.assert_called_with("DROP PITR `cluster_pitr1`")
|
422
|
+
|
423
|
+
|
424
|
+
class TestTransactionPitrManager(unittest.TestCase):
|
425
|
+
"""Test cases for TransactionPitrManager"""
|
426
|
+
|
427
|
+
def setUp(self):
|
428
|
+
"""Set up test fixtures"""
|
429
|
+
self.client = Client()
|
430
|
+
self.client._engine = Mock()
|
431
|
+
self.client._escape_identifier = lambda x: f"`{x}`"
|
432
|
+
self.client._escape_string = lambda x: f"'{x}'"
|
433
|
+
self.transaction_wrapper = Mock()
|
434
|
+
self.transaction_pitr_manager = TransactionPitrManager(self.client, self.transaction_wrapper)
|
435
|
+
|
436
|
+
def test_transaction_create_cluster_pitr(self):
|
437
|
+
"""Test create cluster PITR within transaction"""
|
438
|
+
# Mock successful execution
|
439
|
+
mock_result = Mock()
|
440
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd')]
|
441
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
442
|
+
|
443
|
+
# Test create cluster PITR
|
444
|
+
pitr = self.transaction_pitr_manager.create_cluster_pitr("cluster_pitr1", 1, "d")
|
445
|
+
|
446
|
+
# Verify
|
447
|
+
self.assertIsInstance(pitr, Pitr)
|
448
|
+
self.assertEqual(pitr.name, "cluster_pitr1")
|
449
|
+
# Should be called twice: once for CREATE, once for SHOW
|
450
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
451
|
+
self.transaction_wrapper.execute.assert_any_call("CREATE PITR `cluster_pitr1` FOR CLUSTER RANGE 1 'd'")
|
452
|
+
|
453
|
+
def test_transaction_create_account_pitr(self):
|
454
|
+
"""Test create account PITR within transaction"""
|
455
|
+
# Mock successful execution
|
456
|
+
mock_result = Mock()
|
457
|
+
mock_result.rows = [('account_pitr1', datetime.now(), datetime.now(), 'account', 'acc1', '*', '*', 2, 'h')]
|
458
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
459
|
+
|
460
|
+
# Test create account PITR
|
461
|
+
pitr = self.transaction_pitr_manager.create_account_pitr("account_pitr1", range_value=2, range_unit="h")
|
462
|
+
|
463
|
+
# Verify
|
464
|
+
self.assertIsInstance(pitr, Pitr)
|
465
|
+
self.assertEqual(pitr.name, "account_pitr1")
|
466
|
+
# Should be called twice: once for CREATE, once for SHOW
|
467
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
468
|
+
self.transaction_wrapper.execute.assert_any_call("CREATE PITR `account_pitr1` FOR ACCOUNT RANGE 2 'h'")
|
469
|
+
|
470
|
+
def test_transaction_create_database_pitr(self):
|
471
|
+
"""Test create database PITR within transaction"""
|
472
|
+
# Mock successful execution
|
473
|
+
mock_result = Mock()
|
474
|
+
mock_result.rows = [('db_pitr1', datetime.now(), datetime.now(), 'database', 'acc1', 'db1', '*', 1, 'y')]
|
475
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
476
|
+
|
477
|
+
# Test create database PITR
|
478
|
+
pitr = self.transaction_pitr_manager.create_database_pitr("db_pitr1", "db1", 1, "y")
|
479
|
+
|
480
|
+
# Verify
|
481
|
+
self.assertIsInstance(pitr, Pitr)
|
482
|
+
self.assertEqual(pitr.name, "db_pitr1")
|
483
|
+
# Should be called twice: once for CREATE, once for SHOW
|
484
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
485
|
+
self.transaction_wrapper.execute.assert_any_call("CREATE PITR `db_pitr1` FOR DATABASE `db1` RANGE 1 'y'")
|
486
|
+
|
487
|
+
def test_transaction_create_table_pitr(self):
|
488
|
+
"""Test create table PITR within transaction"""
|
489
|
+
# Mock successful execution
|
490
|
+
mock_result = Mock()
|
491
|
+
mock_result.rows = [('tab_pitr1', datetime.now(), datetime.now(), 'table', 'acc1', 'db1', 't1', 1, 'y')]
|
492
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
493
|
+
|
494
|
+
# Test create table PITR
|
495
|
+
pitr = self.transaction_pitr_manager.create_table_pitr("tab_pitr1", "db1", "t1", 1, "y")
|
496
|
+
|
497
|
+
# Verify
|
498
|
+
self.assertIsInstance(pitr, Pitr)
|
499
|
+
self.assertEqual(pitr.name, "tab_pitr1")
|
500
|
+
# Should be called twice: once for CREATE, once for SHOW
|
501
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
502
|
+
self.transaction_wrapper.execute.assert_any_call("CREATE PITR `tab_pitr1` FOR TABLE `db1` TABLE `t1` RANGE 1 'y'")
|
503
|
+
|
504
|
+
def test_transaction_get_pitr(self):
|
505
|
+
"""Test get PITR within transaction"""
|
506
|
+
# Mock successful execution
|
507
|
+
mock_result = Mock()
|
508
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd')]
|
509
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
510
|
+
|
511
|
+
# Test get PITR
|
512
|
+
pitr = self.transaction_pitr_manager.get("cluster_pitr1")
|
513
|
+
|
514
|
+
# Verify
|
515
|
+
self.assertIsInstance(pitr, Pitr)
|
516
|
+
self.assertEqual(pitr.name, "cluster_pitr1")
|
517
|
+
self.transaction_wrapper.execute.assert_called_with("SHOW PITR WHERE pitr_name = 'cluster_pitr1'")
|
518
|
+
|
519
|
+
def test_transaction_list_pitrs(self):
|
520
|
+
"""Test list PITRs within transaction"""
|
521
|
+
# Mock successful execution
|
522
|
+
mock_result = Mock()
|
523
|
+
mock_result.rows = [
|
524
|
+
('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 1, 'd'),
|
525
|
+
('account_pitr1', datetime.now(), datetime.now(), 'account', 'acc1', '*', '*', 2, 'h'),
|
526
|
+
]
|
527
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
528
|
+
|
529
|
+
# Test list PITRs
|
530
|
+
pitrs = self.transaction_pitr_manager.list()
|
531
|
+
|
532
|
+
# Verify
|
533
|
+
self.assertEqual(len(pitrs), 2)
|
534
|
+
self.assertIsInstance(pitrs[0], Pitr)
|
535
|
+
self.assertIsInstance(pitrs[1], Pitr)
|
536
|
+
self.transaction_wrapper.execute.assert_called_with("SHOW PITR")
|
537
|
+
|
538
|
+
def test_transaction_alter_pitr(self):
|
539
|
+
"""Test alter PITR within transaction"""
|
540
|
+
# Mock successful execution
|
541
|
+
mock_result = Mock()
|
542
|
+
mock_result.rows = [('cluster_pitr1', datetime.now(), datetime.now(), 'cluster', '*', '*', '*', 2, 'h')]
|
543
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
544
|
+
|
545
|
+
# Test alter PITR
|
546
|
+
pitr = self.transaction_pitr_manager.alter("cluster_pitr1", 2, "h")
|
547
|
+
|
548
|
+
# Verify
|
549
|
+
self.assertIsInstance(pitr, Pitr)
|
550
|
+
self.assertEqual(pitr.range_value, 2)
|
551
|
+
self.assertEqual(pitr.range_unit, "h")
|
552
|
+
# Should be called twice: once for ALTER, once for SHOW
|
553
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
554
|
+
self.transaction_wrapper.execute.assert_any_call("ALTER PITR `cluster_pitr1` RANGE 2 'h'")
|
555
|
+
|
556
|
+
def test_transaction_delete_pitr(self):
|
557
|
+
"""Test delete PITR within transaction"""
|
558
|
+
# Mock successful execution
|
559
|
+
mock_result = Mock()
|
560
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
561
|
+
|
562
|
+
# Test delete PITR
|
563
|
+
result = self.transaction_pitr_manager.delete("cluster_pitr1")
|
564
|
+
|
565
|
+
# Verify
|
566
|
+
self.assertTrue(result)
|
567
|
+
self.transaction_wrapper.execute.assert_called_with("DROP PITR `cluster_pitr1`")
|
568
|
+
|
569
|
+
|
570
|
+
if __name__ == '__main__':
|
571
|
+
# Create test suite
|
572
|
+
loader = unittest.TestLoader()
|
573
|
+
suite = unittest.TestSuite()
|
574
|
+
|
575
|
+
# Add test cases
|
576
|
+
suite.addTests(loader.loadTestsFromTestCase(TestPitrManager))
|
577
|
+
suite.addTests(loader.loadTestsFromTestCase(TestAsyncPitrManager))
|
578
|
+
suite.addTests(loader.loadTestsFromTestCase(TestTransactionPitrManager))
|
579
|
+
|
580
|
+
# Run tests
|
581
|
+
runner = unittest.TextTestRunner(verbosity=2)
|
582
|
+
result = runner.run(suite)
|
583
|
+
|
584
|
+
# Exit with appropriate code
|
585
|
+
sys.exit(0 if result.wasSuccessful() else 1)
|