Skip to content

Commit 7bd86d1

Browse files
hbcarlosfcollonval
andauthored
Adds tests for rooms (#181)
* Adds tests for rooms * run pre-commit * Update tests/test_rooms.py Co-authored-by: Frédéric Collonval <[email protected]> * Update tests/test_rooms.py Co-authored-by: Frédéric Collonval <[email protected]> * Update tests/test_rooms.py Co-authored-by: Frédéric Collonval <[email protected]> * Update tests/test_rooms.py Co-authored-by: Frédéric Collonval <[email protected]> * Update tests/test_rooms.py Co-authored-by: Frédéric Collonval <[email protected]> * Improves tests * lint --------- Co-authored-by: Frédéric Collonval <[email protected]>
1 parent a2671b2 commit 7bd86d1

File tree

3 files changed

+207
-33
lines changed

3 files changed

+207
-33
lines changed

tests/test_loaders.py

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,12 @@
55

66
import asyncio
77
from datetime import datetime
8-
from typing import Any
98

109
import pytest
11-
from jupyter_server import _tz as tz
1210

1311
from jupyter_collaboration.loaders import FileLoader, FileLoaderMapping
1412

15-
16-
class FakeFileIDManager:
17-
def __init__(self, mapping: dict[str, str]):
18-
self.mapping = mapping
19-
20-
def get_path(self, id: str) -> str:
21-
return self.mapping[id]
22-
23-
24-
class FakeContentsManager:
25-
def __init__(self, model: dict):
26-
self.model = {
27-
"name": "",
28-
"path": "",
29-
"last_modified": datetime(1970, 1, 1, 0, 0, tzinfo=tz.UTC),
30-
"created": datetime(1970, 1, 1, 0, 0, tzinfo=tz.UTC),
31-
"content": None,
32-
"format": None,
33-
"mimetype": None,
34-
"size": 0,
35-
"writable": False,
36-
}
37-
self.model.update(model)
38-
39-
def get(
40-
self, path: str, content: bool = True, format: str | None = None, type: str | None = None
41-
) -> dict:
42-
return self.model
43-
44-
def save_content(self, model: dict[str, Any], path: str) -> dict:
45-
return self.model
13+
from .utils import FakeContentsManager, FakeFileIDManager
4614

4715

4816
@pytest.mark.asyncio

tests/test_rooms.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# Copyright (c) Jupyter Development Team.
2+
# Distributed under the terms of the Modified BSD License.
3+
4+
from __future__ import annotations
5+
6+
import asyncio
7+
from datetime import datetime
8+
9+
import pytest
10+
from ypy_websocket.yutils import write_var_uint
11+
12+
from jupyter_collaboration.loaders import FileLoader
13+
from jupyter_collaboration.rooms import DocumentRoom
14+
from jupyter_collaboration.utils import RoomMessages
15+
16+
from .utils import FakeContentsManager, FakeEventLogger, FakeFileIDManager
17+
18+
19+
@pytest.mark.asyncio
20+
async def test_should_initialize_document_room_without_store():
21+
id = "test-id"
22+
content = "test"
23+
paths = {id: "test.txt"}
24+
cm = FakeContentsManager({"content": content})
25+
loader = FileLoader(
26+
id,
27+
FakeFileIDManager(paths),
28+
cm,
29+
poll_interval=0.1,
30+
)
31+
32+
room = DocumentRoom("test-room", "text", "file", loader, FakeEventLogger(), None, None)
33+
34+
await room.initialize()
35+
assert room._document.source == content
36+
37+
38+
@pytest.mark.asyncio
39+
async def test_should_initialize_document_room_from_store():
40+
"""
41+
We need to create test files with Y updates to simulate
42+
a store.
43+
"""
44+
pass
45+
46+
47+
@pytest.mark.asyncio
48+
async def test_defined_save_delay_should_save_content_after_document_change():
49+
id = "test-id"
50+
content = "test"
51+
paths = {id: "test.txt"}
52+
cm = FakeContentsManager({"content": content})
53+
loader = FileLoader(
54+
id,
55+
FakeFileIDManager(paths),
56+
cm,
57+
poll_interval=0.1,
58+
)
59+
60+
room = DocumentRoom("test-room", "text", "file", loader, FakeEventLogger(), None, None, 0.01)
61+
62+
await room.initialize()
63+
room._document.source = "Test 2"
64+
65+
# Wait for a bit more than the poll_interval
66+
await asyncio.sleep(0.15)
67+
68+
assert "save" in cm.actions
69+
70+
71+
@pytest.mark.asyncio
72+
async def test_undefined_save_delay_should_not_save_content_after_document_change():
73+
id = "test-id"
74+
content = "test"
75+
paths = {id: "test.txt"}
76+
cm = FakeContentsManager({"content": content})
77+
loader = FileLoader(
78+
id,
79+
FakeFileIDManager(paths),
80+
cm,
81+
poll_interval=0.1,
82+
)
83+
84+
room = DocumentRoom("test-room", "text", "file", loader, FakeEventLogger(), None, None, None)
85+
86+
await room.initialize()
87+
room._document.source = "Test 2"
88+
89+
# Wait for a bit more than the poll_interval
90+
await asyncio.sleep(0.15)
91+
92+
assert "save" not in cm.actions
93+
94+
95+
@pytest.mark.asyncio
96+
async def test_should_reload_content_from_disk():
97+
id = "test-id"
98+
content = "test"
99+
paths = {id: "test.txt"}
100+
last_modified = datetime.now()
101+
cm = FakeContentsManager({"last_modified": last_modified, "content": "whatever"})
102+
loader = FileLoader(
103+
id,
104+
FakeFileIDManager(paths),
105+
cm,
106+
poll_interval=0.1,
107+
)
108+
109+
room = DocumentRoom("test-room", "text", "file", loader, FakeEventLogger(), None, None, None)
110+
111+
await room.initialize()
112+
113+
# Make sure the time increases
114+
cm.model["last_modified"] = datetime.fromtimestamp(last_modified.timestamp() + 1)
115+
cm.model["content"] = content
116+
117+
await loader.notify()
118+
119+
msg_id = next(iter(room._messages)).encode("utf8")
120+
await room.handle_msg(bytes([RoomMessages.RELOAD]) + write_var_uint(len(msg_id)) + msg_id)
121+
122+
assert room._document.source == content
123+
124+
125+
@pytest.mark.asyncio
126+
async def test_should_not_reload_content_from_disk():
127+
id = "test-id"
128+
content = "test"
129+
paths = {id: "test.txt"}
130+
last_modified = datetime.now()
131+
cm = FakeContentsManager({"last_modified": datetime.now(), "content": content})
132+
loader = FileLoader(
133+
id,
134+
FakeFileIDManager(paths),
135+
cm,
136+
poll_interval=0.1,
137+
)
138+
139+
room = DocumentRoom("test-room", "text", "file", loader, FakeEventLogger(), None, None, None)
140+
141+
await room.initialize()
142+
143+
# Make sure the time increases
144+
cm.model["last_modified"] = datetime.fromtimestamp(last_modified.timestamp() + 1)
145+
cm.model["content"] = "whatever"
146+
147+
await loader.notify()
148+
149+
msg_id = list(room._messages.keys())[0].encode("utf8")
150+
await room.handle_msg(bytes([RoomMessages.OVERWRITE]) + write_var_uint(len(msg_id)) + msg_id)
151+
152+
assert room._document.source == content

tests/utils.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright (c) Jupyter Development Team.
2+
# Distributed under the terms of the Modified BSD License.
3+
4+
from __future__ import annotations
5+
6+
from datetime import datetime
7+
from typing import Any
8+
9+
from jupyter_server import _tz as tz
10+
11+
12+
class FakeFileIDManager:
13+
def __init__(self, mapping: dict):
14+
self.mapping = mapping
15+
16+
def get_path(self, id: str) -> str:
17+
return self.mapping[id]
18+
19+
20+
class FakeContentsManager:
21+
def __init__(self, model: dict):
22+
self.model = {
23+
"name": "",
24+
"path": "",
25+
"last_modified": datetime(1970, 1, 1, 0, 0, tzinfo=tz.UTC),
26+
"created": datetime(1970, 1, 1, 0, 0, tzinfo=tz.UTC),
27+
"content": None,
28+
"format": None,
29+
"mimetype": None,
30+
"size": 0,
31+
"writable": False,
32+
}
33+
self.model.update(model)
34+
35+
self.actions: list[str] = []
36+
37+
def get(
38+
self, path: str, content: bool = True, format: str | None = None, type: str | None = None
39+
) -> dict:
40+
self.actions.append("get")
41+
return self.model
42+
43+
def save(self, model: dict[str, Any], path: str) -> dict:
44+
self.actions.append("save")
45+
return self.model
46+
47+
def save_content(self, model: dict[str, Any], path: str) -> dict:
48+
self.actions.append("save_content")
49+
return self.model
50+
51+
52+
class FakeEventLogger:
53+
def emit(self, schema_id: str, data: dict) -> None:
54+
print(data)

0 commit comments

Comments
 (0)