| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- # coding=utf-8
- # type: ignore[index]
- """
- Unit tests for NameSilo DNS provider
- @author: NewFuture & Copilot
- """
- from base_test import BaseProviderTestCase, unittest, patch
- from ddns.provider.namesilo import NamesiloProvider
- class TestNamesiloProvider(BaseProviderTestCase):
- """Test cases for NameSilo DNS provider"""
- def setUp(self):
- """Set up test fixtures"""
- super(TestNamesiloProvider, self).setUp()
- self.provider = NamesiloProvider(self.id, self.token)
- def test_init_with_basic_config(self):
- """Test basic provider initialization"""
- self.assertProviderInitialized(self.provider)
- self.assertEqual(self.provider.endpoint, "https://www.namesilo.com")
- self.assertEqual(self.provider.content_type, "application/json")
- def test_init_with_custom_endpoint(self):
- """Test provider initialization with custom endpoint"""
- custom_endpoint = "https://api.custom.namesilo.com"
- provider = NamesiloProvider(self.id, self.token, endpoint=custom_endpoint)
- self.assertEqual(provider.endpoint, custom_endpoint)
- def test_validate_success(self):
- """Test successful credential validation"""
- # Should not raise exception
- try:
- self.provider._validate()
- except Exception as e:
- self.fail("_validate() raised unexpected exception: {}".format(e))
- def test_validate_missing_token(self):
- """Test validation with missing token"""
- with self.assertRaises(ValueError) as context:
- NamesiloProvider(self.id, "")
- self.assertIn("API key", str(context.exception))
- def test_validate_missing_id_allowed(self):
- """Test validation with missing ID (should be allowed)"""
- # Should not raise exception - ID is not strictly required for NameSilo
- try:
- provider = NamesiloProvider("", self.token)
- self.assertEqual(provider.token, self.token)
- except Exception as e:
- self.fail("_validate() raised unexpected exception with missing ID: {}".format(e))
- @patch.object(NamesiloProvider, "_http")
- def test_request_success(self, mock_http):
- """Test successful API request"""
- mock_response = {"reply": {"code": "300", "detail": "success", "data": {"test": "value"}}}
- mock_http.return_value = mock_response
- result = self.provider._request("testOperation", domain="example.com")
- # Verify request parameters
- mock_http.assert_called_once()
- args, kwargs = mock_http.call_args
- self.assertEqual(args[0], "GET")
- self.assertEqual(args[1], "/api/testOperation")
- expected_queries = {"domain": "example.com", "version": "1", "type": "json", "key": self.token}
- self.assertEqual(kwargs["queries"], expected_queries)
- # Verify response
- self.assertEqual(result["code"], "300")
- @patch.object(NamesiloProvider, "_http")
- def test_request_api_error(self, mock_http):
- """Test API request with error response"""
- mock_response = {"reply": {"code": "400", "detail": "Invalid domain"}}
- mock_http.return_value = mock_response
- # Mock logger to capture warning
- mock_logger = self.mock_logger(self.provider)
- result = self.provider._request("testOperation", domain="invalid.com")
- # Verify warning was logged
- mock_logger.warning.assert_called_once()
- warning_call = mock_logger.warning.call_args[0]
- self.assertIn("400", warning_call[1])
- self.assertIn("Invalid domain", warning_call[2])
- # Should return None on error
- self.assertIsNone(result)
- @patch.object(NamesiloProvider, "_request")
- def test_query_zone_id_success(self, mock_request):
- """Test successful zone ID query"""
- mock_request.return_value = {"code": "300", "domain": {"domain": "example.com"}}
- result = self.provider._query_zone_id("example.com")
- mock_request.assert_called_once_with("getDomainInfo", domain="example.com")
- self.assertEqual(result, "example.com")
- @patch.object(NamesiloProvider, "_request")
- def test_query_zone_id_not_found(self, mock_request):
- """Test zone ID query for non-existent domain"""
- mock_request.return_value = {"code": "400", "detail": "Domain not found"}
- result = self.provider._query_zone_id("nonexistent.com")
- self.assertIsNone(result)
- @patch.object(NamesiloProvider, "_request")
- def test_query_record_success_multiple_records(self, mock_request):
- """Test successful record query with multiple records"""
- mock_request.return_value = {
- "code": "300",
- "resource_record": [
- {"record_id": "12345", "host": "test", "type": "A", "value": "1.2.3.4", "ttl": "3600"},
- {"record_id": "67890", "host": "other", "type": "A", "value": "5.6.7.8", "ttl": "3600"},
- ],
- }
- result = self.provider._query_record("example.com", "test", "example.com", "A", None, {})
- self.assertIsNotNone(result)
- self.assertEqual(result["record_id"], "12345")
- self.assertEqual(result["host"], "test")
- @patch.object(NamesiloProvider, "_request")
- def test_query_record_not_found(self, mock_request):
- """Test record query when no matching record is found"""
- mock_request.return_value = {
- "code": "300",
- "resource_record": [
- {"record_id": "67890", "host": "other", "type": "A", "value": "5.6.7.8", "ttl": "3600"}
- ],
- }
- result = self.provider._query_record("example.com", "test", "example.com", "A", None, {})
- self.assertIsNone(result)
- @patch.object(NamesiloProvider, "_request")
- def test_create_record_success(self, mock_request):
- """Test successful record creation"""
- mock_request.return_value = {"code": "300", "record_id": "12345"}
- result = self.provider._create_record("example.com", "test", "example.com", "1.2.3.4", "A", 3600, None, {})
- expected_params = {
- "domain": "example.com",
- "rrtype": "A",
- "rrhost": "test",
- "rrvalue": "1.2.3.4",
- "rrttl": 3600,
- }
- mock_request.assert_called_once_with("dnsAddRecord", **expected_params)
- self.assertTrue(result)
- @patch.object(NamesiloProvider, "_request")
- def test_create_record_without_ttl(self, mock_request):
- """Test record creation without TTL"""
- mock_request.return_value = {"code": "300", "record_id": "12345"}
- result = self.provider._create_record("example.com", "test", "example.com", "1.2.3.4", "A", None, None, {})
- expected_params = {
- "domain": "example.com",
- "rrtype": "A",
- "rrhost": "test",
- "rrvalue": "1.2.3.4",
- "rrttl": None,
- }
- mock_request.assert_called_once_with("dnsAddRecord", **expected_params)
- self.assertTrue(result)
- @patch.object(NamesiloProvider, "_request")
- def test_create_record_failure(self, mock_request):
- """Test failed record creation"""
- mock_request.return_value = None
- result = self.provider._create_record("example.com", "test", "example.com", "invalid", "A", 3600, None, {})
- self.assertFalse(result)
- @patch.object(NamesiloProvider, "_request")
- def test_update_record_success(self, mock_request):
- """Test successful record update"""
- mock_request.return_value = {"code": "300"}
- old_record = {"record_id": "12345", "host": "test", "type": "A", "value": "1.2.3.4", "ttl": "3600"}
- result = self.provider._update_record("example.com", old_record, "5.6.7.8", "A", 7200, None, {})
- expected_params = {
- "domain": "example.com",
- "rrid": "12345",
- "rrhost": "test",
- "rrvalue": "5.6.7.8",
- "rrtype": "A",
- "rrttl": 7200,
- }
- mock_request.assert_called_once_with("dnsUpdateRecord", **expected_params)
- self.assertTrue(result)
- @patch.object(NamesiloProvider, "_request")
- def test_update_record_keep_existing_ttl(self, mock_request):
- """Test record update keeping existing TTL"""
- mock_request.return_value = {"code": "300"}
- old_record = {"record_id": "12345", "host": "test", "type": "A", "value": "1.2.3.4", "ttl": "3600"}
- result = self.provider._update_record("example.com", old_record, "5.6.7.8", "A", None, None, {})
- expected_params = {
- "domain": "example.com",
- "rrid": "12345",
- "rrhost": "test",
- "rrvalue": "5.6.7.8",
- "rrtype": "A",
- "rrttl": "3600", # Should keep existing TTL
- }
- mock_request.assert_called_once_with("dnsUpdateRecord", **expected_params)
- self.assertTrue(result)
- @patch.object(NamesiloProvider, "_request")
- def test_update_record_missing_record_id(self, mock_request):
- """Test record update with missing record_id"""
- old_record = {"host": "test", "type": "A", "value": "1.2.3.4"}
- result = self.provider._update_record("example.com", old_record, "5.6.7.8", "A", 7200, None, {})
- # Should not make API call and return False
- mock_request.assert_not_called()
- self.assertFalse(result)
- @patch.object(NamesiloProvider, "_request")
- def test_update_record_failure(self, mock_request):
- """Test failed record update"""
- mock_request.return_value = None
- old_record = {"record_id": "12345", "host": "test", "type": "A", "value": "1.2.3.4", "ttl": "3600"}
- result = self.provider._update_record("example.com", old_record, "5.6.7.8", "A", 7200, None, {})
- self.assertFalse(result)
- @patch.object(NamesiloProvider, "_request")
- def test_update_record_extra_priority_over_old_record(self, mock_request):
- """Test that extra parameters take priority over old_record values"""
- mock_request.return_value = {"reply": {"code": "300"}}
- old_record = {"record_id": "12345", "host": "test", "type": "A", "value": "1.2.3.4", "ttl": "3600"}
- # NameSilo doesn't use many extra params in update, but we verify it doesn't break
- extra = {"custom_field": "custom_value"}
- result = self.provider._update_record("example.com", old_record, "5.6.7.8", "A", 7200, None, extra)
- # Verify the basic call was made (NameSilo doesn't support extra params in update)
- mock_request.assert_called_once_with(
- "dnsUpdateRecord",
- rrid="12345",
- domain="example.com",
- rrhost="test",
- rrvalue="5.6.7.8",
- rrtype="A",
- rrttl=7200,
- )
- self.assertTrue(result)
- @patch.object(NamesiloProvider, "_http")
- def test_integration_set_record_update_flow(self, mock_http):
- """Integration test for complete set_record flow with update"""
- # Mock the sequence of API calls for an update scenario
- # 1. Domain info check (zone_id query)
- # 2. Record listing
- # 3. Record update
- mock_responses = [
- # getDomainInfo response
- {"reply": {"code": "300", "domain": {"domain": "example.com"}}},
- # dnsListRecords response
- {
- "reply": {
- "code": "300",
- "resource_record": [
- {"record_id": "12345", "host": "test", "type": "A", "value": "1.2.3.4", "ttl": "3600"}
- ],
- }
- },
- # dnsUpdateRecord response
- {"reply": {"code": "300"}},
- ]
- mock_http.side_effect = mock_responses
- # Execute set_record
- result = self.provider.set_record("test.example.com", "5.6.7.8", "A", 7200)
- # Verify result
- self.assertTrue(result)
- # Verify all expected API calls were made
- self.assertEqual(mock_http.call_count, 3)
- @patch.object(NamesiloProvider, "_http")
- def test_integration_set_record_create_flow(self, mock_http):
- """Integration test for complete set_record flow with create"""
- # Mock the sequence of API calls for a create scenario
- mock_responses = [
- # getDomainInfo response
- {"reply": {"code": "300", "domain": {"domain": "example.com"}}},
- # dnsListRecords response (no matching record)
- {"reply": {"code": "300", "resource_record": []}},
- # dnsAddRecord response
- {"reply": {"code": "300", "record_id": "67890"}},
- ]
- mock_http.side_effect = mock_responses
- # Execute set_record
- result = self.provider.set_record("newtest.example.com", "9.8.7.6", "A", 3600)
- # Verify result
- self.assertTrue(result)
- # Verify all expected API calls were made
- self.assertEqual(mock_http.call_count, 3)
- if __name__ == "__main__":
- unittest.main()
|