From cfbdce1b90431174f64220e3436a19975ff7e270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= Date: Wed, 30 Apr 2025 10:04:07 +0200 Subject: [PATCH] Change timezone test to check timezone in operational instead of checking time Libyang is smart, it "fixes" the timezone for you, this was overriden by a hack in netconf.py and restconf.py, but what you really want is to see in operational what the current timezone is. --- src/statd/python/yanger/ietf_system.py | 29 +++++++++++++++++++ test/case/ietf_system/timezone/test.py | 11 ++++--- test/case/ietf_system/timezone/timezone.adoc | 2 +- .../ietf_system/timezone_utc_offset/test.py | 9 +++--- .../timezone_utc_offset.adoc | 2 +- test/infamy/netconf.py | 20 ------------- test/infamy/restconf.py | 13 --------- test/infamy/transport.py | 5 ---- 8 files changed, 40 insertions(+), 51 deletions(-) diff --git a/src/statd/python/yanger/ietf_system.py b/src/statd/python/yanger/ietf_system.py index 654030e2..f7a1bac3 100644 --- a/src/statd/python/yanger/ietf_system.py +++ b/src/statd/python/yanger/ietf_system.py @@ -1,5 +1,6 @@ import subprocess import ipaddress +import re from .common import insert,YangDate from .host import HOST @@ -210,6 +211,33 @@ def add_hostname(out): hostname = HOST.run(tuple(["hostname"])) out["hostname"] = hostname.strip() +def add_timezone(out): + path = HOST.run(tuple("realpath /etc/localtime".split()), "") + timezone = None + prefixes = [ + '/usr/share/zoneinfo/posix/', + '/usr/share/zoneinfo/right/', + '/usr/share/zoneinfo/' + ] + + for prefix in prefixes: + if path is not None and path.startswith(prefix): + timezone = path[len(prefix):] + break + if timezone is not None: + timezone=timezone.strip() + pattern = r'Etc/GMT([\+\-]\d{1,2})$' + match = re.search(pattern, timezone) + if match: + offset = -int(match.group(1)) + insert(out, "clock", "timezone-utc-offset", offset) + else: + if timezone == "Etc/UTC": + insert(out, "clock", "timezone-utc-offset", 0) + else: + insert(out, "clock", "timezone-name", timezone) + + def add_users(out): shadow_output = HOST.run_multiline(["getent", "shadow"], []) users = [] @@ -257,6 +285,7 @@ def operational(): out_system = out["ietf-system:system"] add_hostname(out_system) add_users(out_system) + add_timezone(out_system) add_software(out_state) add_ntp(out_state) add_dns(out_state) diff --git a/test/case/ietf_system/timezone/test.py b/test/case/ietf_system/timezone/test.py index e4229e75..58bfac2e 100755 --- a/test/case/ietf_system/timezone/test.py +++ b/test/case/ietf_system/timezone/test.py @@ -17,15 +17,14 @@ with infamy.Test() as test: target.put_config_dicts({"ietf-system": { "system": { "clock": { - "timezone-name": "Australia/Perth" # always +8:00, no DTS + "timezone-name": "Australia/Perth" } } }}) - with test.step("Verify current time offset is +08:00"): - current_datetime=target.get_current_time_with_offset() - offset=current_datetime[-6:] - - assert(offset == "+08:00") + with test.step("Verify timezone is Australia/Perth"): + tz=target.get_data("/ietf-system:system/clock/timezone-name") + name=tz.get("system", {}).get("clock",{}).get("timezone-name", "") + assert(name == "Australia/Perth") test.succeed() diff --git a/test/case/ietf_system/timezone/timezone.adoc b/test/case/ietf_system/timezone/timezone.adoc index 4e0104a0..af76d503 100644 --- a/test/case/ietf_system/timezone/timezone.adoc +++ b/test/case/ietf_system/timezone/timezone.adoc @@ -17,7 +17,7 @@ endif::topdoc[] ==== Test sequence . Set up topology and attach to target DUT . Set timezone to Australia/Perth -. Verify current time offset is +08:00 +. Verify timezone is Australia/Perth <<< diff --git a/test/case/ietf_system/timezone_utc_offset/test.py b/test/case/ietf_system/timezone_utc_offset/test.py index d4a3b982..803e445a 100755 --- a/test/case/ietf_system/timezone_utc_offset/test.py +++ b/test/case/ietf_system/timezone_utc_offset/test.py @@ -21,10 +21,9 @@ with infamy.Test() as test: } }}) - with test.step("Verify current time offset is +12:00"): - current_datetime=target.get_current_time_with_offset() - offset=current_datetime[-6:] - - assert(offset == "+12:00") + with test.step("Verify current timezone is UTC+12:00"): + tz=target.get_data("/ietf-system:system/clock/timezone-utc-offset") + offset=tz.get("system", {}).get("clock",{}).get("timezone-utc-offset", 0) + assert(offset == 12) test.succeed() diff --git a/test/case/ietf_system/timezone_utc_offset/timezone_utc_offset.adoc b/test/case/ietf_system/timezone_utc_offset/timezone_utc_offset.adoc index 24638bb1..8f2daefb 100644 --- a/test/case/ietf_system/timezone_utc_offset/timezone_utc_offset.adoc +++ b/test/case/ietf_system/timezone_utc_offset/timezone_utc_offset.adoc @@ -17,7 +17,7 @@ endif::topdoc[] ==== Test sequence . Set up topology and attach to target DUT . Set timezone UTC offset to +12 -. Verify current time offset is +12:00 +. Verify current timezone is UTC+12:00 <<< diff --git a/test/infamy/netconf.py b/test/infamy/netconf.py index 711d684a..68eb2265 100644 --- a/test/infamy/netconf.py +++ b/test/infamy/netconf.py @@ -411,23 +411,3 @@ class Device(Transport): # Apply the configuration change return self.put_config(lyd.print_mem("xml", with_siblings=True, pretty=False)) - - def get_current_time_with_offset(self): - """ - Return current datetime with offset. - - This method retrieves the current datetime from the raw data - before it is passed through libyang. This is necessary because - libyang "adjusts" the time for the offset, and we need the - unadjusted time. - """ - data = self.get_data("/ietf-system:system-state/clock", parse=False) - parsed_data = lxml.etree.fromstring(data) - - xpath = './/{urn:ietf:params:xml:ns:yang:ietf-system}current-datetime' - current_datetime = parsed_data.find(xpath) - - if current_datetime is not None: - return current_datetime.text - else: - raise ValueError("current-datetime element not found in the response") diff --git a/test/infamy/restconf.py b/test/infamy/restconf.py index 4d6f3ce5..63775e39 100644 --- a/test/infamy/restconf.py +++ b/test/infamy/restconf.py @@ -359,19 +359,6 @@ class Device(Transport): return response.content - def get_current_time_with_offset(self): - """ - Return current datetime with offset. - - This method retrieves the current datetime from the raw data - before it is passed through libyang. This is necessary because - libyang "adjusts" the time for the offset, and we need the - unadjusted time. - """ - data = self.get_data("/ietf-system:system-state/clock", parse=False) - data = json.loads(data) - return data["ietf-system:system-state"]["clock"]["current-datetime"] - def delete_xpath(self, xpath): """Delete XPath from running config""" path = f"/ds/ietf-datastores:running{xpath_to_uri(xpath)}" diff --git a/test/infamy/transport.py b/test/infamy/transport.py index 2148073b..daaf8c73 100644 --- a/test/infamy/transport.py +++ b/test/infamy/transport.py @@ -42,11 +42,6 @@ class Transport(ABC): def reboot(self): pass - @abstractmethod - def get_current_time_with_offset(self): - """Needed since libyang is too nice and removes the original offset""" - pass - @abstractmethod def call_dict(self, module, call): pass