tests/spa/orchestration/test_orchestration_freeze_handler.py¶
Source from this local checkout, regenerated when the reader rebuilds.
Line links use #L<number>; a GitHub line range opens its first line.
1 # Copyright 2025 Softwell S.r.l.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 at6 #7 # https://www.apache.org/licenses/LICENSE-2.08 #9 # Unless required by applicable law or agreed to in writing, software10 # 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 and13 # limitations under the License.14 15 """FreezeHandler tests: the semaphore, the two item kinds, the empty folder.16 17 Everything here runs against a real directory in ``tmp_path``: the deposit is18 the one place that talks to the filesystem directly, so a fake filesystem would19 assert nothing. The protocol under test is always the same round — announce,20 take the lock, operate, release — and what the tests pin down is what happens21 at its edges: a second holder finding the lock taken, a folder left with the22 lock alone, a header travelling with a payload nobody reads it for.23 """24 25 from __future__ import annotations26 27 import os28 import time29 30 import pytest31 32 from genro_asgi_multiworker_spa.orchestration import FreezeHandler33 34 35 @pytest.fixture36 def deposit(tmp_path):37 return FreezeHandler(tmp_path / "freezed_users")38 39 40 def test_root_is_created_private(tmp_path):41 root = tmp_path / "deposit" / "freezed_users"42 FreezeHandler(root)43 assert root.is_dir()44 assert os.stat(root).st_mode & 0o777 == 0o70045 46 47 def test_lock_is_mutually_exclusive(deposit):48 assert deposit.take_lock("mario", "standard_0001") is True49 assert deposit.take_lock("mario", "standard_0002") is False50 assert deposit.lock_holder("mario") == "standard_0001"51 52 deposit.release_lock("mario", "standard_0001")53 assert deposit.lock_holder("mario") is None54 assert deposit.take_lock("mario", "standard_0002") is True55 56 57 def test_release_by_a_holder_that_does_not_hold_is_an_error(deposit):58 deposit.take_lock("mario", "standard_0001")59 with pytest.raises(RuntimeError, match="standard_0002"):60 deposit.release_lock("mario", "standard_0002")61 assert deposit.lock_holder("mario") == "standard_0001"62 63 64 def test_two_writers_share_one_folder_one_at_a_time(deposit):65 """The whole freeze writes the user store, a login writes one connection."""66 assert deposit.take_lock("mario", "standard_0001") is True67 deposit.write_user_register_item(68 "mario", {"store": "whole"}, writer="standard_0001", cause="freeze", group="standard"69 )70 assert deposit.take_lock("mario", "standard_0002") is False71 deposit.release_lock("mario", "standard_0001")72 73 assert deposit.take_lock("mario", "standard_0002") is True74 deposit.write_connection_register_item(75 "mario", "cid-a", {"pages": ["p1"]}, writer="standard_0002", cause="login", group="standard"76 )77 deposit.release_lock("mario", "standard_0002")78 79 assert deposit.read_user_register_item("mario") == {"store": "whole"}80 assert deposit.read_connection_register_item("mario", "cid-a") == {"pages": ["p1"]}81 82 83 def test_reading_what_was_never_written_gives_nothing(deposit):84 assert deposit.read_user_register_item("mario") is None85 assert deposit.read_connection_register_item("mario", "cid-a") is None86 assert deposit.get_item_header("mario") is None87 88 89 def test_the_header_travels_with_the_payload(deposit):90 before = time.time()91 deposit.take_lock("mario", "standard_0001")92 deposit.write_connection_register_item(93 "mario", "cid-a", {"pages": []}, writer="standard_0001", cause="freeze", group="standard"94 )95 deposit.release_lock("mario", "standard_0001")96 97 header = deposit.get_item_header("mario", "cid-a")98 assert header["writer"] == "standard_0001"99 assert header["cause"] == "freeze"100 assert header["group"] == "standard"101 assert header["ts"] >= before102 103 104 def test_the_release_takes_away_the_folder_left_with_the_lock_alone(deposit):105 deposit.take_lock("mario", "standard_0001")106 deposit.write_connection_register_item(107 "mario", "cid-a", {"pages": []}, writer="standard_0001", cause="freeze", group="standard"108 )109 deposit.write_user_register_item(110 "mario", {"store": {}}, writer="standard_0001", cause="freeze", group="standard"111 )112 assert deposit.user_folders == {deposit.user_to_userkey("mario")}113 114 deposit.drop_connection_register_item("mario", "cid-a")115 deposit.drop_user_register_item("mario")116 assert deposit.lock_holder("mario") == "standard_0001"117 assert deposit.user_folders == {deposit.user_to_userkey("mario")}118 119 deposit.release_lock("mario", "standard_0001")120 assert deposit.user_folders == set()121 122 123 def test_the_release_leaves_a_folder_that_still_has_items(deposit):124 deposit.take_lock("mario", "standard_0001")125 deposit.write_user_register_item(126 "mario", {"store": {}}, writer="standard_0001", cause="freeze", group="standard"127 )128 deposit.release_lock("mario", "standard_0001")129 130 assert deposit.user_folders == {deposit.user_to_userkey("mario")}131 assert deposit.read_user_register_item("mario") == {"store": {}}132 133 134 def test_the_whole_folder_goes_with_its_user(deposit):135 deposit.take_lock("mario", "standard_0001")136 deposit.write_user_register_item(137 "mario", {"store": {}}, writer="standard_0001", cause="freeze", group="standard"138 )139 deposit.write_connection_register_item(140 "mario", "cid-a", {"pages": []}, writer="standard_0001", cause="freeze", group="standard"141 )142 143 deposit.drop_user_folder("mario")144 assert deposit.user_folders == set()145 assert deposit.lock_holder("mario") is None146 147 148 def test_dropping_a_folder_nobody_wrote_is_no_work(deposit):149 deposit.drop_user_folder("mario")150 assert deposit.user_folders == set()151 152 153 def test_dropping_items_nobody_wrote_is_no_work(deposit):154 deposit.take_lock("mario", "standard_0001")155 156 deposit.drop_user_register_item("mario")157 deposit.drop_connection_register_item("mario", "cid-a")158 159 assert deposit.lock_holder("mario") == "standard_0001"160 deposit.release_lock("mario", "standard_0001")161 assert deposit.user_folders == set()162 163 164 def test_the_folders_of_every_user_come_as_one_set(deposit):165 for user in ("mario", "guest_abc", "anna@example.com"):166 deposit.take_lock(user, "standard_0001")167 deposit.write_user_register_item(168 user, {"store": {}}, writer="standard_0001", cause="freeze", group="standard"169 )170 deposit.release_lock(user, "standard_0001")171 172 assert deposit.user_folders == {173 deposit.user_to_userkey(user) for user in ("mario", "guest_abc", "anna@example.com")174 }175 176 177 def test_the_key_goes_one_way_only(deposit):178 assert deposit.user_to_userkey("anna@example.com") == "anna%40example.com"179 assert not hasattr(deposit, "userkey_to_user")180 181 182 def test_an_identity_carrying_separators_stays_in_its_folder(deposit):183 hostile = "../mario/../../etc"184 deposit.take_lock(hostile, "standard_0001")185 deposit.write_user_register_item(186 hostile, {"store": {}}, writer="standard_0001", cause="freeze", group="standard"187 )188 deposit.release_lock(hostile, "standard_0001")189 190 assert deposit.user_folders == {deposit.user_to_userkey(hostile)}191 assert "/" not in deposit.user_to_userkey(hostile)192 193 194 def test_two_connections_of_one_user_are_two_files(deposit):195 deposit.take_lock("mario", "standard_0001")196 deposit.write_connection_register_item(197 "mario", "cid-a", {"pages": ["a"]}, writer="standard_0001", cause="freeze", group="standard"198 )199 deposit.write_connection_register_item(200 "mario", "cid-b", {"pages": ["b"]}, writer="standard_0001", cause="freeze", group="standard"201 )202 deposit.release_lock("mario", "standard_0001")203 204 assert deposit.read_connection_register_item("mario", "cid-a") == {"pages": ["a"]}205 assert deposit.read_connection_register_item("mario", "cid-b") == {"pages": ["b"]}206 207 deposit.take_lock("mario", "standard_0001")208 deposit.drop_connection_register_item("mario", "cid-a")209 deposit.release_lock("mario", "standard_0001")210 211 assert deposit.read_connection_register_item("mario", "cid-a") is None212 assert deposit.read_connection_register_item("mario", "cid-b") == {"pages": ["b"]}