Skip to content

Commit b47faff

Browse files
committed
Setup automatic unittests
1 parent e1514e0 commit b47faff

File tree

6 files changed

+162
-3
lines changed

6 files changed

+162
-3
lines changed

.github/workflows/python-tests.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Python Tests
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-latest
8+
9+
steps:
10+
- uses: actions/checkout@v3
11+
12+
- name: Set up Python 3.10
13+
uses: actions/setup-python@v4
14+
with:
15+
python-version: 3.10
16+
17+
- name: Install dependencies
18+
run: |
19+
python -m pip install --upgrade pip
20+
pip install -r requirements.txt
21+
22+
- name: Run tests
23+
run: python -m unittest discover

modules/logger.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# modules/logger.py
12
import logging
23

34
GRAY = '\033[90m'

modules/one_com_api.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,20 @@ def get_custom_records(session, domain):
4545
get_res = response.text
4646
if not get_res:
4747
raise ValueError("Empty response from API")
48-
return json.loads(get_res)["result"]["data"]
48+
data = json.loads(get_res)
49+
records = data["result"]["data"]
50+
# Validate that the records are in the expected list format.
51+
if not isinstance(records, list):
52+
raise TypeError("DNS records are not in the expected list format")
53+
return records
4954
except requests.exceptions.RequestException as e:
5055
logger.error(f"Error fetching DNS records for domain: {domain}. HTTP Status Code: {e.response.status_code if e.response else 'N/A'}")
5156
raise SystemExit(f"Failed to get DNS records for domain {domain}: {e}") from e
52-
except (json.JSONDecodeError, KeyError, TypeError) as e:
57+
except (json.JSONDecodeError, KeyError, TypeError, ValueError) as e:
5358
logger.error(f"Error parsing JSON response for domain: {domain}. Response text was: {get_res}")
5459
raise SystemExit(f"Failed to parse DNS records JSON for domain {domain}: {e}") from e
5560

61+
5662
def find_id_by_subdomain(records, subdomain):
5763
extracted_subdomain = tldextract.extract(subdomain).subdomain
5864
logger.info(f"searching domain prefix for: '{extracted_subdomain}'")

one_com_ddns.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import modules.one_com_config as config
3131
import modules.one_com_api as one_com_api
3232
import modules.logger as logger_module # Import the logger module
33-
import logging
3433

3534
logger = logger_module.setup_logging() # Setup logging
3635

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
requests
2+
tldextract
3+
dnspython

test/test.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import modules.dns_utils as dns_utils
2+
import modules.one_com_config as config
3+
import modules.one_com_api as one_com_api
4+
import logging
5+
import requests
6+
import unittest
7+
from unittest.mock import patch, Mock
8+
import json
9+
import sys # Make sure sys is imported
10+
11+
# Setup basic logging for tests
12+
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
13+
14+
class TestOneComDDNS(unittest.TestCase):
15+
16+
def test_dns_utils_get_ip_and_ttl(self):
17+
ip, ttl = dns_utils.get_ip_and_ttl("google.com")
18+
self.assertIsNotNone(ip)
19+
self.assertIsNotNone(ttl)
20+
self.assertIsInstance(ip, str)
21+
self.assertIsInstance(ttl, int)
22+
23+
result_invalid = dns_utils.get_ip_and_ttl("invalid-domain-for-testing.com")
24+
self.assertIsNone(result_invalid)
25+
26+
def test_one_com_config_parse_config(self):
27+
with patch('sys.argv', ['test_script.py', '-u', 'testuser', '-p', 'testpass', '-d', 'test.com', '-i', '127.0.0.1', '-f', '-t', '300', '-y']):
28+
settings = config.parse_config(validate_required=True)
29+
self.assertEqual(settings.username, 'testuser')
30+
self.assertEqual(settings.password, 'testpass')
31+
self.assertEqual(settings.domains, ['test.com'])
32+
self.assertEqual(settings.ip, '127.0.0.1')
33+
self.assertTrue(settings.force_update)
34+
self.assertEqual(settings.ttl, 300)
35+
self.assertTrue(settings.skip_confirmation)
36+
37+
def test_one_com_config_parse_config_auto_ip(self):
38+
with patch('sys.argv', ['test_script.py', '-u', 'testuser', '-p', 'testpass', '-d', 'test.com', '-i', 'AUTO']):
39+
with patch('requests.get') as mock_get:
40+
mock_get.return_value.text = "1.2.3.4"
41+
settings = config.parse_config(validate_required=True)
42+
self.assertEqual(settings.ip, "1.2.3.4")
43+
44+
def test_one_com_config_parse_config_auto_ip_error(self):
45+
with patch('sys.argv', ['test_script.py', '-u', 'testuser', '-p', 'testpass', '-d', 'test.com', '-i', 'AUTO']):
46+
with patch('requests.get') as mock_get:
47+
mock_get.side_effect = requests.ConnectionError
48+
with self.assertRaises(SystemExit):
49+
config.parse_config(validate_required=True)
50+
51+
def test_one_com_api_login_session(self):
52+
with patch('requests.sessions.Session.get') as mock_get:
53+
mock_get.return_value.text = '<form id="kc-form-login" class="Login-form login autofill" onsubmit="login.disabled = true; return true;" action="test_url"></form>'
54+
with patch('requests.sessions.Session.post') as mock_post:
55+
mock_post.return_value.text = "Success"
56+
session = one_com_api.login_session("testuser", "testpass")
57+
self.assertIsNotNone(session)
58+
with patch('requests.sessions.Session.get') as mock_get:
59+
mock_get.side_effect = requests.ConnectionError
60+
with self.assertRaises(SystemExit):
61+
one_com_api.login_session("testuser", "testpass")
62+
63+
def test_one_com_api_get_custom_records(self):
64+
mock_session = Mock()
65+
mock_response = Mock()
66+
mock_response.raise_for_status.return_value = None
67+
mock_response.text = '{"result": {"data": [{"id": "123", "attributes": {"prefix": "test"}} ]}}'
68+
mock_session.get.return_value = mock_response
69+
70+
records = one_com_api.get_custom_records(mock_session, "test.com")
71+
self.assertIsNotNone(records)
72+
self.assertEqual(len(records), 1)
73+
self.assertEqual(records[0]['id'], "123")
74+
75+
mock_session.get.side_effect = requests.exceptions.RequestException("Test Exception")
76+
raised_system_exit = False
77+
try:
78+
one_com_api.get_custom_records(mock_session, "test.com")
79+
except SystemExit:
80+
raised_system_exit = True
81+
self.assertTrue(raised_system_exit, "SystemExit was not raised")
82+
83+
mock_session.get.side_effect = None
84+
mock_response.text = '{"result": {"data": "invalid json"}}'
85+
mock_response.json.side_effect = json.JSONDecodeError("msg", "doc", 0)
86+
mock_session.get.return_value = mock_response
87+
with self.assertRaises(SystemExit):
88+
one_com_api.get_custom_records(mock_session, "test.com")
89+
90+
def test_one_com_api_find_id_by_subdomain(self):
91+
records = [{"id": "1", "attributes": {"prefix": "sub"}}, {"id": "2", "attributes": {"prefix": "other"}}]
92+
record_obj = one_com_api.find_id_by_subdomain(records, "sub.test.com")
93+
self.assertEqual(record_obj['id'], "1")
94+
95+
record_obj_not_found = one_com_api.find_id_by_subdomain(records, "nonexistent.test.com")
96+
self.assertIsNone(record_obj_not_found)
97+
98+
def test_one_com_api_change_ip(self):
99+
mock_session = Mock()
100+
mock_response = Mock()
101+
mock_response.raise_for_status.return_value = None
102+
mock_session.patch.return_value = mock_response
103+
104+
record = {"id": "123", "attributes": {"ttl": 300}}
105+
one_com_api.change_ip(mock_session, record, "sub.test.com", "1.2.3.4", 600)
106+
107+
mock_session.patch.side_effect = requests.exceptions.RequestException("Test Exception")
108+
with self.assertRaises(SystemExit):
109+
one_com_api.change_ip(mock_session, record, "sub.test.com", "1.2.3.4", 600)
110+
111+
def test_dns_utils_get_authoritative_ns(self):
112+
ns_servers = dns_utils.get_authoritative_ns("google.com")
113+
self.assertIsNotNone(ns_servers)
114+
self.assertIsInstance(ns_servers, list)
115+
self.assertGreater(len(ns_servers), 0)
116+
117+
ns_servers_invalid = dns_utils.get_authoritative_ns("invalid-domain-for-testing.com")
118+
self.assertIsNone(ns_servers_invalid)
119+
120+
def test_dns_utils_get_authoritative_ns_parent(self):
121+
ns_servers = dns_utils.get_authoritative_ns("sub.google.com")
122+
self.assertIsNotNone(ns_servers)
123+
self.assertIsInstance(ns_servers, list)
124+
self.assertGreater(len(ns_servers), 0)
125+
126+
if __name__ == '__main__':
127+
unittest.main()

0 commit comments

Comments
 (0)