Files
hell 155c29658e feat(servers): stable uid on every server record
Servers are addressed by their position in data['servers']: reorder
rebuilds the list and remaps user_connections, delete pops an entry and
shifts the ones after it. Any new cross-server reference (a server that
routes through another one) keyed by that index would silently point at
the wrong host after either operation.

Give every server record a `uid` (uuid4 hex). It is minted only in write
paths - the startup migration, api_add_server and the data.json restore
endpoint - never inside load_data(), because two concurrent readers
would otherwise assign different ids to the same record and the last
writer would win. find_server_by_uid() resolves a uid back to (index,
record) and treats an empty or unknown uid as not found.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 00:57:59 +07:00

79 lines
2.6 KiB
Python

import re
import unittest
from app import backfill_server_uids, find_server_by_uid
def servers():
return [
{'name': 'a', 'host': '10.0.0.1', 'protocols': {}},
{'name': 'b', 'host': '10.0.0.2', 'protocols': {}, 'uid': 'f' * 32},
{'name': 'c', 'host': '10.0.0.3', 'protocols': {}},
]
class BackfillServerUidsTests(unittest.TestCase):
def test_mints_distinct_uids_only_where_missing(self):
items = servers()
self.assertTrue(backfill_server_uids(items))
uids = [s['uid'] for s in items]
self.assertEqual(uids[1], 'f' * 32) # existing value untouched
self.assertEqual(len(set(uids)), 3)
for uid in uids:
self.assertRegex(uid, r'^[0-9a-f]{32}$')
def test_is_idempotent(self):
items = servers()
backfill_server_uids(items)
before = [s['uid'] for s in items]
self.assertFalse(backfill_server_uids(items))
self.assertEqual([s['uid'] for s in items], before)
def test_tolerates_missing_list(self):
self.assertFalse(backfill_server_uids(None))
self.assertFalse(backfill_server_uids([]))
class FindServerByUidTests(unittest.TestCase):
def setUp(self):
self.data = {'servers': servers()}
backfill_server_uids(self.data['servers'])
def test_resolves_index_and_record(self):
target = self.data['servers'][2]
idx, server = find_server_by_uid(self.data, target['uid'])
self.assertEqual(idx, 2)
self.assertIs(server, target)
def test_empty_or_unknown_uid_resolves_to_nothing(self):
self.assertEqual(find_server_by_uid(self.data, ''), (None, None))
self.assertEqual(find_server_by_uid(self.data, None), (None, None))
self.assertEqual(find_server_by_uid(self.data, 'no-such-uid'), (None, None))
self.assertEqual(find_server_by_uid({}, 'x'), (None, None))
def test_survives_reorder_and_delete(self):
target = self.data['servers'][2]
uid = target['uid']
# /api/servers/reorder rebuilds the list from a permutation of indices
order = [2, 0, 1]
self.data['servers'] = [self.data['servers'][i] for i in order]
idx, server = find_server_by_uid(self.data, uid)
self.assertEqual(idx, 0)
self.assertIs(server, target)
# /api/servers/{id}/delete pops a record and shifts the ones after it
self.data['servers'].pop(0)
self.assertEqual(find_server_by_uid(self.data, uid), (None, None))
other = self.data['servers'][1]
self.assertEqual(find_server_by_uid(self.data, other['uid']), (1, other))
if __name__ == '__main__':
unittest.main()