microsoft-agents-hosting-core 0.4.0.dev4__py3-none-any.whl → 0.4.0.dev7__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.
- microsoft_agents/hosting/core/oauth/oauth_flow.py +1 -0
- {microsoft_agents_hosting_core-0.4.0.dev4.dist-info → microsoft_agents_hosting_core-0.4.0.dev7.dist-info}/METADATA +2 -2
- {microsoft_agents_hosting_core-0.4.0.dev4.dist-info → microsoft_agents_hosting_core-0.4.0.dev7.dist-info}/RECORD +5 -6
- microsoft_agents/hosting/core/storage/_storage_test_utils.py +0 -508
- {microsoft_agents_hosting_core-0.4.0.dev4.dist-info → microsoft_agents_hosting_core-0.4.0.dev7.dist-info}/WHEEL +0 -0
- {microsoft_agents_hosting_core-0.4.0.dev4.dist-info → microsoft_agents_hosting_core-0.4.0.dev7.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: microsoft-agents-hosting-core
|
|
3
|
-
Version: 0.4.0.
|
|
3
|
+
Version: 0.4.0.dev7
|
|
4
4
|
Summary: Core library for Microsoft Agents
|
|
5
5
|
Author: Microsoft Corporation
|
|
6
6
|
Project-URL: Homepage, https://github.com/microsoft/Agents
|
|
@@ -8,7 +8,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
10
|
Requires-Python: >=3.9
|
|
11
|
-
Requires-Dist: microsoft-agents-activity==0.4.0.
|
|
11
|
+
Requires-Dist: microsoft-agents-activity==0.4.0.dev7
|
|
12
12
|
Requires-Dist: pyjwt>=2.10.1
|
|
13
13
|
Requires-Dist: isodate>=0.6.1
|
|
14
14
|
Requires-Dist: azure-core>=1.30.0
|
|
@@ -65,19 +65,18 @@ microsoft_agents/hosting/core/connector/teams/teams_connector_client.py,sha256=X
|
|
|
65
65
|
microsoft_agents/hosting/core/oauth/__init__.py,sha256=e8PJaNZgbz4V34DDj_RbrK3oaUZc7XE12_x9lJc2MOk,295
|
|
66
66
|
microsoft_agents/hosting/core/oauth/flow_state.py,sha256=2ZKOwGbxZ_QlxlWjg1PSkIm5LsfM-2Qw4XuyWJlj10w,2164
|
|
67
67
|
microsoft_agents/hosting/core/oauth/flow_storage_client.py,sha256=RpeMbPaNl7S1Pf9KQaLPTunnHIjNJODMfxTdEMsaXak,3389
|
|
68
|
-
microsoft_agents/hosting/core/oauth/oauth_flow.py,sha256=
|
|
68
|
+
microsoft_agents/hosting/core/oauth/oauth_flow.py,sha256=flTBNUUNm7CUu_KhjfPJOZEEiVTLhxoDu8cBnwjypmU,12587
|
|
69
69
|
microsoft_agents/hosting/core/state/__init__.py,sha256=yckKi1wg_86ng-DL9Q3R49QiWKvNjPkVNk6HClWgVrY,208
|
|
70
70
|
microsoft_agents/hosting/core/state/agent_state.py,sha256=-6kHxVCl6oUT-XjDXkPOPw0fD227Uy3zNzqMInwFeJc,12891
|
|
71
71
|
microsoft_agents/hosting/core/state/state_property_accessor.py,sha256=kpiNnzkZ6el-oRITRbRkk1Faa_CPFxpJQdvSGxIJP70,1392
|
|
72
72
|
microsoft_agents/hosting/core/state/user_state.py,sha256=zEigX-sroNAyoQAxQjG1OgmJQKjk1zOkdeqylFg7M2E,1484
|
|
73
73
|
microsoft_agents/hosting/core/storage/__init__.py,sha256=wq8zlkoPG6I8PfMvdGPN-tNCdP905W7jylFrmJ-GF6o,196
|
|
74
|
-
microsoft_agents/hosting/core/storage/_storage_test_utils.py,sha256=QwavT0mjdknKHr_70HUZflksA4OVsfxBbS_JoVWIoDc,18315
|
|
75
74
|
microsoft_agents/hosting/core/storage/_type_aliases.py,sha256=VCKtjiCBrhEsGSm3zVVSSccdoiY02GYhABvrLjhAcz8,72
|
|
76
75
|
microsoft_agents/hosting/core/storage/error_handling.py,sha256=zH34d7s4pJG_uajpBWhrtTpH2eMy88kSKaqvOqtbgzY,1265
|
|
77
76
|
microsoft_agents/hosting/core/storage/memory_storage.py,sha256=NADem1wQE1MOG1qMriYw4NjILHEBDbIG5HT6wvHfG2M,2353
|
|
78
77
|
microsoft_agents/hosting/core/storage/storage.py,sha256=vft_Kw4pkzo8NnBEyDx7gAn1Ndg2I9ePaxnuxbKVHzs,3227
|
|
79
78
|
microsoft_agents/hosting/core/storage/store_item.py,sha256=4LSkuI0H0lgWig88YoHFn6BP8Bx44YbyuvqBvaBNdEM,276
|
|
80
|
-
microsoft_agents_hosting_core-0.4.0.
|
|
81
|
-
microsoft_agents_hosting_core-0.4.0.
|
|
82
|
-
microsoft_agents_hosting_core-0.4.0.
|
|
83
|
-
microsoft_agents_hosting_core-0.4.0.
|
|
79
|
+
microsoft_agents_hosting_core-0.4.0.dev7.dist-info/METADATA,sha256=ZN0PIPhdhiWZnl9MabdpEYhcd9XqRApnnrMB-kPM-lk,584
|
|
80
|
+
microsoft_agents_hosting_core-0.4.0.dev7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
81
|
+
microsoft_agents_hosting_core-0.4.0.dev7.dist-info/top_level.txt,sha256=lWKcT4v6fTA_NgsuHdNvuMjSrkiBMXohn64ApY7Xi8A,17
|
|
82
|
+
microsoft_agents_hosting_core-0.4.0.dev7.dist-info/RECORD,,
|
|
@@ -1,508 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
import gc
|
|
3
|
-
from copy import deepcopy
|
|
4
|
-
from abc import ABC
|
|
5
|
-
from typing import Any
|
|
6
|
-
|
|
7
|
-
from .storage import Storage
|
|
8
|
-
from .store_item import StoreItem
|
|
9
|
-
from ._type_aliases import JSON
|
|
10
|
-
from .memory_storage import MemoryStorage
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class MockStoreItem(StoreItem):
|
|
14
|
-
"""Test implementation of StoreItem for testing purposes"""
|
|
15
|
-
|
|
16
|
-
def __init__(self, data: dict[str, Any] = None):
|
|
17
|
-
self.data = data or {}
|
|
18
|
-
|
|
19
|
-
def store_item_to_json(self) -> JSON:
|
|
20
|
-
return self.data
|
|
21
|
-
|
|
22
|
-
@staticmethod
|
|
23
|
-
def from_json_to_store_item(json_data: JSON) -> "MockStoreItem":
|
|
24
|
-
return MockStoreItem(json_data)
|
|
25
|
-
|
|
26
|
-
def __eq__(self, other):
|
|
27
|
-
if not isinstance(other, MockStoreItem):
|
|
28
|
-
return False
|
|
29
|
-
return self.data == other.data
|
|
30
|
-
|
|
31
|
-
def __repr__(self):
|
|
32
|
-
return f"MockStoreItem({self.data})"
|
|
33
|
-
|
|
34
|
-
def deepcopy(self):
|
|
35
|
-
return MockStoreItem(my_deepcopy(self.data))
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class MockStoreItemB(MockStoreItem):
|
|
39
|
-
"""Another test implementation of StoreItem for testing purposes"""
|
|
40
|
-
|
|
41
|
-
def __init__(self, data: dict[str, Any] = None, other_field: bool = True):
|
|
42
|
-
super().__init__(data or {})
|
|
43
|
-
self.other_field = other_field
|
|
44
|
-
|
|
45
|
-
def store_item_to_json(self) -> JSON:
|
|
46
|
-
return [self.data, self.other_field]
|
|
47
|
-
|
|
48
|
-
@staticmethod
|
|
49
|
-
def from_json_to_store_item(json_data: JSON) -> "MockStoreItem":
|
|
50
|
-
return MockStoreItemB(json_data[0], json_data[1])
|
|
51
|
-
|
|
52
|
-
def __eq__(self, other):
|
|
53
|
-
if not isinstance(other, MockStoreItemB):
|
|
54
|
-
return False
|
|
55
|
-
return self.data == other.data and self.other_field == other.other_field
|
|
56
|
-
|
|
57
|
-
def deepcopy(self):
|
|
58
|
-
return MockStoreItemB(my_deepcopy(self.data), self.other_field)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def my_deepcopy(original):
|
|
62
|
-
"""Deep copy an object, including StoreItem instances."""
|
|
63
|
-
|
|
64
|
-
iter_obj = None
|
|
65
|
-
if isinstance(original, list):
|
|
66
|
-
iter_obj = enumerate(original)
|
|
67
|
-
elif isinstance(original, dict):
|
|
68
|
-
iter_obj = original.items()
|
|
69
|
-
elif isinstance(original, MockStoreItem):
|
|
70
|
-
return original.deepcopy()
|
|
71
|
-
else:
|
|
72
|
-
return deepcopy(original)
|
|
73
|
-
|
|
74
|
-
obj = {} if isinstance(original, dict) else ([None] * len(original))
|
|
75
|
-
for key, value in iter_obj:
|
|
76
|
-
obj[key] = my_deepcopy(value)
|
|
77
|
-
return obj
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def subsets(lst, n=-1):
|
|
81
|
-
"""Generate all subsets of a list up to length n. If n is -1, all subsets are generated.
|
|
82
|
-
|
|
83
|
-
Only contiguous subsets are generated.
|
|
84
|
-
"""
|
|
85
|
-
if n < 0:
|
|
86
|
-
n = len(lst)
|
|
87
|
-
subsets = []
|
|
88
|
-
for i in range(len(lst) + 1):
|
|
89
|
-
for j in range(0, i):
|
|
90
|
-
if 1 <= i - j <= n:
|
|
91
|
-
subsets.append(lst[j:i])
|
|
92
|
-
return subsets
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# bootstrapping class to compare against
|
|
96
|
-
# if this class is correct, then the tests are correct
|
|
97
|
-
class StorageBaseline(Storage):
|
|
98
|
-
""" "A simple in-memory storage implementation for testing purposes."""
|
|
99
|
-
|
|
100
|
-
def __init__(self, initial_data: dict = None):
|
|
101
|
-
self._memory = deepcopy(initial_data) or {}
|
|
102
|
-
self._key_history = set(initial_data.keys()) if initial_data else set()
|
|
103
|
-
|
|
104
|
-
def read(self, keys: list[str]) -> dict[str, Any]:
|
|
105
|
-
self._key_history.update(keys)
|
|
106
|
-
return {key: self._memory.get(key) for key in keys if key in self._memory}
|
|
107
|
-
|
|
108
|
-
def write(self, changes: dict[str, Any]) -> None:
|
|
109
|
-
self._key_history.update(changes.keys())
|
|
110
|
-
self._memory.update(changes)
|
|
111
|
-
|
|
112
|
-
def delete(self, keys: list[str]) -> None:
|
|
113
|
-
self._key_history.update(keys)
|
|
114
|
-
for key in keys:
|
|
115
|
-
if key in self._memory:
|
|
116
|
-
del self._memory[key]
|
|
117
|
-
|
|
118
|
-
async def equals(self, other) -> bool:
|
|
119
|
-
"""
|
|
120
|
-
Compare the items for all keys seen by this mock instance.
|
|
121
|
-
|
|
122
|
-
Note:
|
|
123
|
-
This is an extra safety measure, and I've made the
|
|
124
|
-
executive decision to not test this method itself
|
|
125
|
-
because passing tests with calls to this method
|
|
126
|
-
is also dependent on the correctness of other
|
|
127
|
-
aspects, based on the other assertions in the tests.
|
|
128
|
-
"""
|
|
129
|
-
for key in self._key_history:
|
|
130
|
-
if key not in self._memory:
|
|
131
|
-
if len(await other.read([key], target_cls=MockStoreItem)) > 0:
|
|
132
|
-
breakpoint()
|
|
133
|
-
return False # key should not exist in other
|
|
134
|
-
continue
|
|
135
|
-
|
|
136
|
-
# key exists in baseline instance, so let's see if the values match
|
|
137
|
-
item = self._memory.get(key, None)
|
|
138
|
-
target_cls = type(item)
|
|
139
|
-
res = await other.read([key], target_cls=target_cls)
|
|
140
|
-
|
|
141
|
-
if key not in res or item != res[key]:
|
|
142
|
-
breakpoint()
|
|
143
|
-
return False
|
|
144
|
-
return True
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
class StorageTestsCommon(ABC):
|
|
148
|
-
"""Common fixtures for Storage implementations."""
|
|
149
|
-
|
|
150
|
-
KEY_LIST = [
|
|
151
|
-
"f",
|
|
152
|
-
"a!0dslfj",
|
|
153
|
-
"\\?/#\t\n\r*",
|
|
154
|
-
"527",
|
|
155
|
-
"test.txt",
|
|
156
|
-
"_-__--",
|
|
157
|
-
"VAR",
|
|
158
|
-
"None",
|
|
159
|
-
"multi word key",
|
|
160
|
-
]
|
|
161
|
-
|
|
162
|
-
READ_KEY_LIST = KEY_LIST + (["5", "20", "100", "nonexistent_key", "-"])
|
|
163
|
-
|
|
164
|
-
STATE_LIST = [
|
|
165
|
-
{key: MockStoreItem({"id": key, "value": f"value{key}"}) for key in subset}
|
|
166
|
-
for subset in subsets(KEY_LIST, 3)
|
|
167
|
-
if len(subset) == 3
|
|
168
|
-
]
|
|
169
|
-
|
|
170
|
-
@pytest.fixture(params=[dict()] + STATE_LIST)
|
|
171
|
-
def initial_state(self, request):
|
|
172
|
-
return request.param
|
|
173
|
-
|
|
174
|
-
@pytest.fixture(params=KEY_LIST)
|
|
175
|
-
def key(self, request):
|
|
176
|
-
return request.param
|
|
177
|
-
|
|
178
|
-
@pytest.fixture(
|
|
179
|
-
params=[subset for subset in subsets(READ_KEY_LIST, 2) if len(subset) == 2]
|
|
180
|
-
)
|
|
181
|
-
def keys(self, request):
|
|
182
|
-
return request.param
|
|
183
|
-
|
|
184
|
-
@pytest.fixture(params=subsets(KEY_LIST, 2))
|
|
185
|
-
def changes(self, request):
|
|
186
|
-
changes_obj = {}
|
|
187
|
-
keys = request.param
|
|
188
|
-
changes_obj["new_key"] = MockStoreItemB(
|
|
189
|
-
{"field": "new_value_for_new_key"}, True
|
|
190
|
-
)
|
|
191
|
-
for i, key in enumerate(keys):
|
|
192
|
-
if i % 2 == 0:
|
|
193
|
-
changes_obj[key] = MockStoreItemB(
|
|
194
|
-
{"data": f"value{key}"}, (i // 2) % 2 == 0
|
|
195
|
-
)
|
|
196
|
-
else:
|
|
197
|
-
changes_obj[key] = MockStoreItem(
|
|
198
|
-
{"id": key, "value": f"new_value_for_{key}"}
|
|
199
|
-
)
|
|
200
|
-
changes_obj["new_key_2"] = MockStoreItem({"field": "new_value_for_new_key_2"})
|
|
201
|
-
return changes_obj
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
class CRUDStorageTests(StorageTestsCommon):
|
|
205
|
-
"""Tests for Storage implementations that support CRUD operations.
|
|
206
|
-
|
|
207
|
-
To use, subclass and implement the `storage` method.
|
|
208
|
-
"""
|
|
209
|
-
|
|
210
|
-
async def storage(self, initial_data=None, existing=False) -> Storage:
|
|
211
|
-
"""Return a Storage instance to be tested.
|
|
212
|
-
:param initial_data: The initial data to populate the storage with.
|
|
213
|
-
:param existing: If True, the storage instance should connect to an existing store.
|
|
214
|
-
"""
|
|
215
|
-
raise NotImplementedError("Subclasses must implement this")
|
|
216
|
-
|
|
217
|
-
@pytest.mark.asyncio
|
|
218
|
-
async def test_read_individual(self, initial_state, key):
|
|
219
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
220
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
221
|
-
storage = await self.storage(initial_state)
|
|
222
|
-
expected = baseline_storage.read([key])
|
|
223
|
-
actual = await storage.read([key], target_cls=MockStoreItem)
|
|
224
|
-
assert actual == expected
|
|
225
|
-
assert await baseline_storage.equals(storage)
|
|
226
|
-
assert initial_state == initial_state_copy
|
|
227
|
-
|
|
228
|
-
@pytest.mark.asyncio
|
|
229
|
-
async def test_read(self, initial_state, keys):
|
|
230
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
231
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
232
|
-
storage = await self.storage(initial_state)
|
|
233
|
-
expected = baseline_storage.read(keys)
|
|
234
|
-
actual = await storage.read(keys, target_cls=MockStoreItem)
|
|
235
|
-
assert actual == expected
|
|
236
|
-
assert await baseline_storage.equals(storage)
|
|
237
|
-
assert initial_state == initial_state_copy
|
|
238
|
-
|
|
239
|
-
@pytest.mark.asyncio
|
|
240
|
-
async def test_read_missing_key(self, initial_state):
|
|
241
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
242
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
243
|
-
storage = await self.storage(initial_state)
|
|
244
|
-
keys = ["5", "20", "100", "nonexistent_key", "-"]
|
|
245
|
-
expected = baseline_storage.read(keys)
|
|
246
|
-
actual = await storage.read(keys, target_cls=MockStoreItem)
|
|
247
|
-
assert actual == expected
|
|
248
|
-
assert await baseline_storage.equals(storage)
|
|
249
|
-
assert initial_state == initial_state_copy
|
|
250
|
-
|
|
251
|
-
@pytest.mark.asyncio
|
|
252
|
-
async def test_read_errors(self, initial_state):
|
|
253
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
254
|
-
storage = await self.storage(initial_state)
|
|
255
|
-
with pytest.raises(ValueError):
|
|
256
|
-
await storage.read([], target_cls=MockStoreItem)
|
|
257
|
-
with pytest.raises(ValueError):
|
|
258
|
-
await storage.read(None, target_cls=MockStoreItem)
|
|
259
|
-
with pytest.raises(ValueError):
|
|
260
|
-
await storage.read([""], target_cls=MockStoreItem)
|
|
261
|
-
with pytest.raises(ValueError):
|
|
262
|
-
await storage.read(["key"], target_cls=None)
|
|
263
|
-
assert initial_state == initial_state_copy
|
|
264
|
-
|
|
265
|
-
@pytest.mark.asyncio
|
|
266
|
-
async def test_write_individual(self, initial_state, key):
|
|
267
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
268
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
269
|
-
storage = await self.storage(initial_state)
|
|
270
|
-
change = {key: MockStoreItem({key: f"new_value_for_{key}!"})}
|
|
271
|
-
baseline_storage.write(change)
|
|
272
|
-
await storage.write(change)
|
|
273
|
-
assert await baseline_storage.equals(storage)
|
|
274
|
-
assert initial_state == initial_state_copy
|
|
275
|
-
|
|
276
|
-
@pytest.mark.asyncio
|
|
277
|
-
async def test_write_individual_different_target_cls(self, initial_state, key):
|
|
278
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
279
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
280
|
-
storage = await self.storage(initial_state)
|
|
281
|
-
change = {
|
|
282
|
-
key: MockStoreItemB({key: f"new_value_for_{key}!"}, other_field=False)
|
|
283
|
-
}
|
|
284
|
-
baseline_storage.write(change)
|
|
285
|
-
await storage.write(change)
|
|
286
|
-
assert await baseline_storage.equals(storage)
|
|
287
|
-
change = {key: MockStoreItemB({key: f"new_{key}"}, other_field=True)}
|
|
288
|
-
baseline_storage.write(change)
|
|
289
|
-
await storage.write(change)
|
|
290
|
-
assert await baseline_storage.equals(storage)
|
|
291
|
-
assert initial_state == initial_state_copy
|
|
292
|
-
|
|
293
|
-
@pytest.mark.asyncio
|
|
294
|
-
async def test_write_same_values(self, initial_state):
|
|
295
|
-
if not initial_state:
|
|
296
|
-
return
|
|
297
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
298
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
299
|
-
storage = await self.storage(initial_state)
|
|
300
|
-
changes = {key: value for key, value in initial_state.items()}
|
|
301
|
-
baseline_storage.write(changes)
|
|
302
|
-
await storage.write(changes)
|
|
303
|
-
assert await baseline_storage.equals(storage)
|
|
304
|
-
assert initial_state == initial_state_copy
|
|
305
|
-
|
|
306
|
-
@pytest.mark.asyncio
|
|
307
|
-
async def test_write(self, initial_state, changes):
|
|
308
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
309
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
310
|
-
storage = await self.storage(initial_state)
|
|
311
|
-
baseline_storage.write(changes)
|
|
312
|
-
await storage.write(changes)
|
|
313
|
-
assert await baseline_storage.equals(storage)
|
|
314
|
-
baseline_storage.write(initial_state)
|
|
315
|
-
if initial_state:
|
|
316
|
-
await storage.write(initial_state)
|
|
317
|
-
assert await baseline_storage.equals(storage)
|
|
318
|
-
assert initial_state == initial_state_copy
|
|
319
|
-
|
|
320
|
-
@pytest.mark.asyncio
|
|
321
|
-
async def test_write_errors(self, initial_state):
|
|
322
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
323
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
324
|
-
storage = await self.storage(initial_state)
|
|
325
|
-
with pytest.raises(ValueError):
|
|
326
|
-
await storage.write({})
|
|
327
|
-
with pytest.raises(ValueError):
|
|
328
|
-
await storage.write(None)
|
|
329
|
-
assert await baseline_storage.equals(storage)
|
|
330
|
-
assert initial_state == initial_state_copy
|
|
331
|
-
|
|
332
|
-
@pytest.mark.asyncio
|
|
333
|
-
async def test_delete_individual(self, initial_state, key):
|
|
334
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
335
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
336
|
-
storage = await self.storage(initial_state)
|
|
337
|
-
baseline_storage.delete([key])
|
|
338
|
-
await storage.delete([key])
|
|
339
|
-
assert await baseline_storage.equals(storage)
|
|
340
|
-
assert initial_state == initial_state_copy
|
|
341
|
-
|
|
342
|
-
@pytest.mark.asyncio
|
|
343
|
-
async def test_delete(self, initial_state, keys):
|
|
344
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
345
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
346
|
-
storage = await self.storage(initial_state)
|
|
347
|
-
baseline_storage.delete(keys)
|
|
348
|
-
await storage.delete(keys)
|
|
349
|
-
assert await baseline_storage.equals(storage)
|
|
350
|
-
assert initial_state == initial_state_copy
|
|
351
|
-
|
|
352
|
-
@pytest.mark.asyncio
|
|
353
|
-
async def test_delete_missing_key(self, initial_state):
|
|
354
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
355
|
-
baseline_storage = StorageBaseline(initial_state)
|
|
356
|
-
storage = await self.storage(initial_state)
|
|
357
|
-
keys = ["5", "20", "100", "nonexistent_key", "-"]
|
|
358
|
-
baseline_storage.delete(keys)
|
|
359
|
-
await storage.delete(keys)
|
|
360
|
-
assert await baseline_storage.equals(storage)
|
|
361
|
-
assert initial_state == initial_state_copy
|
|
362
|
-
|
|
363
|
-
@pytest.mark.asyncio
|
|
364
|
-
async def test_delete_errors(self, initial_state):
|
|
365
|
-
initial_state_copy = my_deepcopy(initial_state)
|
|
366
|
-
storage = await self.storage(initial_state)
|
|
367
|
-
with pytest.raises(ValueError):
|
|
368
|
-
await storage.read([])
|
|
369
|
-
with pytest.raises(ValueError):
|
|
370
|
-
await storage.read(None)
|
|
371
|
-
assert initial_state == initial_state_copy
|
|
372
|
-
|
|
373
|
-
@pytest.mark.asyncio
|
|
374
|
-
async def test_flow(self):
|
|
375
|
-
baseline_storage = StorageBaseline()
|
|
376
|
-
storage = await self.storage()
|
|
377
|
-
|
|
378
|
-
res = await storage.read(["key"], target_cls=MockStoreItemB)
|
|
379
|
-
assert len(res) == 0
|
|
380
|
-
assert await baseline_storage.equals(storage)
|
|
381
|
-
|
|
382
|
-
changes = {
|
|
383
|
-
"key_a": MockStoreItem({"id": "key_a", "value": "value_a"}),
|
|
384
|
-
"key_b": MockStoreItemB(
|
|
385
|
-
{"id": "key_b", "value": "value_b"}, other_field=False
|
|
386
|
-
),
|
|
387
|
-
}
|
|
388
|
-
changes_copy = my_deepcopy(changes)
|
|
389
|
-
|
|
390
|
-
baseline_storage.write(changes)
|
|
391
|
-
await storage.write(changes)
|
|
392
|
-
|
|
393
|
-
assert (
|
|
394
|
-
await storage.read(["key_a"], target_cls=MockStoreItem)
|
|
395
|
-
) == baseline_storage.read(["key_a"])
|
|
396
|
-
assert (
|
|
397
|
-
await storage.read(["key_b"], target_cls=MockStoreItemB)
|
|
398
|
-
) == baseline_storage.read(["key_b"])
|
|
399
|
-
assert changes_copy == changes
|
|
400
|
-
|
|
401
|
-
baseline_storage.delete(["key_a"])
|
|
402
|
-
await storage.delete(["key_a"])
|
|
403
|
-
assert await baseline_storage.equals(storage)
|
|
404
|
-
|
|
405
|
-
change = {"key_b": MockStoreItem({"id": "key_b", "value": "new_value_b"})}
|
|
406
|
-
baseline_storage.write(change)
|
|
407
|
-
await storage.write(change)
|
|
408
|
-
|
|
409
|
-
assert await baseline_storage.equals(storage)
|
|
410
|
-
assert (
|
|
411
|
-
await storage.read(["key_b"], target_cls=MockStoreItem)
|
|
412
|
-
) == baseline_storage.read(["key_b"])
|
|
413
|
-
|
|
414
|
-
with pytest.raises(ValueError):
|
|
415
|
-
await storage.read([], target_cls=MockStoreItem)
|
|
416
|
-
with pytest.raises(ValueError):
|
|
417
|
-
await storage.read(["key_b"], target_cls=None)
|
|
418
|
-
|
|
419
|
-
change = {
|
|
420
|
-
"key_c": MockStoreItemB(
|
|
421
|
-
{"id": "key_c", "value": "value_c"}, other_field=True
|
|
422
|
-
)
|
|
423
|
-
}
|
|
424
|
-
baseline_storage.write(change)
|
|
425
|
-
await storage.write(change)
|
|
426
|
-
assert (
|
|
427
|
-
await storage.read(["key_a", "key_b"], target_cls=MockStoreItem)
|
|
428
|
-
) == baseline_storage.read(["key_a", "key_b"])
|
|
429
|
-
assert (
|
|
430
|
-
await storage.read(["key_a", "key_c"], target_cls=MockStoreItemB)
|
|
431
|
-
) == baseline_storage.read(["key_a", "key_c"])
|
|
432
|
-
|
|
433
|
-
item_parent_class = (await storage.read(["key_c"], target_cls=MockStoreItem))[
|
|
434
|
-
"key_c"
|
|
435
|
-
]
|
|
436
|
-
item_child_class = (await storage.read(["key_c"], target_cls=MockStoreItemB))[
|
|
437
|
-
"key_c"
|
|
438
|
-
]
|
|
439
|
-
assert item_parent_class.data[0] == item_child_class.data
|
|
440
|
-
assert item_child_class.other_field == True
|
|
441
|
-
|
|
442
|
-
with pytest.raises(ValueError):
|
|
443
|
-
await storage.write({})
|
|
444
|
-
with pytest.raises(Exception):
|
|
445
|
-
await storage.read(["key_b"], target_cls=MockStoreItemB)
|
|
446
|
-
assert await baseline_storage.equals(storage)
|
|
447
|
-
|
|
448
|
-
if not isinstance(storage, MemoryStorage):
|
|
449
|
-
# if not memory storage, then items should persist
|
|
450
|
-
del storage
|
|
451
|
-
gc.collect()
|
|
452
|
-
storage_alt = await self.storage(existing=True)
|
|
453
|
-
assert await baseline_storage.equals(storage_alt)
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
class QuickCRUDStorageTests(CRUDStorageTests):
|
|
457
|
-
"""Reduced set of permutations for quicker tests. Useful for debugging."""
|
|
458
|
-
|
|
459
|
-
KEY_LIST = ["\\?/#\t\n\r*", "test.txt"]
|
|
460
|
-
|
|
461
|
-
READ_KEY_LIST = KEY_LIST + ["nonexistent_key"]
|
|
462
|
-
|
|
463
|
-
STATE_LIST = [
|
|
464
|
-
{key: MockStoreItem({"id": key, "value": f"value{key}"}) for key in KEY_LIST}
|
|
465
|
-
]
|
|
466
|
-
|
|
467
|
-
@pytest.fixture(params=STATE_LIST)
|
|
468
|
-
def initial_state(self, request):
|
|
469
|
-
return request.param
|
|
470
|
-
|
|
471
|
-
@pytest.fixture(params=KEY_LIST)
|
|
472
|
-
def key(self, request):
|
|
473
|
-
return request.param
|
|
474
|
-
|
|
475
|
-
@pytest.fixture(params=[KEY_LIST])
|
|
476
|
-
def keys(self, request):
|
|
477
|
-
return request.param
|
|
478
|
-
|
|
479
|
-
@pytest.fixture(params=subsets(KEY_LIST, 2))
|
|
480
|
-
def changes(self, request):
|
|
481
|
-
changes_obj = {}
|
|
482
|
-
keys = request.param
|
|
483
|
-
changes_obj["new_key"] = MockStoreItemB(
|
|
484
|
-
{"field": "new_value_for_new_key"}, True
|
|
485
|
-
)
|
|
486
|
-
for i, key in enumerate(keys):
|
|
487
|
-
if i % 2 == 0:
|
|
488
|
-
changes_obj[key] = MockStoreItemB(
|
|
489
|
-
{"data": f"value{key}"}, (i // 2) % 2 == 0
|
|
490
|
-
)
|
|
491
|
-
else:
|
|
492
|
-
changes_obj[key] = MockStoreItem(
|
|
493
|
-
{"id": key, "value": f"new_value_for_{key}"}
|
|
494
|
-
)
|
|
495
|
-
changes_obj["new_key_2"] = MockStoreItem({"field": "new_value_for_new_key_2"})
|
|
496
|
-
return changes_obj
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
def debug_print(*args):
|
|
500
|
-
"""Print debug information clearly separated in the console."""
|
|
501
|
-
print("\n" * 2)
|
|
502
|
-
print("--- DEBUG ---")
|
|
503
|
-
for arg in args:
|
|
504
|
-
print("\n" * 2)
|
|
505
|
-
print(arg)
|
|
506
|
-
print("\n" * 2)
|
|
507
|
-
print("--- ----- ---")
|
|
508
|
-
print("\n" * 2)
|
|
File without changes
|