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,712 @@
|
|
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 PubSubManager
|
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, PubSubError, Publication, Subscription
|
29
|
+
from matrixone.exceptions import PubSubError as PubSubErrorClass
|
30
|
+
from matrixone.pubsub import TransactionPubSubManager
|
31
|
+
|
32
|
+
|
33
|
+
class TestPubSubManager(unittest.TestCase):
|
34
|
+
"""Test cases for PubSubManager"""
|
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.pubsub import PubSubManager
|
44
|
+
|
45
|
+
self.pubsub_manager = PubSubManager(self.client)
|
46
|
+
|
47
|
+
def test_create_database_publication_success(self):
|
48
|
+
"""Test successful database publication creation"""
|
49
|
+
# Mock successful execution
|
50
|
+
mock_result = Mock()
|
51
|
+
mock_result.rows = [('db_pub1', 'central_db', '*', 'acc1', '', datetime.now(), None, None)]
|
52
|
+
self.client.execute = Mock(return_value=mock_result)
|
53
|
+
|
54
|
+
# Test create database publication
|
55
|
+
pub = self.pubsub_manager.create_database_publication("db_pub1", "central_db", "acc1")
|
56
|
+
|
57
|
+
# Verify
|
58
|
+
self.assertIsInstance(pub, Publication)
|
59
|
+
self.assertEqual(pub.name, "db_pub1")
|
60
|
+
self.assertEqual(pub.database, "central_db")
|
61
|
+
self.assertEqual(pub.tables, "*")
|
62
|
+
self.assertEqual(pub.sub_account, "acc1")
|
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 PUBLICATION `db_pub1` DATABASE `central_db` ACCOUNT `acc1`")
|
66
|
+
|
67
|
+
def test_create_table_publication_success(self):
|
68
|
+
"""Test successful table publication creation"""
|
69
|
+
# Mock successful execution
|
70
|
+
mock_result = Mock()
|
71
|
+
mock_result.rows = [('table_pub1', 'central_db', 'products', 'acc1', '', datetime.now(), None, None)]
|
72
|
+
self.client.execute = Mock(return_value=mock_result)
|
73
|
+
|
74
|
+
# Test create table publication
|
75
|
+
pub = self.pubsub_manager.create_table_publication("table_pub1", "central_db", "products", "acc1")
|
76
|
+
|
77
|
+
# Verify
|
78
|
+
self.assertIsInstance(pub, Publication)
|
79
|
+
self.assertEqual(pub.name, "table_pub1")
|
80
|
+
self.assertEqual(pub.database, "central_db")
|
81
|
+
self.assertEqual(pub.tables, "products")
|
82
|
+
self.assertEqual(pub.sub_account, "acc1")
|
83
|
+
# Should be called twice: once for CREATE, once for SHOW
|
84
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
85
|
+
self.client.execute.assert_any_call(
|
86
|
+
"CREATE PUBLICATION `table_pub1` DATABASE `central_db` TABLE `products` ACCOUNT `acc1`"
|
87
|
+
)
|
88
|
+
|
89
|
+
def test_get_publication_success(self):
|
90
|
+
"""Test successful publication retrieval"""
|
91
|
+
# Mock successful execution
|
92
|
+
mock_result = Mock()
|
93
|
+
mock_result.rows = [('db_pub1', 'central_db', '*', 'acc1', '', datetime.now(), None, None)]
|
94
|
+
self.client.execute = Mock(return_value=mock_result)
|
95
|
+
|
96
|
+
# Test get publication
|
97
|
+
pub = self.pubsub_manager.get_publication("db_pub1")
|
98
|
+
|
99
|
+
# Verify
|
100
|
+
self.assertIsInstance(pub, Publication)
|
101
|
+
self.assertEqual(pub.name, "db_pub1")
|
102
|
+
self.client.execute.assert_called_with("SHOW PUBLICATIONS")
|
103
|
+
|
104
|
+
def test_get_publication_not_found(self):
|
105
|
+
"""Test publication not found"""
|
106
|
+
# Mock empty result
|
107
|
+
mock_result = Mock()
|
108
|
+
mock_result.rows = []
|
109
|
+
self.client.execute = Mock(return_value=mock_result)
|
110
|
+
|
111
|
+
# Test get publication not found
|
112
|
+
with self.assertRaises(PubSubErrorClass):
|
113
|
+
self.pubsub_manager.get_publication("nonexistent_pub")
|
114
|
+
|
115
|
+
def test_list_publications_success(self):
|
116
|
+
"""Test successful publication listing"""
|
117
|
+
# Mock successful execution
|
118
|
+
mock_result = Mock()
|
119
|
+
mock_result.rows = [
|
120
|
+
('db_pub1', 'central_db', '*', 'acc1', '', datetime.now(), None, None),
|
121
|
+
('table_pub1', 'central_db', 'products', 'acc1', '', datetime.now(), None, None),
|
122
|
+
]
|
123
|
+
self.client.execute = Mock(return_value=mock_result)
|
124
|
+
|
125
|
+
# Test list publications
|
126
|
+
pubs = self.pubsub_manager.list_publications()
|
127
|
+
|
128
|
+
# Verify
|
129
|
+
self.assertEqual(len(pubs), 2)
|
130
|
+
self.assertIsInstance(pubs[0], Publication)
|
131
|
+
self.assertIsInstance(pubs[1], Publication)
|
132
|
+
self.client.execute.assert_called_with("SHOW PUBLICATIONS")
|
133
|
+
|
134
|
+
def test_list_publications_with_filters(self):
|
135
|
+
"""Test publication listing with filters"""
|
136
|
+
# Mock successful execution
|
137
|
+
mock_result = Mock()
|
138
|
+
mock_result.rows = [('db_pub1', 'central_db', '*', 'acc1', '', datetime.now(), None, None)]
|
139
|
+
self.client.execute = Mock(return_value=mock_result)
|
140
|
+
|
141
|
+
# Test list publications with filters
|
142
|
+
pubs = self.pubsub_manager.list_publications(account="acc1", database="central_db")
|
143
|
+
|
144
|
+
# Verify
|
145
|
+
self.assertEqual(len(pubs), 1)
|
146
|
+
self.client.execute.assert_called_with("SHOW PUBLICATIONS")
|
147
|
+
|
148
|
+
def test_alter_publication_success(self):
|
149
|
+
"""Test successful publication alteration"""
|
150
|
+
# Mock successful execution
|
151
|
+
mock_result = Mock()
|
152
|
+
mock_result.rows = [('db_pub1', 'sys', 'central_db', '*', None, datetime.now())]
|
153
|
+
self.client.execute = Mock(return_value=mock_result)
|
154
|
+
|
155
|
+
# Test alter publication
|
156
|
+
pub = self.pubsub_manager.alter_publication("db_pub1", account="acc2")
|
157
|
+
|
158
|
+
# Verify
|
159
|
+
self.assertIsInstance(pub, Publication)
|
160
|
+
# Should be called twice: once for ALTER, once for SHOW
|
161
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
162
|
+
self.client.execute.assert_any_call("ALTER PUBLICATION `db_pub1` ACCOUNT `acc2`")
|
163
|
+
|
164
|
+
def test_drop_publication_success(self):
|
165
|
+
"""Test successful publication deletion"""
|
166
|
+
# Mock successful execution
|
167
|
+
mock_result = Mock()
|
168
|
+
self.client.execute = Mock(return_value=mock_result)
|
169
|
+
|
170
|
+
# Test drop publication
|
171
|
+
result = self.pubsub_manager.drop_publication("db_pub1")
|
172
|
+
|
173
|
+
# Verify
|
174
|
+
self.assertTrue(result)
|
175
|
+
self.client.execute.assert_called_with("DROP PUBLICATION `db_pub1`")
|
176
|
+
|
177
|
+
def test_create_subscription_success(self):
|
178
|
+
"""Test successful subscription creation"""
|
179
|
+
# Mock successful execution
|
180
|
+
mock_result = Mock()
|
181
|
+
mock_result.rows = [
|
182
|
+
(
|
183
|
+
'db_pub1',
|
184
|
+
'sys',
|
185
|
+
'central_db',
|
186
|
+
'*',
|
187
|
+
None,
|
188
|
+
datetime.now(),
|
189
|
+
'sub_db1',
|
190
|
+
datetime.now(),
|
191
|
+
0,
|
192
|
+
)
|
193
|
+
]
|
194
|
+
self.client.execute = Mock(return_value=mock_result)
|
195
|
+
|
196
|
+
# Test create subscription
|
197
|
+
sub = self.pubsub_manager.create_subscription("sub_db1", "db_pub1", "sys")
|
198
|
+
|
199
|
+
# Verify
|
200
|
+
self.assertIsInstance(sub, Subscription)
|
201
|
+
self.assertEqual(sub.sub_name, "sub_db1")
|
202
|
+
self.assertEqual(sub.pub_name, "db_pub1")
|
203
|
+
# Should be called twice: once for CREATE, once for SHOW
|
204
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
205
|
+
self.client.execute.assert_any_call("CREATE DATABASE `sub_db1` FROM `sys` PUBLICATION `db_pub1`")
|
206
|
+
|
207
|
+
def test_get_subscription_success(self):
|
208
|
+
"""Test successful subscription retrieval"""
|
209
|
+
# Mock successful execution
|
210
|
+
mock_result = Mock()
|
211
|
+
mock_result.rows = [
|
212
|
+
(
|
213
|
+
'db_pub1',
|
214
|
+
'sys',
|
215
|
+
'central_db',
|
216
|
+
'*',
|
217
|
+
None,
|
218
|
+
datetime.now(),
|
219
|
+
'sub_db1',
|
220
|
+
datetime.now(),
|
221
|
+
0,
|
222
|
+
)
|
223
|
+
]
|
224
|
+
self.client.execute = Mock(return_value=mock_result)
|
225
|
+
|
226
|
+
# Test get subscription
|
227
|
+
sub = self.pubsub_manager.get_subscription("sub_db1")
|
228
|
+
|
229
|
+
# Verify
|
230
|
+
self.assertIsInstance(sub, Subscription)
|
231
|
+
self.assertEqual(sub.sub_name, "sub_db1")
|
232
|
+
self.client.execute.assert_called_with("SHOW SUBSCRIPTIONS")
|
233
|
+
|
234
|
+
def test_list_subscriptions_success(self):
|
235
|
+
"""Test successful subscription listing"""
|
236
|
+
# Mock successful execution
|
237
|
+
mock_result = Mock()
|
238
|
+
mock_result.rows = [
|
239
|
+
(
|
240
|
+
'db_pub1',
|
241
|
+
'sys',
|
242
|
+
'central_db',
|
243
|
+
'*',
|
244
|
+
None,
|
245
|
+
datetime.now(),
|
246
|
+
'sub_db1',
|
247
|
+
datetime.now(),
|
248
|
+
0,
|
249
|
+
),
|
250
|
+
(
|
251
|
+
'table_pub1',
|
252
|
+
'sys',
|
253
|
+
'central_db',
|
254
|
+
'products',
|
255
|
+
None,
|
256
|
+
datetime.now(),
|
257
|
+
'sub_table1',
|
258
|
+
datetime.now(),
|
259
|
+
0,
|
260
|
+
),
|
261
|
+
]
|
262
|
+
self.client.execute = Mock(return_value=mock_result)
|
263
|
+
|
264
|
+
# Test list subscriptions
|
265
|
+
subs = self.pubsub_manager.list_subscriptions()
|
266
|
+
|
267
|
+
# Verify
|
268
|
+
self.assertEqual(len(subs), 2)
|
269
|
+
self.assertIsInstance(subs[0], Subscription)
|
270
|
+
self.assertIsInstance(subs[1], Subscription)
|
271
|
+
self.client.execute.assert_called_with("SHOW SUBSCRIPTIONS")
|
272
|
+
|
273
|
+
|
274
|
+
class TestAsyncPubSubManager(unittest.IsolatedAsyncioTestCase):
|
275
|
+
"""Test cases for AsyncPubSubManager"""
|
276
|
+
|
277
|
+
async def asyncSetUp(self):
|
278
|
+
"""Set up async test fixtures"""
|
279
|
+
self.client = AsyncClient()
|
280
|
+
self.client._engine = Mock()
|
281
|
+
self.client._escape_identifier = lambda x: f"`{x}`"
|
282
|
+
self.client._escape_string = lambda x: f"'{x}'"
|
283
|
+
# Initialize managers manually for testing
|
284
|
+
from matrixone.async_client import AsyncPubSubManager
|
285
|
+
|
286
|
+
self.pubsub_manager = AsyncPubSubManager(self.client)
|
287
|
+
|
288
|
+
async def test_async_create_database_publication_success(self):
|
289
|
+
"""Test successful async database publication creation"""
|
290
|
+
# Mock successful execution
|
291
|
+
mock_result = Mock()
|
292
|
+
mock_result.rows = [('db_pub1', 'central_db', '*', 'acc1', '', datetime.now(), None, None)]
|
293
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
294
|
+
|
295
|
+
# Test create database publication
|
296
|
+
pub = await self.pubsub_manager.create_database_publication("db_pub1", "central_db", "acc1")
|
297
|
+
|
298
|
+
# Verify
|
299
|
+
self.assertIsInstance(pub, Publication)
|
300
|
+
self.assertEqual(pub.name, "db_pub1")
|
301
|
+
self.assertEqual(pub.database, "central_db")
|
302
|
+
self.assertEqual(pub.tables, "*")
|
303
|
+
self.assertEqual(pub.sub_account, "acc1")
|
304
|
+
# Should be called twice: once for CREATE, once for SHOW
|
305
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
306
|
+
self.client.execute.assert_any_call("CREATE PUBLICATION `db_pub1` DATABASE `central_db` ACCOUNT `acc1`")
|
307
|
+
|
308
|
+
async def test_async_create_table_publication_success(self):
|
309
|
+
"""Test successful async table publication creation"""
|
310
|
+
# Mock successful execution
|
311
|
+
mock_result = Mock()
|
312
|
+
mock_result.rows = [('table_pub1', 'central_db', 'products', 'acc1', '', datetime.now(), None, None)]
|
313
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
314
|
+
|
315
|
+
# Test create table publication
|
316
|
+
pub = await self.pubsub_manager.create_table_publication("table_pub1", "central_db", "products", "acc1")
|
317
|
+
|
318
|
+
# Verify
|
319
|
+
self.assertIsInstance(pub, Publication)
|
320
|
+
self.assertEqual(pub.name, "table_pub1")
|
321
|
+
self.assertEqual(pub.database, "central_db")
|
322
|
+
self.assertEqual(pub.tables, "products")
|
323
|
+
self.assertEqual(pub.sub_account, "acc1")
|
324
|
+
# Should be called twice: once for CREATE, once for SHOW
|
325
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
326
|
+
self.client.execute.assert_any_call(
|
327
|
+
"CREATE PUBLICATION `table_pub1` DATABASE `central_db` TABLE `products` ACCOUNT `acc1`"
|
328
|
+
)
|
329
|
+
|
330
|
+
async def test_async_get_publication_success(self):
|
331
|
+
"""Test successful async publication retrieval"""
|
332
|
+
# Mock successful execution
|
333
|
+
mock_result = Mock()
|
334
|
+
mock_result.rows = [('db_pub1', 'central_db', '*', 'acc1', '', datetime.now(), None, None)]
|
335
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
336
|
+
|
337
|
+
# Test get publication
|
338
|
+
pub = await self.pubsub_manager.get_publication("db_pub1")
|
339
|
+
|
340
|
+
# Verify
|
341
|
+
self.assertIsInstance(pub, Publication)
|
342
|
+
self.assertEqual(pub.name, "db_pub1")
|
343
|
+
self.client.execute.assert_called_with("SHOW PUBLICATIONS")
|
344
|
+
|
345
|
+
async def test_async_list_publications_success(self):
|
346
|
+
"""Test successful async publication listing"""
|
347
|
+
# Mock successful execution
|
348
|
+
mock_result = Mock()
|
349
|
+
mock_result.rows = [
|
350
|
+
('db_pub1', 'sys', 'central_db', '*', None, datetime.now()),
|
351
|
+
('table_pub1', 'sys', 'central_db', 'products', None, datetime.now()),
|
352
|
+
]
|
353
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
354
|
+
|
355
|
+
# Test list publications
|
356
|
+
pubs = await self.pubsub_manager.list_publications()
|
357
|
+
|
358
|
+
# Verify
|
359
|
+
self.assertEqual(len(pubs), 2)
|
360
|
+
self.assertIsInstance(pubs[0], Publication)
|
361
|
+
self.assertIsInstance(pubs[1], Publication)
|
362
|
+
self.client.execute.assert_called_with("SHOW PUBLICATIONS")
|
363
|
+
|
364
|
+
async def test_async_alter_publication_success(self):
|
365
|
+
"""Test successful async publication alteration"""
|
366
|
+
# Mock successful execution
|
367
|
+
mock_result = Mock()
|
368
|
+
mock_result.rows = [('db_pub1', 'sys', 'central_db', '*', None, datetime.now())]
|
369
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
370
|
+
|
371
|
+
# Test alter publication
|
372
|
+
pub = await self.pubsub_manager.alter_publication("db_pub1", account="acc2")
|
373
|
+
|
374
|
+
# Verify
|
375
|
+
self.assertIsInstance(pub, Publication)
|
376
|
+
# Should be called twice: once for ALTER, once for SHOW
|
377
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
378
|
+
self.client.execute.assert_any_call("ALTER PUBLICATION `db_pub1` ACCOUNT `acc2`")
|
379
|
+
|
380
|
+
async def test_async_drop_publication_success(self):
|
381
|
+
"""Test successful async publication deletion"""
|
382
|
+
# Mock successful execution
|
383
|
+
mock_result = Mock()
|
384
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
385
|
+
|
386
|
+
# Test drop publication
|
387
|
+
result = await self.pubsub_manager.drop_publication("db_pub1")
|
388
|
+
|
389
|
+
# Verify
|
390
|
+
self.assertTrue(result)
|
391
|
+
self.client.execute.assert_called_with("DROP PUBLICATION `db_pub1`")
|
392
|
+
|
393
|
+
async def test_async_create_subscription_success(self):
|
394
|
+
"""Test successful async subscription creation"""
|
395
|
+
# Mock successful execution
|
396
|
+
mock_result = Mock()
|
397
|
+
mock_result.rows = [
|
398
|
+
(
|
399
|
+
'db_pub1',
|
400
|
+
'sys',
|
401
|
+
'central_db',
|
402
|
+
'*',
|
403
|
+
None,
|
404
|
+
datetime.now(),
|
405
|
+
'sub_db1',
|
406
|
+
datetime.now(),
|
407
|
+
0,
|
408
|
+
)
|
409
|
+
]
|
410
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
411
|
+
|
412
|
+
# Test create subscription
|
413
|
+
sub = await self.pubsub_manager.create_subscription("sub_db1", "db_pub1", "sys")
|
414
|
+
|
415
|
+
# Verify
|
416
|
+
self.assertIsInstance(sub, Subscription)
|
417
|
+
self.assertEqual(sub.sub_name, "sub_db1")
|
418
|
+
self.assertEqual(sub.pub_name, "db_pub1")
|
419
|
+
# Should be called twice: once for CREATE, once for SHOW
|
420
|
+
self.assertEqual(self.client.execute.call_count, 2)
|
421
|
+
self.client.execute.assert_any_call("CREATE DATABASE `sub_db1` FROM `sys` PUBLICATION `db_pub1`")
|
422
|
+
|
423
|
+
async def test_async_get_subscription_success(self):
|
424
|
+
"""Test successful async subscription retrieval"""
|
425
|
+
# Mock successful execution
|
426
|
+
mock_result = Mock()
|
427
|
+
mock_result.rows = [
|
428
|
+
(
|
429
|
+
'db_pub1',
|
430
|
+
'sys',
|
431
|
+
'central_db',
|
432
|
+
'*',
|
433
|
+
None,
|
434
|
+
datetime.now(),
|
435
|
+
'sub_db1',
|
436
|
+
datetime.now(),
|
437
|
+
0,
|
438
|
+
)
|
439
|
+
]
|
440
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
441
|
+
|
442
|
+
# Test get subscription
|
443
|
+
sub = await self.pubsub_manager.get_subscription("sub_db1")
|
444
|
+
|
445
|
+
# Verify
|
446
|
+
self.assertIsInstance(sub, Subscription)
|
447
|
+
self.assertEqual(sub.sub_name, "sub_db1")
|
448
|
+
self.client.execute.assert_called_with("SHOW SUBSCRIPTIONS")
|
449
|
+
|
450
|
+
async def test_async_list_subscriptions_success(self):
|
451
|
+
"""Test successful async subscription listing"""
|
452
|
+
# Mock successful execution
|
453
|
+
mock_result = Mock()
|
454
|
+
mock_result.rows = [
|
455
|
+
(
|
456
|
+
'db_pub1',
|
457
|
+
'sys',
|
458
|
+
'central_db',
|
459
|
+
'*',
|
460
|
+
None,
|
461
|
+
datetime.now(),
|
462
|
+
'sub_db1',
|
463
|
+
datetime.now(),
|
464
|
+
0,
|
465
|
+
),
|
466
|
+
(
|
467
|
+
'table_pub1',
|
468
|
+
'sys',
|
469
|
+
'central_db',
|
470
|
+
'products',
|
471
|
+
None,
|
472
|
+
datetime.now(),
|
473
|
+
'sub_table1',
|
474
|
+
datetime.now(),
|
475
|
+
0,
|
476
|
+
),
|
477
|
+
]
|
478
|
+
self.client.execute = AsyncMock(return_value=mock_result)
|
479
|
+
|
480
|
+
# Test list subscriptions
|
481
|
+
subs = await self.pubsub_manager.list_subscriptions()
|
482
|
+
|
483
|
+
# Verify
|
484
|
+
self.assertEqual(len(subs), 2)
|
485
|
+
self.assertIsInstance(subs[0], Subscription)
|
486
|
+
self.assertIsInstance(subs[1], Subscription)
|
487
|
+
self.client.execute.assert_called_with("SHOW SUBSCRIPTIONS")
|
488
|
+
|
489
|
+
|
490
|
+
class TestTransactionPubSubManager(unittest.TestCase):
|
491
|
+
"""Test cases for TransactionPubSubManager"""
|
492
|
+
|
493
|
+
def setUp(self):
|
494
|
+
"""Set up test fixtures"""
|
495
|
+
self.client = Client()
|
496
|
+
self.client._engine = Mock()
|
497
|
+
self.client._escape_identifier = lambda x: f"`{x}`"
|
498
|
+
self.client._escape_string = lambda x: f"'{x}'"
|
499
|
+
self.transaction_wrapper = Mock()
|
500
|
+
self.transaction_pubsub_manager = TransactionPubSubManager(self.client, self.transaction_wrapper)
|
501
|
+
|
502
|
+
def test_transaction_create_database_publication(self):
|
503
|
+
"""Test create database publication within transaction"""
|
504
|
+
# Mock successful execution
|
505
|
+
mock_result = Mock()
|
506
|
+
mock_result.rows = [('db_pub1', 'sys', 'central_db', '*', None, datetime.now())]
|
507
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
508
|
+
|
509
|
+
# Test create database publication
|
510
|
+
pub = self.transaction_pubsub_manager.create_database_publication("db_pub1", "central_db", "acc1")
|
511
|
+
|
512
|
+
# Verify
|
513
|
+
self.assertIsInstance(pub, Publication)
|
514
|
+
self.assertEqual(pub.name, "db_pub1")
|
515
|
+
# Should be called twice: once for CREATE, once for SHOW
|
516
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
517
|
+
self.transaction_wrapper.execute.assert_any_call("CREATE PUBLICATION `db_pub1` DATABASE `central_db` ACCOUNT `acc1`")
|
518
|
+
|
519
|
+
def test_transaction_create_table_publication(self):
|
520
|
+
"""Test create table publication within transaction"""
|
521
|
+
# Mock successful execution
|
522
|
+
mock_result = Mock()
|
523
|
+
mock_result.rows = [('table_pub1', 'sys', 'central_db', 'products', None, datetime.now())]
|
524
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
525
|
+
|
526
|
+
# Test create table publication
|
527
|
+
pub = self.transaction_pubsub_manager.create_table_publication("table_pub1", "central_db", "products", "acc1")
|
528
|
+
|
529
|
+
# Verify
|
530
|
+
self.assertIsInstance(pub, Publication)
|
531
|
+
self.assertEqual(pub.name, "table_pub1")
|
532
|
+
# Should be called twice: once for CREATE, once for SHOW
|
533
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
534
|
+
self.transaction_wrapper.execute.assert_any_call(
|
535
|
+
"CREATE PUBLICATION `table_pub1` DATABASE `central_db` TABLE `products` ACCOUNT `acc1`"
|
536
|
+
)
|
537
|
+
|
538
|
+
def test_transaction_get_publication(self):
|
539
|
+
"""Test get publication within transaction"""
|
540
|
+
# Mock successful execution
|
541
|
+
mock_result = Mock()
|
542
|
+
mock_result.rows = [('db_pub1', 'sys', 'central_db', '*', None, datetime.now())]
|
543
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
544
|
+
|
545
|
+
# Test get publication
|
546
|
+
pub = self.transaction_pubsub_manager.get_publication("db_pub1")
|
547
|
+
|
548
|
+
# Verify
|
549
|
+
self.assertIsInstance(pub, Publication)
|
550
|
+
self.assertEqual(pub.name, "db_pub1")
|
551
|
+
self.transaction_wrapper.execute.assert_called_with("SHOW PUBLICATIONS WHERE pub_name = 'db_pub1'")
|
552
|
+
|
553
|
+
def test_transaction_list_publications(self):
|
554
|
+
"""Test list publications within transaction"""
|
555
|
+
# Mock successful execution
|
556
|
+
mock_result = Mock()
|
557
|
+
mock_result.rows = [
|
558
|
+
('db_pub1', 'sys', 'central_db', '*', None, datetime.now()),
|
559
|
+
('table_pub1', 'sys', 'central_db', 'products', None, datetime.now()),
|
560
|
+
]
|
561
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
562
|
+
|
563
|
+
# Test list publications
|
564
|
+
pubs = self.transaction_pubsub_manager.list_publications()
|
565
|
+
|
566
|
+
# Verify
|
567
|
+
self.assertEqual(len(pubs), 2)
|
568
|
+
self.assertIsInstance(pubs[0], Publication)
|
569
|
+
self.assertIsInstance(pubs[1], Publication)
|
570
|
+
self.transaction_wrapper.execute.assert_called_with("SHOW PUBLICATIONS")
|
571
|
+
|
572
|
+
def test_transaction_alter_publication(self):
|
573
|
+
"""Test alter publication within transaction"""
|
574
|
+
# Mock successful execution
|
575
|
+
mock_result = Mock()
|
576
|
+
mock_result.rows = [('db_pub1', 'sys', 'central_db', '*', None, datetime.now())]
|
577
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
578
|
+
|
579
|
+
# Test alter publication
|
580
|
+
pub = self.transaction_pubsub_manager.alter_publication("db_pub1", account="acc2")
|
581
|
+
|
582
|
+
# Verify
|
583
|
+
self.assertIsInstance(pub, Publication)
|
584
|
+
# Should be called twice: once for ALTER, once for SHOW
|
585
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
586
|
+
self.transaction_wrapper.execute.assert_any_call("ALTER PUBLICATION `db_pub1` ACCOUNT `acc2`")
|
587
|
+
|
588
|
+
def test_transaction_drop_publication(self):
|
589
|
+
"""Test drop publication within transaction"""
|
590
|
+
# Mock successful execution
|
591
|
+
mock_result = Mock()
|
592
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
593
|
+
|
594
|
+
# Test drop publication
|
595
|
+
result = self.transaction_pubsub_manager.drop_publication("db_pub1")
|
596
|
+
|
597
|
+
# Verify
|
598
|
+
self.assertTrue(result)
|
599
|
+
self.transaction_wrapper.execute.assert_called_with("DROP PUBLICATION `db_pub1`")
|
600
|
+
|
601
|
+
def test_transaction_create_subscription(self):
|
602
|
+
"""Test create subscription within transaction"""
|
603
|
+
# Mock successful execution
|
604
|
+
mock_result = Mock()
|
605
|
+
mock_result.rows = [
|
606
|
+
(
|
607
|
+
'db_pub1',
|
608
|
+
'sys',
|
609
|
+
'central_db',
|
610
|
+
'*',
|
611
|
+
None,
|
612
|
+
datetime.now(),
|
613
|
+
'sub_db1',
|
614
|
+
datetime.now(),
|
615
|
+
0,
|
616
|
+
)
|
617
|
+
]
|
618
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
619
|
+
|
620
|
+
# Test create subscription
|
621
|
+
sub = self.transaction_pubsub_manager.create_subscription("sub_db1", "db_pub1", "sys")
|
622
|
+
|
623
|
+
# Verify
|
624
|
+
self.assertIsInstance(sub, Subscription)
|
625
|
+
self.assertEqual(sub.sub_name, "sub_db1")
|
626
|
+
# Should be called twice: once for CREATE, once for SHOW
|
627
|
+
self.assertEqual(self.transaction_wrapper.execute.call_count, 2)
|
628
|
+
self.transaction_wrapper.execute.assert_any_call("CREATE DATABASE `sub_db1` FROM `sys` PUBLICATION `db_pub1`")
|
629
|
+
|
630
|
+
def test_transaction_get_subscription(self):
|
631
|
+
"""Test get subscription within transaction"""
|
632
|
+
# Mock successful execution
|
633
|
+
mock_result = Mock()
|
634
|
+
mock_result.rows = [
|
635
|
+
(
|
636
|
+
'db_pub1',
|
637
|
+
'sys',
|
638
|
+
'central_db',
|
639
|
+
'*',
|
640
|
+
None,
|
641
|
+
datetime.now(),
|
642
|
+
'sub_db1',
|
643
|
+
datetime.now(),
|
644
|
+
0,
|
645
|
+
)
|
646
|
+
]
|
647
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
648
|
+
|
649
|
+
# Test get subscription
|
650
|
+
sub = self.transaction_pubsub_manager.get_subscription("sub_db1")
|
651
|
+
|
652
|
+
# Verify
|
653
|
+
self.assertIsInstance(sub, Subscription)
|
654
|
+
self.assertEqual(sub.sub_name, "sub_db1")
|
655
|
+
self.transaction_wrapper.execute.assert_called_with("SHOW SUBSCRIPTIONS")
|
656
|
+
|
657
|
+
def test_transaction_list_subscriptions(self):
|
658
|
+
"""Test list subscriptions within transaction"""
|
659
|
+
# Mock successful execution
|
660
|
+
mock_result = Mock()
|
661
|
+
mock_result.rows = [
|
662
|
+
(
|
663
|
+
'db_pub1',
|
664
|
+
'sys',
|
665
|
+
'central_db',
|
666
|
+
'*',
|
667
|
+
None,
|
668
|
+
datetime.now(),
|
669
|
+
'sub_db1',
|
670
|
+
datetime.now(),
|
671
|
+
0,
|
672
|
+
),
|
673
|
+
(
|
674
|
+
'table_pub1',
|
675
|
+
'sys',
|
676
|
+
'central_db',
|
677
|
+
'products',
|
678
|
+
None,
|
679
|
+
datetime.now(),
|
680
|
+
'sub_table1',
|
681
|
+
datetime.now(),
|
682
|
+
0,
|
683
|
+
),
|
684
|
+
]
|
685
|
+
self.transaction_wrapper.execute = Mock(return_value=mock_result)
|
686
|
+
|
687
|
+
# Test list subscriptions
|
688
|
+
subs = self.transaction_pubsub_manager.list_subscriptions()
|
689
|
+
|
690
|
+
# Verify
|
691
|
+
self.assertEqual(len(subs), 2)
|
692
|
+
self.assertIsInstance(subs[0], Subscription)
|
693
|
+
self.assertIsInstance(subs[1], Subscription)
|
694
|
+
self.transaction_wrapper.execute.assert_called_with("SHOW SUBSCRIPTIONS")
|
695
|
+
|
696
|
+
|
697
|
+
if __name__ == '__main__':
|
698
|
+
# Create test suite
|
699
|
+
loader = unittest.TestLoader()
|
700
|
+
suite = unittest.TestSuite()
|
701
|
+
|
702
|
+
# Add test cases
|
703
|
+
suite.addTests(loader.loadTestsFromTestCase(TestPubSubManager))
|
704
|
+
suite.addTests(loader.loadTestsFromTestCase(TestAsyncPubSubManager))
|
705
|
+
suite.addTests(loader.loadTestsFromTestCase(TestTransactionPubSubManager))
|
706
|
+
|
707
|
+
# Run tests
|
708
|
+
runner = unittest.TextTestRunner(verbosity=2)
|
709
|
+
result = runner.run(suite)
|
710
|
+
|
711
|
+
# Exit with appropriate code
|
712
|
+
sys.exit(0 if result.wasSuccessful() else 1)
|