mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-08-03 06:06:05 -04:00
Fix MSC3030 /timestamp_to_event
returning outliers
that it has no idea whether are near a gap or not (#14215)
Fix MSC3030 `/timestamp_to_event` endpoint returning `outliers` that it has no idea whether are near a gap or not (and therefore unable to determine whether it's actually the closest event). The reason Synapse doesn't know whether an `outlier` is next to a gap is because our gap checks rely on entries in the `event_edges`, `event_forward_extremeties`, and `event_backward_extremities` tables which is [not the case for `outliers`](2c63cdcc3f/docs/development/room-dag-concepts.md (outliers)
). Also fixes MSC3030 Complement `can_paginate_after_getting_remote_event_from_timestamp_to_event_endpoint` test flake. Although this acted flakey in Complement, if `sync_partial_state` raced and beat us before `/timestamp_to_event`, then even if we retried the failing `/context` request it wouldn't work until we made this Synapse change. With this PR, Synapse will never return an `outlier` event so that test will always go and ask over federation. Fix https://github.com/matrix-org/synapse/issues/13944 ### Why did this fail before? Why was it flakey? Sleuthing the server logs on the [CI failure](5121449357 (step)
:5:5805), it looks like `hs2:/timestamp_to_event` found `$NP6-oU7mIFVyhtKfGvfrEQX949hQX-T-gvuauG6eurU` as an `outlier` event locally. Then when we went and asked for it via `/context`, since it's an `outlier`, it was filtered out of the results -> `You don't have permission to access that event.` This is reproducible when `sync_partial_state` races and persists `$NP6-oU7mIFVyhtKfGvfrEQX949hQX-T-gvuauG6eurU` as an `outlier` before we evaluate `get_event_for_timestamp(...)`. To consistently reproduce locally, just add a delay at the [start of `get_event_for_timestamp(...)`](cb20b885cb/synapse/handlers/room.py (L1470-L1496)
) so it always runs after `sync_partial_state` completes. ```py from twisted.internet import task as twisted_task d = twisted_task.deferLater(self.hs.get_reactor(), 3.5) await d ``` In a run where it passes, on `hs2`, `get_event_for_timestamp(...)` finds a different event locally which is next to a gap and we request from a closer one from `hs1` which gets backfilled. And since the backfilled event is not an `outlier`, it's returned as expected during `/context`. With this PR, Synapse will never return an `outlier` event so that test will always go and ask over federation.
This commit is contained in:
parent
2a76a7369f
commit
fa8616e65c
3 changed files with 104 additions and 21 deletions
|
@ -39,6 +39,8 @@ from synapse.api.constants import (
|
|||
)
|
||||
from synapse.api.errors import Codes, HttpResponseException
|
||||
from synapse.appservice import ApplicationService
|
||||
from synapse.events import EventBase
|
||||
from synapse.events.snapshot import EventContext
|
||||
from synapse.handlers.pagination import PurgeStatus
|
||||
from synapse.rest import admin
|
||||
from synapse.rest.client import account, directory, login, profile, register, room, sync
|
||||
|
@ -51,6 +53,7 @@ from tests import unittest
|
|||
from tests.http.server._base import make_request_with_cancellation_test
|
||||
from tests.storage.test_stream import PaginationTestCase
|
||||
from tests.test_utils import make_awaitable
|
||||
from tests.test_utils.event_injection import create_event
|
||||
|
||||
PATH_PREFIX = b"/_matrix/client/api/v1"
|
||||
|
||||
|
@ -3486,3 +3489,65 @@ class ThreepidInviteTestCase(unittest.HomeserverTestCase):
|
|||
)
|
||||
self.assertEqual(channel.code, 400)
|
||||
self.assertEqual(channel.json_body["errcode"], "M_MISSING_PARAM")
|
||||
|
||||
|
||||
class TimestampLookupTestCase(unittest.HomeserverTestCase):
|
||||
servlets = [
|
||||
admin.register_servlets,
|
||||
room.register_servlets,
|
||||
login.register_servlets,
|
||||
]
|
||||
|
||||
def default_config(self) -> JsonDict:
|
||||
config = super().default_config()
|
||||
config["experimental_features"] = {"msc3030_enabled": True}
|
||||
return config
|
||||
|
||||
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
|
||||
self._storage_controllers = self.hs.get_storage_controllers()
|
||||
|
||||
self.room_owner = self.register_user("room_owner", "test")
|
||||
self.room_owner_tok = self.login("room_owner", "test")
|
||||
|
||||
def _inject_outlier(self, room_id: str) -> EventBase:
|
||||
event, _context = self.get_success(
|
||||
create_event(
|
||||
self.hs,
|
||||
room_id=room_id,
|
||||
type="m.test",
|
||||
sender="@test_remote_user:remote",
|
||||
)
|
||||
)
|
||||
|
||||
event.internal_metadata.outlier = True
|
||||
self.get_success(
|
||||
self._storage_controllers.persistence.persist_event(
|
||||
event, EventContext.for_outlier(self._storage_controllers)
|
||||
)
|
||||
)
|
||||
return event
|
||||
|
||||
def test_no_outliers(self) -> None:
|
||||
"""
|
||||
Test to make sure `/timestamp_to_event` does not return `outlier` events.
|
||||
We're unable to determine whether an `outlier` is next to a gap so we
|
||||
don't know whether it's actually the closest event. Instead, let's just
|
||||
ignore `outliers` with this endpoint.
|
||||
|
||||
This test is really seeing that we choose the non-`outlier` event behind the
|
||||
`outlier`. Since the gap checking logic considers the latest message in the room
|
||||
as *not* next to a gap, asking over federation does not come into play here.
|
||||
"""
|
||||
room_id = self.helper.create_room_as(self.room_owner, tok=self.room_owner_tok)
|
||||
|
||||
outlier_event = self._inject_outlier(room_id)
|
||||
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
f"/_matrix/client/unstable/org.matrix.msc3030/rooms/{room_id}/timestamp_to_event?dir=b&ts={outlier_event.origin_server_ts}",
|
||||
access_token=self.room_owner_tok,
|
||||
)
|
||||
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||
|
||||
# Make sure the outlier event is not returned
|
||||
self.assertNotEqual(channel.json_body["event_id"], outlier_event.event_id)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue