mesh-sandbox 0.1.14__py3-none-any.whl → 0.1.16__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.
- mesh_sandbox/__init__.py +1 -1
- mesh_sandbox/api.py +2 -2
- mesh_sandbox/handlers/inbox.py +3 -2
- mesh_sandbox/handlers/reset.py +14 -3
- mesh_sandbox/handlers/tracking.py +9 -0
- mesh_sandbox/routers/{simple.py → admin.py} +22 -2
- mesh_sandbox/store/base.py +8 -2
- mesh_sandbox/store/canned_store.py +4 -1
- mesh_sandbox/store/file_store.py +9 -2
- mesh_sandbox/store/memory_store.py +8 -1
- mesh_sandbox/tests/admin.py +201 -0
- mesh_sandbox/tests/helpers.py +0 -33
- mesh_sandbox/tests/inbox.py +63 -4
- mesh_sandbox/tests/mesh_api_helpers.py +132 -0
- mesh_sandbox/tests/mesh_client_tests.py +45 -16
- mesh_sandbox/tests/outbox.py +18 -14
- {mesh_sandbox-0.1.14.dist-info → mesh_sandbox-0.1.16.dist-info}/METADATA +1 -1
- {mesh_sandbox-0.1.14.dist-info → mesh_sandbox-0.1.16.dist-info}/RECORD +20 -19
- mesh_sandbox/tests/reset.py +0 -59
- {mesh_sandbox-0.1.14.dist-info → mesh_sandbox-0.1.16.dist-info}/LICENSE +0 -0
- {mesh_sandbox-0.1.14.dist-info → mesh_sandbox-0.1.16.dist-info}/WHEEL +0 -0
mesh_sandbox/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.16"
|
mesh_sandbox/api.py
CHANGED
|
@@ -7,12 +7,12 @@ from .common import logger
|
|
|
7
7
|
from .common.exceptions import MessagingException
|
|
8
8
|
from .dependencies import get_env_config
|
|
9
9
|
from .routers import (
|
|
10
|
+
admin,
|
|
10
11
|
handshake,
|
|
11
12
|
inbox,
|
|
12
13
|
inbox_count,
|
|
13
14
|
lookup,
|
|
14
15
|
outbox,
|
|
15
|
-
simple,
|
|
16
16
|
tracking,
|
|
17
17
|
update,
|
|
18
18
|
)
|
|
@@ -72,7 +72,7 @@ async def validation_exception_handler(request: Request, exc: RequestValidationE
|
|
|
72
72
|
return get_validation_error_response(request, exc)
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
app.include_router(
|
|
75
|
+
app.include_router(admin.router)
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
app.include_router(
|
mesh_sandbox/handlers/inbox.py
CHANGED
|
@@ -241,9 +241,10 @@ class InboxHandler:
|
|
|
241
241
|
max_results: int = DEFAULT_MAX_RESULTS,
|
|
242
242
|
last_key: Optional[dict] = None,
|
|
243
243
|
message_filter: Optional[Callable[[Message], bool]] = None,
|
|
244
|
+
rich: bool = False,
|
|
244
245
|
) -> tuple[list[Message], Optional[dict]]:
|
|
245
246
|
|
|
246
|
-
messages = await self.store.get_inbox(mailbox.mailbox_id)
|
|
247
|
+
messages = await self.store.get_inbox(mailbox.mailbox_id, rich=rich)
|
|
247
248
|
|
|
248
249
|
if message_filter:
|
|
249
250
|
messages = list(filter(message_filter, messages))
|
|
@@ -383,7 +384,7 @@ class InboxHandler:
|
|
|
383
384
|
def message_filter(message: Message) -> bool:
|
|
384
385
|
return message.created_timestamp > from_date
|
|
385
386
|
|
|
386
|
-
messages, last_key = await self._get_inbox_messages(mailbox, max_results, last_key, message_filter)
|
|
387
|
+
messages, last_key = await self._get_inbox_messages(mailbox, max_results, last_key, message_filter, rich=True)
|
|
387
388
|
|
|
388
389
|
url_template = "{0}/inbox/rich"
|
|
389
390
|
links: dict[str, str] = {
|
mesh_sandbox/handlers/reset.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from fastapi import Depends, HTTPException, status
|
|
2
4
|
|
|
3
5
|
from ..common import EnvConfig
|
|
4
6
|
from ..dependencies import get_env_config, get_store
|
|
@@ -10,5 +12,14 @@ class ResetHandler:
|
|
|
10
12
|
self.config = config
|
|
11
13
|
self.store = store
|
|
12
14
|
|
|
13
|
-
async def reset(self, clear_disk: bool):
|
|
14
|
-
|
|
15
|
+
async def reset(self, clear_disk: bool, mailbox_id: Optional[str] = None):
|
|
16
|
+
|
|
17
|
+
if not mailbox_id:
|
|
18
|
+
await self.store.reset(clear_disk)
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
mailbox = await self.store.get_mailbox(mailbox_id, accessed=True)
|
|
22
|
+
if not mailbox:
|
|
23
|
+
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="mailbox does not exist")
|
|
24
|
+
|
|
25
|
+
await self.store.reset_mailbox(clear_disk, mailbox.mailbox_id)
|
|
@@ -28,6 +28,10 @@ class TrackingHandler:
|
|
|
28
28
|
# intentionally not a 403 (matching spine)
|
|
29
29
|
raise HTTPException(status_code=http_status.HTTP_404_NOT_FOUND)
|
|
30
30
|
|
|
31
|
+
sender_outbox = await self.store.get_outbox(sender_mailbox.mailbox_id)
|
|
32
|
+
if message.message_id not in [message.message_id for message in sender_outbox]:
|
|
33
|
+
raise HTTPException(status_code=http_status.HTTP_404_NOT_FOUND)
|
|
34
|
+
|
|
31
35
|
model = create_tracking_response(message, accepts_api_version)
|
|
32
36
|
return JSONResponse(content=exclude_none_json_encoder(model), media_type=MESH_MEDIA_TYPES[accepts_api_version])
|
|
33
37
|
|
|
@@ -42,5 +46,10 @@ class TrackingHandler:
|
|
|
42
46
|
raise HTTPException(status_code=http_status.HTTP_300_MULTIPLE_CHOICES)
|
|
43
47
|
|
|
44
48
|
message = messages[0]
|
|
49
|
+
|
|
50
|
+
sender_outbox = await self.store.get_outbox(sender_mailbox.mailbox_id)
|
|
51
|
+
if message.message_id not in [message.message_id for message in sender_outbox]:
|
|
52
|
+
raise HTTPException(status_code=http_status.HTTP_404_NOT_FOUND)
|
|
53
|
+
|
|
45
54
|
model = create_tracking_response(message, 1)
|
|
46
55
|
return JSONResponse(content=exclude_none_json_encoder(model))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from fastapi import APIRouter, Depends, Query, status
|
|
2
2
|
|
|
3
|
-
from ..dependencies import EnvConfig, get_env_config
|
|
3
|
+
from ..dependencies import EnvConfig, get_env_config, normalise_mailbox_id_path
|
|
4
4
|
from ..handlers.reset import ResetHandler
|
|
5
5
|
from .request_logging import RequestLoggingRoute
|
|
6
6
|
|
|
@@ -40,4 +40,24 @@ async def reset(
|
|
|
40
40
|
handler: ResetHandler = Depends(ResetHandler),
|
|
41
41
|
):
|
|
42
42
|
await handler.reset(clear_disk.lower() == "true")
|
|
43
|
-
return {"message": "reset
|
|
43
|
+
return {"message": "all mailboxes reset"}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@router.get(
|
|
47
|
+
"/messageexchange/reset/{mailbox_id}",
|
|
48
|
+
status_code=status.HTTP_200_OK,
|
|
49
|
+
include_in_schema=False,
|
|
50
|
+
response_model_exclude_none=True,
|
|
51
|
+
)
|
|
52
|
+
async def reset_mailbox(
|
|
53
|
+
clear_disk: str = Query(
|
|
54
|
+
default="true",
|
|
55
|
+
title="Clear disk",
|
|
56
|
+
description="whether to clear the filesystem store if STORE_MODE=file, otherwise ignored",
|
|
57
|
+
example="true",
|
|
58
|
+
),
|
|
59
|
+
mailbox_id: str = Depends(normalise_mailbox_id_path),
|
|
60
|
+
handler: ResetHandler = Depends(ResetHandler),
|
|
61
|
+
):
|
|
62
|
+
await handler.reset(clear_disk.lower() == "true", mailbox_id)
|
|
63
|
+
return {"message": "mailbox {mailbox_id} reset"}
|
mesh_sandbox/store/base.py
CHANGED
|
@@ -72,7 +72,13 @@ class Store(ABC):
|
|
|
72
72
|
def __init__(self, config: EnvConfig):
|
|
73
73
|
self.config = config
|
|
74
74
|
|
|
75
|
-
async def
|
|
75
|
+
async def reset(self, clear_disk: bool):
|
|
76
|
+
raise HTTPException(
|
|
77
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
78
|
+
detail=f"reset not supported for {self.config.store_mode} store mode",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
async def reset_mailbox(self, clear_disk: bool, mailbox_id: str):
|
|
76
82
|
raise HTTPException(
|
|
77
83
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
78
84
|
detail=f"reset not supported for {self.config.store_mode} store mode",
|
|
@@ -156,7 +162,7 @@ class Store(ABC):
|
|
|
156
162
|
pass
|
|
157
163
|
|
|
158
164
|
@abstractmethod
|
|
159
|
-
async def get_inbox(self, mailbox_id: str) -> list[Message]:
|
|
165
|
+
async def get_inbox(self, mailbox_id: str, rich: bool) -> list[Message]:
|
|
160
166
|
pass
|
|
161
167
|
|
|
162
168
|
@abstractmethod
|
|
@@ -167,7 +167,10 @@ class CannedStore(Store):
|
|
|
167
167
|
async def get_message(self, message_id: str) -> Optional[Message]:
|
|
168
168
|
return self.messages.get(message_id)
|
|
169
169
|
|
|
170
|
-
async def get_inbox(self, mailbox_id: str) -> list[Message]:
|
|
170
|
+
async def get_inbox(self, mailbox_id: str, rich: bool) -> list[Message]:
|
|
171
|
+
if rich: # note: rich inbox is deprecated
|
|
172
|
+
return [m for m in self.messages.values() if m.recipient.mailbox_id == mailbox_id]
|
|
173
|
+
|
|
171
174
|
return self.inboxes[mailbox_id]
|
|
172
175
|
|
|
173
176
|
async def get_outbox(self, mailbox_id: str) -> list[Message]:
|
mesh_sandbox/store/file_store.py
CHANGED
|
@@ -15,8 +15,8 @@ class FileStore(MemoryStore):
|
|
|
15
15
|
super().__init__(config)
|
|
16
16
|
self._base_dir = config.file_store_dir
|
|
17
17
|
|
|
18
|
-
async def
|
|
19
|
-
await super().
|
|
18
|
+
async def reset(self, clear_disk: bool):
|
|
19
|
+
await super().reset(clear_disk)
|
|
20
20
|
# recursive delete, but preserve top-level folder
|
|
21
21
|
if clear_disk:
|
|
22
22
|
for file in os.listdir(self._base_dir):
|
|
@@ -26,6 +26,13 @@ class FileStore(MemoryStore):
|
|
|
26
26
|
else:
|
|
27
27
|
shutil.rmtree(path)
|
|
28
28
|
|
|
29
|
+
async def reset_mailbox(self, clear_disk: bool, mailbox_id):
|
|
30
|
+
await super().reset_mailbox(clear_disk, mailbox_id)
|
|
31
|
+
if clear_disk:
|
|
32
|
+
path = os.path.join(self._base_dir, mailbox_id)
|
|
33
|
+
if os.path.exists(path):
|
|
34
|
+
shutil.rmtree(path)
|
|
35
|
+
|
|
29
36
|
async def _get_file_size(self, message: Message) -> int:
|
|
30
37
|
size = 0
|
|
31
38
|
message_dir = os.path.join(self._base_dir, f"{message.recipient.mailbox_id}/in/{message.message_id}")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
1
2
|
from typing import cast
|
|
2
3
|
|
|
3
4
|
from ..common import EnvConfig
|
|
@@ -13,9 +14,15 @@ class MemoryStore(CannedStore):
|
|
|
13
14
|
def __init__(self, config: EnvConfig):
|
|
14
15
|
super().__init__(config, load_messages=False)
|
|
15
16
|
|
|
16
|
-
async def
|
|
17
|
+
async def reset(self, clear_disk: bool):
|
|
17
18
|
super().initialise()
|
|
18
19
|
|
|
20
|
+
async def reset_mailbox(self, clear_disk: bool, mailbox_id: str):
|
|
21
|
+
|
|
22
|
+
self.inboxes[mailbox_id] = []
|
|
23
|
+
self.outboxes[mailbox_id] = []
|
|
24
|
+
self.local_ids[mailbox_id] = defaultdict(list)
|
|
25
|
+
|
|
19
26
|
async def send_message(self, message: Message, body: bytes):
|
|
20
27
|
|
|
21
28
|
async with self.lock:
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
from fastapi import status
|
|
6
|
+
from fastapi.testclient import TestClient
|
|
7
|
+
|
|
8
|
+
from mesh_sandbox.tests import _CANNED_MAILBOX1, _CANNED_MAILBOX2
|
|
9
|
+
from mesh_sandbox.tests.mesh_api_helpers import (
|
|
10
|
+
mesh_api_get_inbox_size,
|
|
11
|
+
mesh_api_send_message_and_return_message_id,
|
|
12
|
+
mesh_api_track_message_by_message_id,
|
|
13
|
+
mesh_api_track_message_by_message_id_status,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .helpers import temp_env_vars
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_reset_canned_store_should_return_bad_request(app: TestClient):
|
|
20
|
+
|
|
21
|
+
with temp_env_vars(STORE_MODE="canned"):
|
|
22
|
+
|
|
23
|
+
res = app.get("/messageexchange/reset")
|
|
24
|
+
assert res.status_code == status.HTTP_400_BAD_REQUEST
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_reset_canned_store_with_valid_mailbox_id_should_return_bad_request(app: TestClient):
|
|
28
|
+
|
|
29
|
+
with temp_env_vars(STORE_MODE="canned"):
|
|
30
|
+
|
|
31
|
+
res = app.get(f"/messageexchange/reset/{_CANNED_MAILBOX1}")
|
|
32
|
+
assert res.status_code == status.HTTP_400_BAD_REQUEST
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_reset_memory_store_with_invalid_mailbox_id_should_return_bad_request(app: TestClient):
|
|
36
|
+
|
|
37
|
+
with temp_env_vars(STORE_MODE="memory"):
|
|
38
|
+
|
|
39
|
+
res = app.get(f"/messageexchange/reset/{uuid4().hex}")
|
|
40
|
+
assert res.status_code == status.HTTP_400_BAD_REQUEST
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_reset_file_store_with_invalid_mailbox_id_should_return_bad_request(app: TestClient):
|
|
44
|
+
|
|
45
|
+
with temp_env_vars(STORE_MODE="file"):
|
|
46
|
+
|
|
47
|
+
res = app.get(f"/messageexchange/reset/{uuid4().hex}")
|
|
48
|
+
assert res.status_code == status.HTTP_400_BAD_REQUEST
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_reset_memory_store_should_clear_all_mailboxes(app: TestClient):
|
|
52
|
+
|
|
53
|
+
with temp_env_vars(STORE_MODE="memory"):
|
|
54
|
+
|
|
55
|
+
msg_1to2_id = mesh_api_send_message_and_return_message_id(app, _CANNED_MAILBOX1, _CANNED_MAILBOX2)
|
|
56
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX2) == 1
|
|
57
|
+
|
|
58
|
+
msg_2to1_id = mesh_api_send_message_and_return_message_id(app, _CANNED_MAILBOX2, _CANNED_MAILBOX1)
|
|
59
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX1) == 1
|
|
60
|
+
|
|
61
|
+
res = app.get("/messageexchange/reset")
|
|
62
|
+
assert res.status_code == status.HTTP_200_OK
|
|
63
|
+
|
|
64
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX1) == 0
|
|
65
|
+
assert (
|
|
66
|
+
mesh_api_track_message_by_message_id_status(app, _CANNED_MAILBOX1, msg_2to1_id) == status.HTTP_404_NOT_FOUND
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX2) == 0
|
|
70
|
+
assert (
|
|
71
|
+
mesh_api_track_message_by_message_id_status(app, _CANNED_MAILBOX2, msg_1to2_id) == status.HTTP_404_NOT_FOUND
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_reset_memory_store_should_clear_specified_mailbox_only(app: TestClient):
|
|
76
|
+
|
|
77
|
+
with temp_env_vars(STORE_MODE="memory"):
|
|
78
|
+
|
|
79
|
+
msg_1to2_id = mesh_api_send_message_and_return_message_id(app, _CANNED_MAILBOX1, _CANNED_MAILBOX2)
|
|
80
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX2) == 1
|
|
81
|
+
|
|
82
|
+
res = mesh_api_track_message_by_message_id(app, _CANNED_MAILBOX1, msg_1to2_id)
|
|
83
|
+
assert res.json()["messageId"] == msg_1to2_id
|
|
84
|
+
|
|
85
|
+
msg_2to1_id = mesh_api_send_message_and_return_message_id(app, _CANNED_MAILBOX2, _CANNED_MAILBOX1)
|
|
86
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX1) == 1
|
|
87
|
+
|
|
88
|
+
res = mesh_api_track_message_by_message_id(app, _CANNED_MAILBOX2, msg_2to1_id)
|
|
89
|
+
assert res.json()["messageId"] == msg_2to1_id
|
|
90
|
+
|
|
91
|
+
res = app.get(f"/messageexchange/reset/{_CANNED_MAILBOX2}")
|
|
92
|
+
assert res.status_code == status.HTTP_200_OK
|
|
93
|
+
|
|
94
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX2) == 0
|
|
95
|
+
assert (
|
|
96
|
+
mesh_api_track_message_by_message_id_status(app, _CANNED_MAILBOX2, msg_2to1_id) == status.HTTP_404_NOT_FOUND
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX1) == 1
|
|
100
|
+
assert mesh_api_track_message_by_message_id_status(app, _CANNED_MAILBOX1, msg_1to2_id) == status.HTTP_200_OK
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@pytest.mark.parametrize("clear_disk", ["tRue", "faLse", None])
|
|
104
|
+
def test_reset_file_store_should_clear_all_mailboxes_and_maybe_files(app: TestClient, clear_disk: str, tmp_path: str):
|
|
105
|
+
|
|
106
|
+
with temp_env_vars(STORE_MODE="file", FILE_STORE_DIR=tmp_path):
|
|
107
|
+
|
|
108
|
+
msg_1to2_id = mesh_api_send_message_and_return_message_id(app, _CANNED_MAILBOX1, _CANNED_MAILBOX2)
|
|
109
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX2) == 1
|
|
110
|
+
|
|
111
|
+
msg_2to1_id = mesh_api_send_message_and_return_message_id(app, _CANNED_MAILBOX2, _CANNED_MAILBOX1)
|
|
112
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX1) == 1
|
|
113
|
+
|
|
114
|
+
inbox_folder1 = os.path.join(tmp_path, _CANNED_MAILBOX1, "in")
|
|
115
|
+
assert os.path.exists(inbox_folder1)
|
|
116
|
+
messages = os.listdir(inbox_folder1)
|
|
117
|
+
assert len(messages) == 1
|
|
118
|
+
assert messages[0] == msg_2to1_id
|
|
119
|
+
|
|
120
|
+
inbox_folder2 = os.path.join(tmp_path, _CANNED_MAILBOX2, "in")
|
|
121
|
+
assert os.path.exists(inbox_folder2)
|
|
122
|
+
messages = os.listdir(inbox_folder2)
|
|
123
|
+
assert len(messages) == 1
|
|
124
|
+
assert messages[0] == msg_1to2_id
|
|
125
|
+
|
|
126
|
+
clear_disk_param = "" if clear_disk is None else f"?clear_disk={clear_disk}"
|
|
127
|
+
res = app.get(f"/messageexchange/reset{clear_disk_param}")
|
|
128
|
+
assert res.status_code == status.HTTP_200_OK
|
|
129
|
+
|
|
130
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX1) == 0
|
|
131
|
+
assert (
|
|
132
|
+
mesh_api_track_message_by_message_id_status(app, _CANNED_MAILBOX1, msg_1to2_id) == status.HTTP_404_NOT_FOUND
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX2) == 0
|
|
136
|
+
assert (
|
|
137
|
+
mesh_api_track_message_by_message_id_status(app, _CANNED_MAILBOX2, msg_2to1_id) == status.HTTP_404_NOT_FOUND
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# clear_disk should default to true if file mode is used
|
|
141
|
+
if not clear_disk or clear_disk == "tRue":
|
|
142
|
+
assert not os.path.exists(inbox_folder1)
|
|
143
|
+
assert not os.path.exists(inbox_folder2)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@pytest.mark.parametrize("clear_disk", ["tRue", "faLse", None])
|
|
147
|
+
def test_reset_file_store_should_clear_specified_mailbox_only_and_maybe_files(
|
|
148
|
+
app: TestClient, clear_disk: str, tmp_path: str
|
|
149
|
+
):
|
|
150
|
+
|
|
151
|
+
with temp_env_vars(STORE_MODE="file", FILE_STORE_DIR=tmp_path):
|
|
152
|
+
|
|
153
|
+
msg_1to2_id = mesh_api_send_message_and_return_message_id(app, _CANNED_MAILBOX1, _CANNED_MAILBOX2)
|
|
154
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX2) == 1
|
|
155
|
+
|
|
156
|
+
msg_2to1_id = mesh_api_send_message_and_return_message_id(app, _CANNED_MAILBOX2, _CANNED_MAILBOX1)
|
|
157
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX1) == 1
|
|
158
|
+
|
|
159
|
+
inbox_folder1 = os.path.join(tmp_path, _CANNED_MAILBOX1, "in")
|
|
160
|
+
assert os.path.exists(inbox_folder1)
|
|
161
|
+
messages = os.listdir(inbox_folder1)
|
|
162
|
+
assert len(messages) == 1
|
|
163
|
+
assert messages[0] == msg_2to1_id
|
|
164
|
+
|
|
165
|
+
inbox_folder2 = os.path.join(tmp_path, _CANNED_MAILBOX2, "in")
|
|
166
|
+
assert os.path.exists(inbox_folder2)
|
|
167
|
+
messages = os.listdir(inbox_folder2)
|
|
168
|
+
assert len(messages) == 1
|
|
169
|
+
assert messages[0] == msg_1to2_id
|
|
170
|
+
|
|
171
|
+
clear_disk_param = "" if clear_disk is None else f"?clear_disk={clear_disk}"
|
|
172
|
+
res = app.get(f"/messageexchange/reset/{_CANNED_MAILBOX2}{clear_disk_param}")
|
|
173
|
+
assert res.status_code == status.HTTP_200_OK
|
|
174
|
+
|
|
175
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX1) == 1
|
|
176
|
+
assert mesh_api_track_message_by_message_id_status(app, _CANNED_MAILBOX1, msg_1to2_id) == status.HTTP_200_OK
|
|
177
|
+
|
|
178
|
+
assert mesh_api_get_inbox_size(app, _CANNED_MAILBOX2) == 0
|
|
179
|
+
assert (
|
|
180
|
+
mesh_api_track_message_by_message_id_status(app, _CANNED_MAILBOX2, msg_2to1_id) == status.HTTP_404_NOT_FOUND
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# clear_disk should default to true if file mode is used
|
|
184
|
+
if not clear_disk or clear_disk == "tRue":
|
|
185
|
+
assert os.path.exists(inbox_folder1)
|
|
186
|
+
assert not os.path.exists(inbox_folder2)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@pytest.mark.parametrize("clear_disk", ["tRue", "faLse", None])
|
|
190
|
+
def test_reset_file_store_should_not_error_if_folder_does_not_exist_yet(
|
|
191
|
+
app: TestClient, clear_disk: str, tmp_path: str
|
|
192
|
+
):
|
|
193
|
+
|
|
194
|
+
with temp_env_vars(STORE_MODE="file", FILE_STORE_DIR=tmp_path):
|
|
195
|
+
|
|
196
|
+
inbox_folder = os.path.join(tmp_path, _CANNED_MAILBOX1, "in")
|
|
197
|
+
assert not os.path.exists(inbox_folder)
|
|
198
|
+
|
|
199
|
+
clear_disk_param = "" if clear_disk is None else f"?clear_disk={clear_disk}"
|
|
200
|
+
res = app.get(f"/messageexchange/reset/{_CANNED_MAILBOX2}{clear_disk_param}")
|
|
201
|
+
assert res.status_code == status.HTTP_200_OK
|
mesh_sandbox/tests/helpers.py
CHANGED
|
@@ -8,11 +8,9 @@ from typing import Optional
|
|
|
8
8
|
from uuid import uuid4
|
|
9
9
|
|
|
10
10
|
import httpx
|
|
11
|
-
from fastapi.testclient import TestClient
|
|
12
11
|
from OpenSSL import crypto
|
|
13
12
|
|
|
14
13
|
from ..common import MESH_AUTH_SCHEME, generate_cipher_text
|
|
15
|
-
from ..common.constants import Headers
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
def generate_auth_token(
|
|
@@ -49,37 +47,6 @@ def temp_env_vars(**kwargs):
|
|
|
49
47
|
os.environ.update(old_environ)
|
|
50
48
|
|
|
51
49
|
|
|
52
|
-
def send_message(
|
|
53
|
-
app: TestClient,
|
|
54
|
-
sender_mailbox_id: str,
|
|
55
|
-
recipient_mailbox_id: str,
|
|
56
|
-
workflow_id: Optional[str] = None,
|
|
57
|
-
message_data: Optional[bytes] = None,
|
|
58
|
-
extra_headers: Optional[dict] = None,
|
|
59
|
-
test_empty_payload: bool = False,
|
|
60
|
-
file_name: Optional[str] = None,
|
|
61
|
-
):
|
|
62
|
-
|
|
63
|
-
if not test_empty_payload:
|
|
64
|
-
message_data = message_data or f"Hello World!\n{uuid4().hex}".encode("utf-8")
|
|
65
|
-
|
|
66
|
-
headers = {
|
|
67
|
-
Headers.Mex_From: sender_mailbox_id,
|
|
68
|
-
Headers.Mex_To: recipient_mailbox_id,
|
|
69
|
-
Headers.Mex_WorkflowID: workflow_id or "TEST_WORKFLOW",
|
|
70
|
-
Headers.Authorization: generate_auth_token(sender_mailbox_id),
|
|
71
|
-
}
|
|
72
|
-
if file_name:
|
|
73
|
-
headers[Headers.Mex_FileName] = file_name
|
|
74
|
-
|
|
75
|
-
if extra_headers:
|
|
76
|
-
headers.update(extra_headers)
|
|
77
|
-
|
|
78
|
-
response = app.post(f"/messageexchange/{sender_mailbox_id}/outbox", headers=headers, data=message_data)
|
|
79
|
-
|
|
80
|
-
return response
|
|
81
|
-
|
|
82
|
-
|
|
83
50
|
def ensure_client_installed(java_path: str, base_dir: str, version: str): # pylint: disable=too-many-locals
|
|
84
51
|
|
|
85
52
|
install_dir = os.path.join(base_dir, version)
|
mesh_sandbox/tests/inbox.py
CHANGED
|
@@ -4,10 +4,12 @@ import pytest
|
|
|
4
4
|
from fastapi import status
|
|
5
5
|
from fastapi.testclient import TestClient
|
|
6
6
|
|
|
7
|
+
from mesh_sandbox.tests.mesh_api_helpers import mesh_api_send_message
|
|
8
|
+
|
|
7
9
|
from ..common import APP_V1_JSON, APP_V2_JSON
|
|
8
10
|
from ..common.constants import Headers
|
|
9
11
|
from ..models.message import MessageStatus
|
|
10
|
-
from .helpers import generate_auth_token,
|
|
12
|
+
from .helpers import generate_auth_token, temp_env_vars
|
|
11
13
|
|
|
12
14
|
_CANNED_MAILBOX1 = "X26ABC1"
|
|
13
15
|
_CANNED_MAILBOX2 = "X26ABC2"
|
|
@@ -39,12 +41,12 @@ def test_inbox_count(app: TestClient, accept: str):
|
|
|
39
41
|
|
|
40
42
|
message_body = f"test{uuid4().hex}".encode()
|
|
41
43
|
|
|
42
|
-
resp =
|
|
44
|
+
resp = mesh_api_send_message(
|
|
43
45
|
app,
|
|
44
46
|
sender_mailbox_id=sender,
|
|
45
47
|
recipient_mailbox_id=recipient,
|
|
46
|
-
workflow_id=workflow_id,
|
|
47
48
|
message_data=message_body,
|
|
49
|
+
workflow_id=workflow_id,
|
|
48
50
|
extra_headers={Headers.Accept: accept, Headers.Mex_LocalID: local_id},
|
|
49
51
|
)
|
|
50
52
|
|
|
@@ -78,7 +80,7 @@ def test_paginated_inbox_outbox(app: TestClient, accept: str):
|
|
|
78
80
|
message_ids = []
|
|
79
81
|
for _ in range(page_size * 3):
|
|
80
82
|
|
|
81
|
-
resp =
|
|
83
|
+
resp = mesh_api_send_message(
|
|
82
84
|
app,
|
|
83
85
|
sender_mailbox_id=sender,
|
|
84
86
|
recipient_mailbox_id=recipient,
|
|
@@ -259,3 +261,60 @@ def test_receive_canned_undelivered_message(app: TestClient, accept: str):
|
|
|
259
261
|
result = res.json()
|
|
260
262
|
expected = MessageStatus.UNDELIVERABLE.title() if accept == APP_V1_JSON else MessageStatus.UNDELIVERABLE
|
|
261
263
|
assert result["status"] == expected
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def test_rich_inbox_includes_acknowledged_messages(app: TestClient):
|
|
267
|
+
|
|
268
|
+
sender = _CANNED_MAILBOX1
|
|
269
|
+
recipient = _CANNED_MAILBOX2
|
|
270
|
+
|
|
271
|
+
res = app.get(
|
|
272
|
+
f"/messageexchange/{recipient}/inbox",
|
|
273
|
+
headers={Headers.Authorization: generate_auth_token(recipient)},
|
|
274
|
+
)
|
|
275
|
+
assert res.json()["messages"] == []
|
|
276
|
+
|
|
277
|
+
acknowledged_message_id = ""
|
|
278
|
+
message_ids = []
|
|
279
|
+
for index in range(5):
|
|
280
|
+
|
|
281
|
+
resp = mesh_api_send_message(
|
|
282
|
+
app,
|
|
283
|
+
sender_mailbox_id=sender,
|
|
284
|
+
recipient_mailbox_id=recipient,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
assert resp.status_code == status.HTTP_202_ACCEPTED
|
|
288
|
+
result = resp.json()
|
|
289
|
+
message_id = result["messageID"]
|
|
290
|
+
assert message_id
|
|
291
|
+
message_ids.append(message_id)
|
|
292
|
+
|
|
293
|
+
if index == 2:
|
|
294
|
+
ack_response = app.put(
|
|
295
|
+
f"/messageexchange/{recipient}/inbox/{message_id}/status/acknowledged",
|
|
296
|
+
headers={Headers.Authorization: generate_auth_token(recipient)},
|
|
297
|
+
)
|
|
298
|
+
assert ack_response.status_code == status.HTTP_200_OK
|
|
299
|
+
assert message_id in ack_response.text
|
|
300
|
+
acknowledged_message_id = message_id
|
|
301
|
+
|
|
302
|
+
# inbox
|
|
303
|
+
res = app.get(
|
|
304
|
+
f"/messageexchange/{recipient}/inbox",
|
|
305
|
+
headers={Headers.Authorization: generate_auth_token(recipient)},
|
|
306
|
+
)
|
|
307
|
+
assert res.status_code == status.HTTP_200_OK
|
|
308
|
+
messages = res.json().get("messages", [])
|
|
309
|
+
assert len(messages) == 4
|
|
310
|
+
assert acknowledged_message_id not in messages
|
|
311
|
+
|
|
312
|
+
# rich inbox
|
|
313
|
+
res = app.get(
|
|
314
|
+
f"/messageexchange/{recipient}/inbox/rich",
|
|
315
|
+
headers={Headers.Authorization: generate_auth_token(recipient)},
|
|
316
|
+
)
|
|
317
|
+
assert res.status_code == status.HTTP_200_OK
|
|
318
|
+
messages = res.json().get("messages", [])
|
|
319
|
+
assert len(messages) == 5
|
|
320
|
+
assert acknowledged_message_id in [m["message_id"] for m in messages]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
|
|
4
|
+
from fastapi.testclient import TestClient
|
|
5
|
+
|
|
6
|
+
from mesh_sandbox.tests.helpers import generate_auth_token
|
|
7
|
+
|
|
8
|
+
from ..common.constants import Headers
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def mesh_api_send_message(
|
|
12
|
+
app: TestClient,
|
|
13
|
+
sender_mailbox_id: str,
|
|
14
|
+
recipient_mailbox_id: str,
|
|
15
|
+
message_data: Optional[bytes] = None,
|
|
16
|
+
workflow_id: Optional[str] = None,
|
|
17
|
+
extra_headers: Optional[dict] = None,
|
|
18
|
+
test_empty_message_data: bool = False,
|
|
19
|
+
file_name: Optional[str] = None,
|
|
20
|
+
):
|
|
21
|
+
|
|
22
|
+
if not test_empty_message_data:
|
|
23
|
+
message_data = message_data or f"Hello World!\n{uuid4().hex}".encode("utf-8")
|
|
24
|
+
|
|
25
|
+
headers = {
|
|
26
|
+
Headers.Mex_From: sender_mailbox_id,
|
|
27
|
+
Headers.Mex_To: recipient_mailbox_id,
|
|
28
|
+
Headers.Mex_WorkflowID: workflow_id or "TEST_WORKFLOW",
|
|
29
|
+
Headers.Authorization: generate_auth_token(sender_mailbox_id),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if file_name:
|
|
33
|
+
headers[Headers.Mex_FileName] = file_name
|
|
34
|
+
|
|
35
|
+
if extra_headers:
|
|
36
|
+
headers.update(extra_headers)
|
|
37
|
+
|
|
38
|
+
return app.post(f"/messageexchange/{sender_mailbox_id}/outbox", headers=headers, data=message_data)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def mesh_api_send_message_and_return_message_id(
|
|
42
|
+
app: TestClient,
|
|
43
|
+
sender_mailbox_id: str,
|
|
44
|
+
recipient_mailbox_id: str,
|
|
45
|
+
message_data: Optional[bytes] = None,
|
|
46
|
+
workflow_id: Optional[str] = None,
|
|
47
|
+
extra_headers: Optional[dict] = None,
|
|
48
|
+
test_empty_message_data: bool = False,
|
|
49
|
+
file_name: Optional[str] = None,
|
|
50
|
+
):
|
|
51
|
+
|
|
52
|
+
res = mesh_api_send_message(
|
|
53
|
+
app,
|
|
54
|
+
sender_mailbox_id,
|
|
55
|
+
recipient_mailbox_id,
|
|
56
|
+
message_data,
|
|
57
|
+
workflow_id,
|
|
58
|
+
extra_headers,
|
|
59
|
+
test_empty_message_data,
|
|
60
|
+
file_name,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
assert res.status_code == 202, res.text
|
|
64
|
+
return res.json()["messageID"]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def mesh_api_get_message(
|
|
68
|
+
app: TestClient,
|
|
69
|
+
recipient_mailbox_id: str,
|
|
70
|
+
message_id: str,
|
|
71
|
+
extra_headers: Optional[dict] = None,
|
|
72
|
+
):
|
|
73
|
+
|
|
74
|
+
headers = {Headers.Authorization: generate_auth_token(recipient_mailbox_id)}
|
|
75
|
+
if extra_headers:
|
|
76
|
+
headers.update(extra_headers)
|
|
77
|
+
|
|
78
|
+
return app.get(url=f"/messageexchange/{recipient_mailbox_id}/inbox/{message_id}", headers=headers)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def mesh_api_get_inbox(
|
|
82
|
+
app: TestClient,
|
|
83
|
+
recipient_mailbox_id: str,
|
|
84
|
+
extra_headers: Optional[dict] = None,
|
|
85
|
+
):
|
|
86
|
+
|
|
87
|
+
headers = {Headers.Authorization: generate_auth_token(recipient_mailbox_id)}
|
|
88
|
+
if extra_headers:
|
|
89
|
+
headers.update(extra_headers)
|
|
90
|
+
|
|
91
|
+
return app.get(url=f"/messageexchange/{recipient_mailbox_id}/inbox", headers=headers)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def mesh_api_get_inbox_size(
|
|
95
|
+
app: TestClient,
|
|
96
|
+
recipient_mailbox_id: str,
|
|
97
|
+
extra_headers: Optional[dict] = None,
|
|
98
|
+
):
|
|
99
|
+
res = mesh_api_get_inbox(app, recipient_mailbox_id, extra_headers=extra_headers)
|
|
100
|
+
assert res.status_code == 200
|
|
101
|
+
return len(res.json()["messages"])
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def mesh_api_track_message_by_local_id(
|
|
105
|
+
app: TestClient, sender_mailbox_id: str, local_id: str, extra_headers: Optional[dict] = None
|
|
106
|
+
):
|
|
107
|
+
|
|
108
|
+
headers = {Headers.Authorization: generate_auth_token(sender_mailbox_id)}
|
|
109
|
+
if extra_headers:
|
|
110
|
+
headers.update(extra_headers)
|
|
111
|
+
|
|
112
|
+
return app.get(f"/messageexchange/{sender_mailbox_id}/outbox/tracking?localID={local_id}", headers=headers)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def mesh_api_track_message_by_message_id(
|
|
116
|
+
app: TestClient, sender_mailbox_id: str, message_id: str, extra_headers: Optional[dict] = None
|
|
117
|
+
):
|
|
118
|
+
|
|
119
|
+
headers = {Headers.Authorization: generate_auth_token(sender_mailbox_id)}
|
|
120
|
+
if extra_headers:
|
|
121
|
+
headers.update(extra_headers)
|
|
122
|
+
|
|
123
|
+
res = app.get(f"/messageexchange/{sender_mailbox_id}/outbox/tracking?messageID={message_id}", headers=headers)
|
|
124
|
+
return res
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def mesh_api_track_message_by_message_id_status(
|
|
128
|
+
app: TestClient, sender_mailbox_id: str, message_id: str, extra_headers: Optional[dict] = None
|
|
129
|
+
):
|
|
130
|
+
|
|
131
|
+
res = mesh_api_track_message_by_message_id(app, sender_mailbox_id, message_id, extra_headers=extra_headers)
|
|
132
|
+
return res.status_code
|
|
@@ -14,7 +14,22 @@ from mesh_sandbox.tests.docker_tests import (
|
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def
|
|
17
|
+
def _mesh_client_send_message(
|
|
18
|
+
base_uri: str,
|
|
19
|
+
sender_mailbox_id: str,
|
|
20
|
+
recipient_mailbox_id: str,
|
|
21
|
+
workflow_id: str,
|
|
22
|
+
payload: bytes,
|
|
23
|
+
):
|
|
24
|
+
with MeshClient(
|
|
25
|
+
url=base_uri, mailbox=sender_mailbox_id, password=_PASSWORD, shared_key=_SHARED_KEY, max_chunk_size=100
|
|
26
|
+
) as sender:
|
|
27
|
+
message_id = sender.send_message(recipient_mailbox_id, payload, workflow_id=workflow_id)
|
|
28
|
+
assert message_id
|
|
29
|
+
return message_id
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _mesh_client_get_inbox_count(base_uri: str, recipient_mailbox_id: str):
|
|
18
33
|
with MeshClient(
|
|
19
34
|
url=base_uri, mailbox=recipient_mailbox_id, password=_PASSWORD, shared_key=_SHARED_KEY
|
|
20
35
|
) as recipient:
|
|
@@ -22,19 +37,13 @@ def _get_inbox_count(base_uri: str, recipient_mailbox_id: str):
|
|
|
22
37
|
return len(message_ids)
|
|
23
38
|
|
|
24
39
|
|
|
25
|
-
def
|
|
26
|
-
base_uri: str, recipient_mailbox_id: str, workflow_id: str, payload: bytes
|
|
27
|
-
):
|
|
28
|
-
sender_mailbox_id = _CANNED_MAILBOX1
|
|
29
|
-
|
|
40
|
+
def _mesh_client_track_message_by_message_id(base_uri: str, sender_mailbox_id: str, message_id: str):
|
|
30
41
|
with MeshClient(
|
|
31
42
|
url=base_uri, mailbox=sender_mailbox_id, password=_PASSWORD, shared_key=_SHARED_KEY, max_chunk_size=100
|
|
32
43
|
) as sender:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
assert _get_inbox_count(base_uri, _CANNED_MAILBOX2) == 1
|
|
37
|
-
return message_id
|
|
44
|
+
tracking = sender.track_by_message_id(message_id)
|
|
45
|
+
assert tracking
|
|
46
|
+
return tracking
|
|
38
47
|
|
|
39
48
|
|
|
40
49
|
def test_app_health(base_uri: str):
|
|
@@ -62,14 +71,12 @@ def test_handshake_bad_password(base_uri: str):
|
|
|
62
71
|
|
|
63
72
|
def test_send_receive_chunked_message(base_uri: str):
|
|
64
73
|
|
|
65
|
-
recipient_mailbox_id = _CANNED_MAILBOX2
|
|
66
74
|
workflow_id = uuid4().hex
|
|
67
75
|
sent_payload = b"a" * 1000
|
|
68
|
-
message_id =
|
|
76
|
+
message_id = _mesh_client_send_message(base_uri, _CANNED_MAILBOX1, _CANNED_MAILBOX2, workflow_id, sent_payload)
|
|
77
|
+
assert _mesh_client_get_inbox_count(base_uri, _CANNED_MAILBOX2) == 1
|
|
69
78
|
|
|
70
|
-
with MeshClient(
|
|
71
|
-
url=base_uri, mailbox=recipient_mailbox_id, password=_PASSWORD, shared_key=_SHARED_KEY
|
|
72
|
-
) as recipient:
|
|
79
|
+
with MeshClient(url=base_uri, mailbox=_CANNED_MAILBOX2, password=_PASSWORD, shared_key=_SHARED_KEY) as recipient:
|
|
73
80
|
message_ids = recipient.list_messages()
|
|
74
81
|
assert message_ids == [message_id]
|
|
75
82
|
message = recipient.retrieve_message(message_id)
|
|
@@ -80,3 +87,25 @@ def test_send_receive_chunked_message(base_uri: str):
|
|
|
80
87
|
message.acknowledge()
|
|
81
88
|
message_ids = recipient.list_messages()
|
|
82
89
|
assert message_ids == []
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_track_message_by_message_id(base_uri: str):
|
|
93
|
+
|
|
94
|
+
workflow_id = uuid4().hex
|
|
95
|
+
sent_payload = b"a" * 1000
|
|
96
|
+
message_id = _mesh_client_send_message(base_uri, _CANNED_MAILBOX1, _CANNED_MAILBOX2, workflow_id, sent_payload)
|
|
97
|
+
assert _mesh_client_get_inbox_count(base_uri, _CANNED_MAILBOX2) == 1
|
|
98
|
+
|
|
99
|
+
tracking = _mesh_client_track_message_by_message_id(base_uri, _CANNED_MAILBOX1, message_id)
|
|
100
|
+
assert tracking["messageId"] == message_id
|
|
101
|
+
assert tracking["status"] == "Accepted"
|
|
102
|
+
assert tracking["sender"] == _CANNED_MAILBOX1
|
|
103
|
+
assert tracking["recipient"] == _CANNED_MAILBOX2
|
|
104
|
+
|
|
105
|
+
with MeshClient(url=base_uri, mailbox=_CANNED_MAILBOX2, password=_PASSWORD, shared_key=_SHARED_KEY) as recipient:
|
|
106
|
+
message = recipient.retrieve_message(message_id)
|
|
107
|
+
message.acknowledge()
|
|
108
|
+
|
|
109
|
+
tracking = _mesh_client_track_message_by_message_id(base_uri, _CANNED_MAILBOX1, message_id)
|
|
110
|
+
assert tracking["messageId"] == message_id
|
|
111
|
+
assert tracking["status"] == "Acknowledged"
|
mesh_sandbox/tests/outbox.py
CHANGED
|
@@ -5,10 +5,12 @@ import pytest
|
|
|
5
5
|
from fastapi import status
|
|
6
6
|
from fastapi.testclient import TestClient
|
|
7
7
|
|
|
8
|
+
from mesh_sandbox.tests.mesh_api_helpers import mesh_api_send_message
|
|
9
|
+
|
|
8
10
|
from ..common import APP_V1_JSON, APP_V2_JSON
|
|
9
11
|
from ..common.constants import Headers
|
|
10
12
|
from ..models.message import MessageStatus
|
|
11
|
-
from .helpers import generate_auth_token,
|
|
13
|
+
from .helpers import generate_auth_token, temp_env_vars
|
|
12
14
|
|
|
13
15
|
_CANNED_MAILBOX1 = "X26ABC1"
|
|
14
16
|
_CANNED_MAILBOX2 = "X26ABC2"
|
|
@@ -33,12 +35,12 @@ def test_memory_send_message_with_local_id(app: TestClient, accept: str):
|
|
|
33
35
|
|
|
34
36
|
message_body = f"test{uuid4().hex}".encode()
|
|
35
37
|
|
|
36
|
-
resp =
|
|
38
|
+
resp = mesh_api_send_message(
|
|
37
39
|
app,
|
|
38
40
|
sender_mailbox_id=sender,
|
|
39
41
|
recipient_mailbox_id=recipient,
|
|
40
|
-
workflow_id=workflow_id,
|
|
41
42
|
message_data=message_body,
|
|
43
|
+
workflow_id=workflow_id,
|
|
42
44
|
extra_headers={Headers.Accept: accept, Headers.Mex_LocalID: local_id},
|
|
43
45
|
)
|
|
44
46
|
|
|
@@ -146,12 +148,12 @@ def test_file_send_message_with_local_id(app: TestClient, accept: str, tmp_path:
|
|
|
146
148
|
|
|
147
149
|
message_body = f"test{uuid4().hex}".encode()
|
|
148
150
|
|
|
149
|
-
resp =
|
|
151
|
+
resp = mesh_api_send_message(
|
|
150
152
|
app,
|
|
151
153
|
sender_mailbox_id=sender,
|
|
152
154
|
recipient_mailbox_id=recipient,
|
|
153
|
-
workflow_id=workflow_id,
|
|
154
155
|
message_data=message_body,
|
|
156
|
+
workflow_id=workflow_id,
|
|
155
157
|
extra_headers={Headers.Accept: accept},
|
|
156
158
|
)
|
|
157
159
|
|
|
@@ -208,12 +210,12 @@ def test_memory_send_chunked_message(app: TestClient, accept: str):
|
|
|
208
210
|
|
|
209
211
|
workflow_id = "TEST_WORKFLOW"
|
|
210
212
|
|
|
211
|
-
resp =
|
|
213
|
+
resp = mesh_api_send_message(
|
|
212
214
|
app,
|
|
213
215
|
sender_mailbox_id=sender,
|
|
214
216
|
recipient_mailbox_id=recipient,
|
|
215
|
-
workflow_id=workflow_id,
|
|
216
217
|
message_data=chunk_1,
|
|
218
|
+
workflow_id=workflow_id,
|
|
217
219
|
extra_headers={Headers.Accept: accept, Headers.Mex_Chunk_Range: "1:2"},
|
|
218
220
|
)
|
|
219
221
|
|
|
@@ -330,12 +332,12 @@ def test_file_send_chunked_message(app: TestClient, accept: str, tmp_path: str):
|
|
|
330
332
|
|
|
331
333
|
workflow_id = "TEST_WORKFLOW"
|
|
332
334
|
|
|
333
|
-
resp =
|
|
335
|
+
resp = mesh_api_send_message(
|
|
334
336
|
app,
|
|
335
337
|
sender_mailbox_id=sender,
|
|
336
338
|
recipient_mailbox_id=recipient,
|
|
337
|
-
workflow_id=workflow_id,
|
|
338
339
|
message_data=chunk_1,
|
|
340
|
+
workflow_id=workflow_id,
|
|
339
341
|
extra_headers={Headers.Accept: accept, Headers.Mex_Chunk_Range: "1:2"},
|
|
340
342
|
)
|
|
341
343
|
|
|
@@ -464,7 +466,7 @@ def test_mex_content_compress_validation(app: TestClient, value: str):
|
|
|
464
466
|
sender = _CANNED_MAILBOX1
|
|
465
467
|
recipient = _CANNED_MAILBOX2
|
|
466
468
|
|
|
467
|
-
response =
|
|
469
|
+
response = mesh_api_send_message(app, sender, recipient, extra_headers={Headers.Mex_Content_Compress: value})
|
|
468
470
|
|
|
469
471
|
assert response.status_code == status.HTTP_202_ACCEPTED
|
|
470
472
|
|
|
@@ -502,7 +504,7 @@ def test_mex_content_encrypted_validation(app: TestClient, value: str):
|
|
|
502
504
|
sender = _CANNED_MAILBOX1
|
|
503
505
|
recipient = _CANNED_MAILBOX2
|
|
504
506
|
|
|
505
|
-
response =
|
|
507
|
+
response = mesh_api_send_message(app, sender, recipient, extra_headers={Headers.Mex_Content_Encrypted: value})
|
|
506
508
|
|
|
507
509
|
assert response.status_code == status.HTTP_202_ACCEPTED
|
|
508
510
|
|
|
@@ -540,7 +542,7 @@ def test_mex_content_compressed_validation(app: TestClient, value: str):
|
|
|
540
542
|
sender = _CANNED_MAILBOX1
|
|
541
543
|
recipient = _CANNED_MAILBOX2
|
|
542
544
|
|
|
543
|
-
response =
|
|
545
|
+
response = mesh_api_send_message(app, sender, recipient, extra_headers={Headers.Mex_Content_Compressed: value})
|
|
544
546
|
assert response.status_code == status.HTTP_202_ACCEPTED
|
|
545
547
|
|
|
546
548
|
|
|
@@ -561,7 +563,9 @@ def test_mex_content_checksum_validation(app: TestClient, mex_content_checksum:
|
|
|
561
563
|
sender = _CANNED_MAILBOX1
|
|
562
564
|
recipient = _CANNED_MAILBOX2
|
|
563
565
|
|
|
564
|
-
response =
|
|
566
|
+
response = mesh_api_send_message(
|
|
567
|
+
app, sender, recipient, extra_headers={Headers.Mex_Content_Checksum: mex_content_checksum}
|
|
568
|
+
)
|
|
565
569
|
|
|
566
570
|
assert response.status_code == expected_response_status
|
|
567
571
|
|
|
@@ -571,7 +575,7 @@ def test_mex_local_id_validation(app: TestClient):
|
|
|
571
575
|
sender = _CANNED_MAILBOX1
|
|
572
576
|
recipient = _CANNED_MAILBOX2
|
|
573
577
|
|
|
574
|
-
response =
|
|
578
|
+
response = mesh_api_send_message(
|
|
575
579
|
app, sender, recipient, extra_headers={Headers.Mex_LocalID: "test#TEST", Headers.Mex_WorkflowID: "test TEST"}
|
|
576
580
|
)
|
|
577
581
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
mesh_sandbox/__init__.py,sha256=
|
|
2
|
-
mesh_sandbox/api.py,sha256=
|
|
1
|
+
mesh_sandbox/__init__.py,sha256=yF88-8vL8keLe6gCTumymw0UoMkWkSrJnzLru4zBCLQ,23
|
|
2
|
+
mesh_sandbox/api.py,sha256=F2KUKENAsSe6NAGG0wzHA2jebGF6mWFgta1q55oqacU,3925
|
|
3
3
|
mesh_sandbox/common/__init__.py,sha256=B0eGgN6SGCvNIsalhQOXhFJvxZaE4wJS_ratFOMMwvI,3071
|
|
4
4
|
mesh_sandbox/common/constants.py,sha256=_hnaHDkAQGHWLF7n_WfC5ZHIY5D-fUbOdpSqLusUMNY,6504
|
|
5
5
|
mesh_sandbox/common/exceptions.py,sha256=YQII8w6DQQoKuW0cukEr6PIE9j0rwrqDpCn5lapgmkQ,1481
|
|
@@ -10,46 +10,47 @@ mesh_sandbox/conftest.py,sha256=Bd-soyJTgtNAhC_LOH0vFNuE5bK9mPW1uYPglxL2Ox4,2186
|
|
|
10
10
|
mesh_sandbox/dependencies.py,sha256=f23B71zqz4gAyQHdlw-9bFpWrQk373BG9zZrHY2wnd4,3264
|
|
11
11
|
mesh_sandbox/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
mesh_sandbox/handlers/handshake.py,sha256=p3_NveSscNBgCdIIJhBza34b0WreqgBxZwI2sw7ZMTk,605
|
|
13
|
-
mesh_sandbox/handlers/inbox.py,sha256=
|
|
13
|
+
mesh_sandbox/handlers/inbox.py,sha256=FH6jEl1vgHD07ttFJqUbarOzumfVJNv-hi0QziIfxl0,15227
|
|
14
14
|
mesh_sandbox/handlers/lookup.py,sha256=hqZBjp-Bwg4Jrx71BfKE3ET2AO6x8XXsbl81tLYoshM,1471
|
|
15
15
|
mesh_sandbox/handlers/outbox.py,sha256=wRBTquvOBLYHhvnvXc07DvSpPEdWy7nCu3zvrXrhjbM,9426
|
|
16
|
-
mesh_sandbox/handlers/reset.py,sha256
|
|
17
|
-
mesh_sandbox/handlers/tracking.py,sha256=
|
|
16
|
+
mesh_sandbox/handlers/reset.py,sha256=Mxnsrc273B2B3HvkX3R8Ij7Sl4HW05rj6__XLqG-K48,829
|
|
17
|
+
mesh_sandbox/handlers/tracking.py,sha256=yZdb30g8vHRXv5o6AjgNcX6lY_sxlFxzc0_TxYmP_jU,2407
|
|
18
18
|
mesh_sandbox/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
mesh_sandbox/models/mailbox.py,sha256=W1b1R1XjhyiCp30LvTLtQVlxagfxXH8eb0XnNj3D4Dw,993
|
|
20
20
|
mesh_sandbox/models/message.py,sha256=br4U7jxJ8Dxkibal9IA9FAK-Yv1sEtkXVQzPDAFXT08,4875
|
|
21
21
|
mesh_sandbox/models/workflow.py,sha256=T8A1Q729TOUaz1MOa1Ly8oZs_G4769xMZpTYGF0TlO8,518
|
|
22
22
|
mesh_sandbox/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
mesh_sandbox/routers/admin.py,sha256=mLZ81tBi7tRjGgTDqVzCxyu3QUseoxVY7DJqmzmONEo,2463
|
|
23
24
|
mesh_sandbox/routers/handshake.py,sha256=5TVyQ5OrHIe6W3UVpbap-hc5ia669Of6w6F1vgcYjm4,2693
|
|
24
25
|
mesh_sandbox/routers/inbox.py,sha256=wSgXEziugJM2PLlVbmGRvd3Hw5GK2hecwxhWx2ycal4,8787
|
|
25
26
|
mesh_sandbox/routers/inbox_count.py,sha256=_hnBuJJaO-g9F_ddmA6WLaNcYHEAsvyF9TimRVaRBH0,1490
|
|
26
27
|
mesh_sandbox/routers/lookup.py,sha256=ViYK80gp9m9nkiZuQf-nimuuIo_nmYKdUBHEuNcKCLY,2115
|
|
27
28
|
mesh_sandbox/routers/outbox.py,sha256=kuMrJPW9XiwLisquAs2rNqaUG0c9VauCudWPLu43inc,4736
|
|
28
29
|
mesh_sandbox/routers/request_logging.py,sha256=gZaOJ_Mp3QPsmrpxXQ0pOzVGNPKd_RAEjpT3Iz1ImVM,1439
|
|
29
|
-
mesh_sandbox/routers/simple.py,sha256=r7eWvR-Uv0IhlvhsHxRCug5u_cMpStam3RmpkAmCUlM,1795
|
|
30
30
|
mesh_sandbox/routers/tracking.py,sha256=UVIRkMBGD5pI7vgp8l6cnP5VX8OFRDPNb2JHs9q5w58,2210
|
|
31
31
|
mesh_sandbox/routers/update.py,sha256=a9ttmk3levdDcu-ZF7a5EniR35zRMhty8pG2EyzB1po,409
|
|
32
32
|
mesh_sandbox/store/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
mesh_sandbox/store/base.py,sha256=
|
|
34
|
-
mesh_sandbox/store/canned_store.py,sha256=
|
|
33
|
+
mesh_sandbox/store/base.py,sha256=7oRqluFGBIHQ7liLVj42bYIPtSS3luh8MmHTM5Md5a0,5907
|
|
34
|
+
mesh_sandbox/store/canned_store.py,sha256=Prbo78iKc7XgeCJmxKRFK4ZUSj13Su-3pM5WR8TeU0U,7210
|
|
35
35
|
mesh_sandbox/store/data/chunks.jsonl,sha256=sQ6ZfrCGLMRxeukgbdUYC03ScPg3ofgppG7USNu20ek,2612
|
|
36
36
|
mesh_sandbox/store/data/mailboxes.jsonl,sha256=Gar9pfGb3f3v0Tp8ighV31ZQVy5uKtjofSb8NURgGzs,434
|
|
37
37
|
mesh_sandbox/store/data/messages.jsonl,sha256=MtwyUVows8-nrk4uR88cw7uz_CjjxI7wyD7qc0ppBAg,2333
|
|
38
38
|
mesh_sandbox/store/data/workflows.jsonl,sha256=RFvycuqVmEkImeXlFD2wjuJFjt6dw581D_raPWstxpU,292
|
|
39
|
-
mesh_sandbox/store/file_store.py,sha256=
|
|
40
|
-
mesh_sandbox/store/memory_store.py,sha256=
|
|
39
|
+
mesh_sandbox/store/file_store.py,sha256=ljWHpAJ0mab8gNRUXIHto6A5f0wUIaSh1BWk6wPxnJI,2223
|
|
40
|
+
mesh_sandbox/store/memory_store.py,sha256=O0E-szdW7r4XknXOXWPhhqRUS6EYZ8fFObNsb6KKhW4,2523
|
|
41
41
|
mesh_sandbox/store/serialisation.py,sha256=nzBMxGkrHOEQ3Q-zmV0W5bwNhs_Q1JlvLsbqONDAtzo,3585
|
|
42
42
|
mesh_sandbox/tests/__init__.py,sha256=wPjH0Ka1334a0OR9VMUfeYxsr03JqWjHTBnAH_1SB7I,106
|
|
43
|
+
mesh_sandbox/tests/admin.py,sha256=9niKHUrTqRA4XHZ2abXkOx8RvdrPFL8WW7_tH0rND5Q,8261
|
|
43
44
|
mesh_sandbox/tests/docker_tests.py,sha256=nxErB5EDDvewgrgI-YqofsOqo52uYWCPTsk-ggK5axQ,1292
|
|
44
45
|
mesh_sandbox/tests/exceptions.py,sha256=j_jKskVzLAYpyu4qNAEY5ahkbk8Uh2Nc_CGpnpdXjnI,740
|
|
45
46
|
mesh_sandbox/tests/handshake.py,sha256=X-fCbwaEAc8cAvvnniCvt4W4DAV9ItPq7tpIpZkfj6M,6259
|
|
46
|
-
mesh_sandbox/tests/helpers.py,sha256=
|
|
47
|
-
mesh_sandbox/tests/inbox.py,sha256=
|
|
47
|
+
mesh_sandbox/tests/helpers.py,sha256=Cr4FtD3jLGf-jsnDBd39YCLW_6__VdWBTZ2gzySaqmc,6901
|
|
48
|
+
mesh_sandbox/tests/inbox.py,sha256=GLqOC6qlivKpp7qEtcGqv_nECkf2MhP4XwRWbIPC_ks,10412
|
|
48
49
|
mesh_sandbox/tests/java_client_tests.py,sha256=oeg1dG83ZBrgy3rb3-lQ26myAxRu-z-u7T-wigIwAhE,6546
|
|
49
50
|
mesh_sandbox/tests/lookup.py,sha256=wY8x0F415y2um48Lw5kyD4ugMo1vBGKB7cqPdHEaVO4,2768
|
|
50
|
-
mesh_sandbox/tests/
|
|
51
|
-
mesh_sandbox/tests/
|
|
52
|
-
mesh_sandbox/tests/
|
|
51
|
+
mesh_sandbox/tests/mesh_api_helpers.py,sha256=spMQnv0EvOSfBVwnr3yAX2Zq1lOg3cc5X4YkZBKeMpg,3898
|
|
52
|
+
mesh_sandbox/tests/mesh_client_tests.py,sha256=Q_s_U5-NRl4aaX8Tq0diMQdUS-SmPE8nBfc2XjXbV9s,3949
|
|
53
|
+
mesh_sandbox/tests/outbox.py,sha256=x4H7quRre8EZe23_Js4pqF0KCumvtDemS92UuYcan5c,18950
|
|
53
54
|
mesh_sandbox/tests/serialisation.py,sha256=zCoP_fAaTCzZ68HpdKQVZLzUJGpbcHTYjHPM2uTtNWQ,640
|
|
54
55
|
mesh_sandbox/views/__init__.py,sha256=nZkb6_1S8jz8Xl_AayfwjgEZG0JD2dfulfGxjJ5W9Ec,1237
|
|
55
56
|
mesh_sandbox/views/error.py,sha256=9lnUr3P93Vm-nOrBTEuAD6nrSBUvpI6-XqXzILWjgGk,3885
|
|
@@ -57,7 +58,7 @@ mesh_sandbox/views/inbox.py,sha256=gnaD9Csx5BqilVRefQQ_tXmeq80lwcLJfepW005GrkU,5
|
|
|
57
58
|
mesh_sandbox/views/lookup.py,sha256=HHUqZ-Iy22ysC3qaO8Bl5GBQqf_7IiBbe5acyxqS78M,2775
|
|
58
59
|
mesh_sandbox/views/outbox.py,sha256=gd32ClmFn-_sROCBnsPos9SPrkTn9GpY1e4tQ_jWf1g,4883
|
|
59
60
|
mesh_sandbox/views/tracking.py,sha256=UDEHd0DI_iCS5di8r134nh5lY0c9gClb7mdhXA5nMo4,8827
|
|
60
|
-
mesh_sandbox-0.1.
|
|
61
|
-
mesh_sandbox-0.1.
|
|
62
|
-
mesh_sandbox-0.1.
|
|
63
|
-
mesh_sandbox-0.1.
|
|
61
|
+
mesh_sandbox-0.1.16.dist-info/LICENSE,sha256=usgzIvDUpVX5pYZepJTRXQJqIaz0mdd32GuS5a3PFlY,1051
|
|
62
|
+
mesh_sandbox-0.1.16.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
|
|
63
|
+
mesh_sandbox-0.1.16.dist-info/METADATA,sha256=XcDTBhb5A4AYg6o4Ikx_M4-_2_BW8uBoZcUVHOjOmOc,2232
|
|
64
|
+
mesh_sandbox-0.1.16.dist-info/RECORD,,
|
mesh_sandbox/tests/reset.py
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from uuid import uuid4
|
|
3
|
-
|
|
4
|
-
import httpx
|
|
5
|
-
import pytest
|
|
6
|
-
from fastapi import status
|
|
7
|
-
|
|
8
|
-
from mesh_sandbox.tests import _CANNED_MAILBOX2
|
|
9
|
-
from mesh_sandbox.tests.mesh_client_tests import (
|
|
10
|
-
_get_inbox_count,
|
|
11
|
-
_send_message_and_assert_inbox_count_is_one,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
from .helpers import temp_env_vars
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def test_reset_memory_store_should_clear_inbox(base_uri: str):
|
|
18
|
-
|
|
19
|
-
_send_message_and_assert_inbox_count_is_one(base_uri, _CANNED_MAILBOX2, uuid4().hex, b"b" * 10)
|
|
20
|
-
|
|
21
|
-
with temp_env_vars(STORE_MODE="memory"):
|
|
22
|
-
with httpx.Client(base_url=base_uri) as client:
|
|
23
|
-
res = client.get("/messageexchange/reset")
|
|
24
|
-
assert res.status_code == status.HTTP_200_OK
|
|
25
|
-
|
|
26
|
-
assert _get_inbox_count(base_uri, _CANNED_MAILBOX2) == 0
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@pytest.mark.parametrize("clear_disk", ["tRue", "faLse", None])
|
|
30
|
-
def test_reset_file_store_should_clear_inbox_and_maybe_files(base_uri: str, clear_disk: str, tmp_path: str):
|
|
31
|
-
|
|
32
|
-
with temp_env_vars(STORE_MODE="file", FILE_STORE_DIR=tmp_path):
|
|
33
|
-
|
|
34
|
-
message_id = _send_message_and_assert_inbox_count_is_one(base_uri, _CANNED_MAILBOX2, uuid4().hex, b"b" * 10)
|
|
35
|
-
|
|
36
|
-
inbox_folder = os.path.join(tmp_path, _CANNED_MAILBOX2, "in")
|
|
37
|
-
assert os.path.exists(inbox_folder)
|
|
38
|
-
messages = os.listdir(inbox_folder)
|
|
39
|
-
assert len(messages) == 1
|
|
40
|
-
assert messages[0] == message_id
|
|
41
|
-
|
|
42
|
-
with httpx.Client(base_url=base_uri, timeout=60) as client:
|
|
43
|
-
clear_disk_param = "" if clear_disk is None else f"?clear_disk={clear_disk}"
|
|
44
|
-
res = client.get(f"/messageexchange/reset{clear_disk_param}")
|
|
45
|
-
assert res.status_code == status.HTTP_200_OK
|
|
46
|
-
|
|
47
|
-
assert _get_inbox_count(base_uri, _CANNED_MAILBOX2) == 0
|
|
48
|
-
|
|
49
|
-
# clear_disk should default to true if file mode is used
|
|
50
|
-
if not clear_disk or clear_disk == "tRue":
|
|
51
|
-
assert not os.path.exists(inbox_folder)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_reset_canned_store_should_return_bad_request(base_uri: str):
|
|
55
|
-
|
|
56
|
-
with temp_env_vars(STORE_MODE="canned"):
|
|
57
|
-
with httpx.Client(base_url=base_uri) as client:
|
|
58
|
-
res = client.get("/messageexchange/reset")
|
|
59
|
-
assert res.status_code == status.HTTP_400_BAD_REQUEST
|
|
File without changes
|
|
File without changes
|