feat: DDNS self-healing heartbeat + manual re-register endpoint
Unit Tests / test (push) Successful in 15m26s

- DDNSTokenExpired exception triggers auto re-register in update_ip()
  so cells recover silently after a DDNS DB reset
- POST /api/ddns/register lets the user force re-registration from Settings
- Re-register button in Settings → External Domain & DDNS (pic_ngo only)
- 3 new tests covering register endpoint: wrong provider, missing name, success

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 15:05:27 -04:00
parent cde177966d
commit 0b31d02f10
5 changed files with 106 additions and 3 deletions
+33
View File
@@ -136,5 +136,38 @@ class TestUpdateDdnsConfig(unittest.TestCase):
mock_id.assert_any_call('domain_name', 'home.example.com')
class TestDdnsRegister(unittest.TestCase):
def setUp(self):
self.client = _make_client()
def test_non_pic_ngo_provider_returns_400(self):
from app import config_manager
with patch.object(config_manager, 'configs', {'ddns': {'provider': 'cloudflare'}, '_identity': {}}):
r = self.client.post('/api/ddns/register')
self.assertEqual(r.status_code, 400)
def test_missing_cell_name_returns_400(self):
from app import config_manager
with patch.object(config_manager, 'configs', {'ddns': {'provider': 'pic_ngo'}, '_identity': {}}):
r = self.client.post('/api/ddns/register')
self.assertEqual(r.status_code, 400)
self.assertIn('cell_name', json.loads(r.data)['error'])
def test_register_success(self):
from app import config_manager
from ddns_manager import DDNSManager
with patch.object(config_manager, 'configs', {
'ddns': {'provider': 'pic_ngo'},
'_identity': {'cell_name': 'mypic'}
}):
with patch.object(DDNSManager, 'register', return_value={'subdomain': 'mypic.pic.ngo', 'token': 'tok'}) as mock_reg, \
patch.object(config_manager, 'set_identity_field') as mock_id:
r = self.client.post('/api/ddns/register')
self.assertEqual(r.status_code, 200)
body = json.loads(r.data)
self.assertTrue(body['registered'])
self.assertEqual(body['subdomain'], 'mypic.pic.ngo')
if __name__ == '__main__':
unittest.main()