Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Fix inconsistent behavior of get_last_client_by_ip #10970

Merged
merged 2 commits into from
Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/10970.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix inconsistent behavior of `get_last_client_by_ip` when reporting data that has not been stored in the database yet.
13 changes: 9 additions & 4 deletions synapse/storage/databases/main/client_ips.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,15 +538,20 @@ async def get_last_client_ip_by_device(
"""
ret = await super().get_last_client_ip_by_device(user_id, device_id)

# Update what is retrieved from the database with data which is pending insertion.
# Update what is retrieved from the database with data which is pending
# insertion, as if it has already been stored in the database.
for key in self._batch_row_update:
uid, access_token, ip = key
uid, _access_token, ip = key
if uid == user_id:
user_agent, did, last_seen = self._batch_row_update[key]

if did is None:
# These updates don't make it to the `devices` table
continue

if not device_id or did == device_id:
ret[(user_id, device_id)] = {
ret[(user_id, did)] = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

device_id can be None, which means info for all devices should be reported (as noted in the docstring).
The fetch-from-database code path files entries under their actual device id rather than None, so the previous code here was inconsistent.

"user_id": user_id,
"access_token": access_token,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

access_token was intentionally removed in 51d2827

"ip": ip,
"user_agent": user_agent,
"device_id": did,
Expand Down
43 changes: 43 additions & 0 deletions tests/storage/test_client_ips.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,49 @@ def test_insert_new_client_ip_none_device_id(self):
],
)

@parameterized.expand([(False,), (True,)])
def test_get_last_client_ip_by_device(self, after_persisting: bool):
"""Test `get_last_client_ip_by_device` for persisted and unpersisted data"""
self.reactor.advance(12345678)

user_id = "@user:id"
device_id = "MY_DEVICE"

# Insert a user IP
self.get_success(
self.store.store_device(
user_id,
device_id,
"display name",
)
)
self.get_success(
self.store.insert_client_ip(
user_id, "access_token", "ip", "user_agent", device_id
)
)

if after_persisting:
# Trigger the storage loop
self.reactor.advance(10)

result = self.get_success(
self.store.get_last_client_ip_by_device(user_id, device_id)
)

self.assertEqual(
result,
{
(user_id, device_id): {
"user_id": user_id,
"device_id": device_id,
"ip": "ip",
"user_agent": "user_agent",
"last_seen": 12345678000,
},
},
)

@parameterized.expand([(False,), (True,)])
def test_get_user_ip_and_agents(self, after_persisting: bool):
"""Test `get_user_ip_and_agents` for persisted and unpersisted data"""
Expand Down