Updated gnss power off and power on test cases

Change-Id: I9eec723890d1b4705a4d0b37157ccfb4fdcecd16
Signed-off-by: Guntaka Umashankar Reddy <umashankarguntaka.reddy@windriver.com>
This commit is contained in:
Guntaka Umashankar Reddy
2025-06-18 11:27:59 -04:00
parent e1e3d8f0bb
commit 9b23a60d21
6 changed files with 175 additions and 128 deletions

View File

@@ -1,4 +1,6 @@
from framework.validation.validation import validate_equals_with_retry
from typing import Union
from framework.validation.validation import validate_equals_with_retry, validate_list_contains_with_retry
from keywords.ptp.pmc.pmc_keywords import PMCKeywords
@@ -52,13 +54,13 @@ class PTPReadinessKeywords:
validate_equals_with_retry(lambda: check_port_state_in_port_data_set(name), expected_port_states, "port state in port data set", 120, 30)
def wait_for_clock_class_appear_in_grandmaster_settings_np(self, name: str, expected_clock_class: int) -> None:
def wait_for_clock_class_appear_in_grandmaster_settings_np(self, name: str, expected_clock_class: Union[int, list]) -> None:
"""
Waits until the clock class observed in the grandmaster settings np match the expected clock class, or times out.
Args:
name (str): Name of the PTP instance.
expected_clock_class (int): expected clock class to wait for.
expected_clock_class (Union[int, list]): expected clock class to wait for.
Raises:
Exception: If expected clock class do not appear within the timeout.
@@ -84,15 +86,16 @@ class PTPReadinessKeywords:
return observed_clock_class
validate_equals_with_retry(lambda: get_clock_class_in_grandmaster_settings_np(name), expected_clock_class, "clock class in grandmaster settings np", 120, 30)
exp_clock_class = expected_clock_class if isinstance(expected_clock_class, list) else [expected_clock_class]
validate_list_contains_with_retry(lambda: get_clock_class_in_grandmaster_settings_np(name), exp_clock_class, "clock class in grandmaster settings np", 120, 30)
def wait_for_gm_clock_class_appear_in_parent_data_set(self, name: str, expected_gm_clock_class: int) -> None:
def wait_for_gm_clock_class_appear_in_parent_data_set(self, name: str, expected_gm_clock_class: Union[int, list]) -> None:
"""
Waits until the gm clock class observed in the parent data set match the expected clock class, or times out.
Args:
name (str): Name of the PTP instance.
expected_gm_clock_class (int): expected gm clock class to wait for.
expected_gm_clock_class (Union[int, list]): expected gm clock class to wait for.
Raises:
Exception: If expected gm clock class do not appear within the timeout.
@@ -118,4 +121,5 @@ class PTPReadinessKeywords:
return observed_gm_clock_class
validate_equals_with_retry(lambda: get_gm_clock_class_in_parent_data_set(name), expected_gm_clock_class, "gm clock class in parent data set", 120, 30)
exp_gm_clock_class = expected_gm_clock_class if isinstance(expected_gm_clock_class, list) else [expected_gm_clock_class]
validate_list_contains_with_retry(lambda: get_gm_clock_class_in_parent_data_set(name), exp_gm_clock_class, "gm clock class in parent data set", 120, 30)

View File

@@ -7,7 +7,6 @@ from keywords.base_keyword import BaseKeyword
from keywords.cloud_platform.fault_management.alarms.alarm_list_keywords import AlarmListKeywords
from keywords.cloud_platform.ssh.lab_connection_keywords import LabConnectionKeywords
from keywords.cloud_platform.system.host.system_host_list_keywords import SystemHostListKeywords
from keywords.linux.systemctl.systemctl_status_keywords import SystemCTLStatusKeywords
from keywords.ptp.cat.cat_clock_conf_keywords import CatClockConfKeywords
from keywords.ptp.cat.cat_ptp_cgu_keywords import CatPtpCguKeywords
from keywords.ptp.cat.cat_ptp_config_keywords import CatPtpConfigKeywords
@@ -504,7 +503,7 @@ class PTPVerifyConfigKeywords(BaseKeyword):
ptp4l_expected_obj = self.ptp_setup.get_ptp4l_expected_by_name(name)
expected_parent_data_set_obj = ptp4l_expected_obj.get_parent_data_set_for_hostname(hostname)
validate_equals(parent_data_set_obj.get_gm_clock_class(), expected_parent_data_set_obj.get_gm_clock_class(), "gm.ClockClass value within GET PARENT_DATA_SET")
validate_list_contains(parent_data_set_obj.get_gm_clock_class(), expected_parent_data_set_obj.get_gm_clock_class(), "gm.ClockClass value within GET PARENT_DATA_SET")
validate_equals(parent_data_set_obj.get_gm_clock_accuracy(), expected_parent_data_set_obj.get_gm_clock_accuracy(), "gm.ClockAccuracy value within GET PARENT_DATA_SET")
validate_equals(parent_data_set_obj.get_gm_offset_scaled_log_variance(), expected_parent_data_set_obj.get_gm_offset_scaled_log_variance(), "gm.OffsetScaledLogVariance value within GET PARENT_DATA_SET")
@@ -626,7 +625,7 @@ class PTPVerifyConfigKeywords(BaseKeyword):
expected_time_source = expected_grandmaster_settings_obj.get_time_source()
expected_current_utc_offset_valid = expected_grandmaster_settings_obj.get_current_utc_offset_valid()
validate_equals(observed_clock_class, expected_clock_class, "clockClass value within GET GRANDMASTER_SETTINGS_NP")
validate_list_contains(observed_clock_class, expected_clock_class, "clockClass value within GET GRANDMASTER_SETTINGS_NP")
validate_equals(observed_clock_accuracy, expected_clock_accuracy, "clockAccuracy value within GET GRANDMASTER_SETTINGS_NP")
validate_equals(observed_offset_scaled_log_variance, expected_offset_scaled_log_variance, "offsetScaledLogVariance value within GET GRANDMASTER_SETTINGS_NP")
validate_equals(observed_current_utc_offset_valid, expected_current_utc_offset_valid, "currentUtcOffsetValid value within GET GRANDMASTER_SETTINGS_NP")

View File

@@ -112,12 +112,16 @@ class GnssKeywords(BaseKeyword):
raise Exception(f"GPIO switch port not configured for {hostname} {nic}")
# Export GPIO pin if not already exported
export_cmd = f"if [ ! -d /sys/class/gpio/gpio{gpio_switch_port} ]; then echo {gpio_switch_port} > /sys/class/gpio/export; fi"
export_cmd = f"if [ ! -d /sys/class/gpio/gpio{gpio_switch_port} ]; then echo {gpio_switch_port} > /sys/class/gpio/export; sleep 0.5; fi"
gnss_ssh_connection.send(export_cmd)
# sleep needed even with retry loop
time.sleep(1)
# Set direction to output
direction_cmd = f"echo out > /sys/class/gpio/gpio{gpio_switch_port}/direction"
gnss_ssh_connection.send(direction_cmd)
# sleep needed even with retry loop
time.sleep(1)
# Set GPIO value to 1 (power on GNSS)
value_cmd = f"echo 1 > /sys/class/gpio/gpio{gpio_switch_port}/value"
@@ -147,12 +151,16 @@ class GnssKeywords(BaseKeyword):
raise Exception(f"GPIO switch port not configured for {hostname} {nic}")
# Export GPIO pin if not already exported
export_cmd = f"if [ ! -d /sys/class/gpio/gpio{gpio_switch_port} ]; then echo {gpio_switch_port} > /sys/class/gpio/export; fi"
export_cmd = f"if [ ! -d /sys/class/gpio/gpio{gpio_switch_port} ]; then echo {gpio_switch_port} > /sys/class/gpio/export; sleep 0.5; fi"
gnss_ssh_connection.send(export_cmd)
# sleep needed even with retry loop
time.sleep(1)
# Set direction to output
direction_cmd = f"echo out > /sys/class/gpio/gpio{gpio_switch_port}/direction"
gnss_ssh_connection.send(direction_cmd)
# sleep needed even with retry loop
time.sleep(1)
# Set GPIO value to 0 (power off GNSS)
value_cmd = f"echo 0 > /sys/class/gpio/gpio{gpio_switch_port}/value"

View File

@@ -15,7 +15,8 @@ class ParentDataSet:
"""
if "gm_clock_class" not in expected_dict:
raise Exception("Every expected dict should have a gm_clock_class.")
self.gm_clock_class = expected_dict["gm_clock_class"]
gm_clock_class = expected_dict["gm_clock_class"]
self.gm_clock_class = gm_clock_class if isinstance(gm_clock_class, list) else [gm_clock_class]
if "gm_clock_accuracy" not in expected_dict:
raise Exception("Every expected dict should have a gm_clock_accuracy.")
@@ -25,12 +26,12 @@ class ParentDataSet:
raise Exception("Every expected dict should have a gm_offset_scaled_log_variance.")
self.gm_offset_scaled_log_variance = expected_dict["gm_offset_scaled_log_variance"]
def get_gm_clock_class(self) -> int:
def get_gm_clock_class(self) -> list:
"""
Gets the gm clock class.
Returns:
int: The gm clock class.
list: The gm clock class.
"""
return self.gm_clock_class

View File

@@ -153,58 +153,6 @@ Prerequisites
3. Confirm all nodes are up and running
4. PTP services should be configured but not necessarily synchronized
Test Execution
------------
To run all PTP tests:
.. code-block:: bash
python -m pytest starlingx/testcases/cloud_platform/regression/ptp/test_ptp.py -v
To run a specific test:
.. code-block:: bash
python -m pytest starlingx/testcases/cloud_platform/regression/ptp/test_ptp.py::test_ptp_operation_gnss_disable -v
Test Cases
=========
test_ptp_operation_gnss_disable
-----------------------------
**Purpose**: Verify PTP behavior when GNSS signal is lost and then restored.
**Steps**:
1. Turn off GNSS for Controller-0 NIC1 using GPIO control
2. Verify alarms are triggered (100.119)
3. Verify clock class degradation (248 for holdover mode)
4. Verify PMC configuration with GNSS off
5. Turn GNSS back on
6. Verify alarms clear
7. Verify clock class restoration (6 for normal operation)
8. Verify PMC configuration after restoration
**Expected Results**:
- When GNSS is off, system should enter holdover mode with appropriate alarms
- When GNSS is restored, system should return to normal operation with alarms cleared
test_ptp_operation_phc_ctl_time_change
------------------------------------
**Purpose**: Verify PTP behavior when hardware clocks are manually adjusted.
**Steps**:
1. Start phc_ctl loop on controller-0 NIC1 to introduce time drift
2. Verify out-of-tolerance alarms are triggered
3. Stop the adjustment and verify alarms clear
4. Repeat the process for controller-1 NIC2
**Expected Results**:
- Manual clock adjustments should trigger out-of-tolerance alarms
- When adjustments stop, system should recover and alarms should clear
Common Alarms
============
@@ -293,7 +241,7 @@ Common Issues and Solutions
- Check for proper delay mechanism configuration
Diagnostic Commands and Interpretation
--------------------------------
================================
Below are essential commands for diagnosing PTP issues, along with explanations of what to look for in the output:
@@ -350,17 +298,68 @@ Below are essential commands for diagnosing PTP issues, along with explanations
**Understanding Clock Class Values:**
- **6**: Synchronized to primary reference (GNSS) - Optimal
- **7**: Synchronized to primary reference but holdover capable - Good
- **13-14**: Synchronized to application-specific source - Acceptable
- **52**: Degraded reference but synchronized - Warning
- **6**: Synchronized to primary reference (GNSS) - Highest accuracy
- **7**: Synchronized to primary reference but in holdover - Starting to drift
- **13-14**: Synchronized to application-specific source - Alternative reference
- **52**: Degraded reference but synchronized - Reduced accuracy
- **165**: Clock in holdover mode after losing synchronization - Drifting
- **187**: In holdover but within specifications - Warning
- **193**: In holdover, out of specifications - Problem
- **248**: Default/Holdover/Uncalibrated - Problem
- **255**: Slave-only clock - Normal for slave devices
- **248**: Default/uncalibrated clock - Worst quality, complete loss
- **255**: Slave-only clock - Receives time, never provides it
**Clock Accuracy Values:**
- **0x20**: "±25 nanoseconds - Highest accuracy with GNSS lock",
- **0x21**: "±100 nanoseconds - Very high accuracy",
- **0x22**: "±250 nanoseconds - High accuracy",
- **0xFE**: "Unknown - Accuracy cannot be determined (typically in holdover)",
- **0xFF**: "Reserved/Invalid - Not used for synchronization"
**Port States:**
- **MASTER**: "Port provides timing to downstream devices",
- **SLAVE**: "Port receives timing from an upstream master",
- **PASSIVE**: "Port is not currently used for synchronization",
- **LISTENING**: "Port is monitoring the network but not synchronized",
- **FAULTY**: "Port has detected a fault condition",
- **DISABLED**: "Port is administratively disabled",
- **UNCALIBRATED**: "Port is in the process of calibrating",
- **PRE_MASTER**: "Port is transitioning to MASTER state"
}
** Flag Values:**
- **time_traceable_1**: "Time is traceable to a primary reference (GNSS/UTC)",
- **time_traceable_0**: "Time is not traceable to a primary reference",
- **frequency_traceable_1**: "Frequency is traceable to a primary reference",
- **frequency_traceable_0**: "Frequency is not traceable to a primary reference",
- **current_utc_offset_valid_1**: "The UTC offset is valid and can be trusted",
- **current_utc_offset_valid_0**: "The UTC offset is not valid and cannot be trusted"
## Clock Accuracy Values
| Accuracy Value | Description | Meaning in Tests |
|----------------|-------------|------------------|
| 0x20 | ±25 nanoseconds | Highest accuracy, typically with GNSS lock |
| 0x21 | ±100 nanoseconds | Very high accuracy |
| 0x22 | ±250 nanoseconds | High accuracy |
| 0xFE | Unknown | Accuracy cannot be determined (typically in holdover) |
| 0xFF | Reserved/Invalid | Not used for synchronization |
## Port States
| Port State | Description | Test Implications |
|------------|-------------|-------------------|
| MASTER | Port provides timing to downstream devices | Device is acting as time source |
| SLAVE | Port receives timing from an upstream master | Device is synchronizing to another clock |
| PASSIVE | Port is not currently used for synchronization | Monitoring only, not active in timing path |
| LISTENING | Port is monitoring the network but not synchronized | Initial state or recovering from error |
| FAULTY | Port has detected a fault condition | Problem with timing or physical connection |
| DISABLED | Port is administratively disabled | Not participating in PTP |
| UNCALIBRATED | Port is in the process of calibrating | Transitional state during initialization |
| PRE_MASTER | Port is transitioning to MASTER state | Temporary state before becoming MASTER |
References and Learning Resources
===========================
================================
Standards and Specifications
--------------------------

View File

@@ -500,6 +500,22 @@ def test_ptp_operation_gnss_off_and_on():
Preconditions:
- System is set up with valid PTP configuration as defined in ptp_configuration_expectation_compute.json5.
Notes:
When analyzing test results, pay attention to:
1. **Clock Class Transitions**:
- 6 → 7: Brief GNSS signal loss, entering holdover
- 6 → 248: Complete GNSS signal loss, uncalibrated
- 248 → 6: GNSS signal recovery
2. **Port State Changes**:
- MASTER → SLAVE: Loss of reference or better clock available
- SLAVE → MASTER: Becoming best available clock
- Any state → FAULTY: Hardware or connectivity issue
3. **Flag Value Changes**:
- time_traceable 1 → 0: Loss of traceable time reference
- frequency_traceable 1 → 0: Loss of traceable frequency reference
"""
lab_connect_keywords = LabConnectionKeywords()
ssh_connection = lab_connect_keywords.get_active_controller_ssh()
@@ -510,45 +526,66 @@ def test_ptp_operation_gnss_off_and_on():
selected_instances = [("ptp1", "controller-0", []), ("ptp1", "controller-1", []), ("ptp3", "controller-0", []), ("ptp4", "controller-1", [])]
# controller-0 with GNSS disabled demotes itself (clockClass: 248) and becomes a SLAVE.
# controller-1 (still in degraded state but better than 248) becomes MASTER.
# Synchronization continues from controller-1 to controller-0.
# External clients (e.g., Proxmox) continue receiving PTP sync via remaining MASTER ports.
# Clock quality degradation is tracked via clock_class, accuracy, and variance.
# Flag Values:
# time_traceable=1: Time is traceable to primary reference (GNSS/UTC)
# time_traceable=0: Time is not traceable to primary reference
# frequency_traceable=1: Frequency is traceable to primary reference
# frequency_traceable=0: Frequency is not traceable to primary reference
# current_utc_offset_valid=0: UTC offset cannot be trusted without GNSS
#
# When GNSS signal is lost:
# - Controller-0 changes from clock class 6 to 7 (brief loss) or 248 (complete loss)
# - Port roles may reverse with the best available clock becoming MASTER
# - External clients continue receiving time from both controllers
#
# Role Changes During GNSS Signal Loss
# When GNSS signal is lost, the following changes occur in the PTP network:
# 1. Controller-0 with GNSS:
# - Clock class changes from 6 (GNSS-synchronized) to 248 (uncalibrated)
# - Port state changes from MASTER to SLAVE
# - time_traceable and frequency_traceable flags change from 1 to 0
# 2. Controller-1 without direct GNSS:
# - Takes over as best available time source with clock class 165
# - Port state changes from SLAVE to MASTER
# - Becomes the new reference for Controller-0
# 3. External Clients:
# - Continue receiving time from both controllers
# - Service availability is maintained despite degraded accuracy
# This role reversal ensures that the best available clock is always used as the reference,
# maintaining time synchronization even when the primary reference is lost.
ctrl0_nic1_gnss_disable_exp_dict = """{
"ptp4l": [
{
"name": "ptp1",
"controller-0": {
"parent_data_set": {
"gm_clock_class": 165, // GM is in holdover or degraded mode due to GNSS loss
"gm_clock_class": 7, // GM is in holdover or degraded mode due to GNSS loss
"gm_clock_accuracy": "0xfe", // Accuracy unknown due to GNSS signal loss
"gm_offset_scaled_log_variance": "0xffff" // Clock stability unknown
},
"time_properties_data_set": {
"current_utc_offset": 37, // Standard UTC offset (can be static)
"current_utc_offset_valid": 0, // UTC offset is not currently valid
"time_traceable": 0, // Time is not traceable to a valid source
"frequency_traceable": 0 // Frequency is not traceable to a valid reference
"time_traceable": 1, // Time is not traceable to a valid source
"frequency_traceable": 1 // Frequency is not traceable to a valid reference
},
"grandmaster_settings": {
"clock_class": 248, // Indicates GNSS signal is lost (free-running or degraded)
"clock_class": 7, // Indicates GNSS signal is lost (free-running or degraded)
"clock_accuracy": "0xfe", // Accuracy is unknown
"offset_scaled_log_variance": "0xffff", // Clock variance is unknown
"time_traceable": 0, // Time not traceable
"frequency_traceable": 0, // Frequency not traceable
"time_traceable": 1, // Time not traceable
"frequency_traceable": 1, // Frequency not traceable
"time_source": "0xa0", // Time source originally GNSS (0xA0)
"current_utc_offset_valid": 0 // UTC offset invalid due to signal loss
},
"port_data_set": [
{
"interface": "{{ controller_0.nic1.nic_connection.interface }}",
"port_state": "SLAVE", // Now syncing from controller-1, no longer acting as GM
"parent_port_identity" : {
"name": "ptp1", // Source PTP instance (controller-1)
"hostname":"controller-1", // Controller now acting as GM
"interface": "{{ controller_1.nic1.nic_connection.interface }}" // Source interface on controller-1
},
"port_state": "MASTER",
},
{
"interface": "{{ controller_0.nic1.conn_to_proxmox }}",
@@ -558,18 +595,18 @@ def test_ptp_operation_gnss_off_and_on():
},
"controller-1": {
"parent_data_set": {
"gm_clock_class": 165, // Controller-1 is GM but in holdover/degraded state
"gm_clock_class": 7,
"gm_clock_accuracy": "0xfe", // Unknown accuracy
"gm_offset_scaled_log_variance": "0xffff" // Unknown clock variance
},
"time_properties_data_set": {
"current_utc_offset": 37,
"current_utc_offset_valid": 0,
"time_traceable": 0,
"frequency_traceable": 0
"time_traceable": 1,
"frequency_traceable": 1
},
"grandmaster_settings": {
"clock_class": 165, // Controller-1 is acting as the best available GM
"clock_class": [165,248],
"clock_accuracy": "0xfe",
"offset_scaled_log_variance": "0xffff",
"time_traceable": 0,
@@ -580,7 +617,12 @@ def test_ptp_operation_gnss_off_and_on():
"port_data_set": [
{
"interface": "{{ controller_1.nic1.nic_connection.interface }}",
"port_state": "MASTER" // Now acting as the Grandmaster
"port_state": "SLAVE",
"parent_port_identity" : {
"name": "ptp1",
"hostname":"controller-0",
"interface": "{{ controller_0.nic1.nic_connection.interface }}" // ctrl-0 NIC1 is Master and ctrl-1 NIC1 is slave
},
},
{
"interface": "{{ controller_1.nic1.conn_to_proxmox }}",
@@ -593,34 +635,29 @@ def test_ptp_operation_gnss_off_and_on():
"name": "ptp3",
"controller-0": {
"parent_data_set": {
"gm_clock_class": 165, // Degraded GM status
"gm_clock_class": 7, // Lost GNSS, degraded state
"gm_clock_accuracy": "0xfe",
"gm_offset_scaled_log_variance": "0xffff"
},
"time_properties_data_set": {
"current_utc_offset": 37,
"current_utc_offset_valid": 0,
"time_traceable": 0,
"frequency_traceable": 0
"time_traceable": 1,
"frequency_traceable": 1
},
"grandmaster_settings": {
"clock_class": 248, // Lost GNSS, degraded state
"clock_class": 7, // Lost GNSS, degraded state
"clock_accuracy": "0xfe",
"offset_scaled_log_variance": "0xffff",
"time_traceable": 0,
"frequency_traceable": 0,
"time_traceable": 1,
"frequency_traceable": 1,
"time_source": "0xa0",
"current_utc_offset_valid": 0
},
"port_data_set": [
{
"interface": "{{ controller_0.nic2.nic_connection.interface }}",
"port_state": "SLAVE", // Now following ptp4 on controller-1 NIC2
"parent_port_identity" : {
"name": "ptp4",
"hostname":"controller-1",
"interface": "{{ controller_1.nic2.nic_connection.interface }}"
},
"port_state": "MASTER",
},
{
"interface": "{{ controller_0.nic2.conn_to_proxmox }}",
@@ -633,18 +670,18 @@ def test_ptp_operation_gnss_off_and_on():
"name": "ptp4",
"controller-1": {
"parent_data_set": {
"gm_clock_class": 165,
"gm_clock_class": 7,
"gm_clock_accuracy": "0xfe",
"gm_offset_scaled_log_variance": "0xffff"
},
"time_properties_data_set": {
"current_utc_offset": 37,
"current_utc_offset_valid": 0,
"time_traceable": 0,
"frequency_traceable": 0
"time_traceable": 1,
"frequency_traceable": 1
},
"grandmaster_settings": {
"clock_class": 165,
"clock_class": [165,248],
"clock_accuracy": "0xfe",
"offset_scaled_log_variance": "0xffff",
"time_traceable": 0,
@@ -655,7 +692,12 @@ def test_ptp_operation_gnss_off_and_on():
"port_data_set": [
{
"interface": "{{ controller_1.nic2.nic_connection.interface }}",
"port_state": "MASTER" // Acting as GM for NIC2
"port_state": "SLAVE", // Acting as GM for NIC2
"parent_port_identity" : {
"name": "ptp3",
"hostname":"controller-0",
"interface": "{{ controller_0.nic2.nic_connection.interface }}" // ctrl-0 NIC2 is Master and ctrl-1 NIC2 is slave
},
},
{
"interface": "{{ controller_1.nic2.conn_to_proxmox }}",
@@ -679,13 +721,8 @@ def test_ptp_operation_gnss_off_and_on():
ptp1_not_locked_alarm_obj = AlarmListObject()
ptp1_not_locked_alarm_obj.set_alarm_id("100.119")
ptp1_not_locked_alarm_obj.set_reason_text("controller-1 is not locked to remote PTP Grand Master")
ptp1_not_locked_alarm_obj.set_entity_id("host=controller-1.instance=ptp1.ptp=no-lock")
ptp4_not_locked_alarm_obj = AlarmListObject()
ptp4_not_locked_alarm_obj.set_alarm_id("100.119")
ptp4_not_locked_alarm_obj.set_reason_text("controller-1 is not locked to remote PTP Grand Master")
ptp4_not_locked_alarm_obj.set_entity_id("host=controller-1.instance=ptp4.ptp=no-lock")
ptp1_not_locked_alarm_obj.set_reason_text("controller-0 is not locked to remote PTP Grand Master")
ptp1_not_locked_alarm_obj.set_entity_id("host=controller-0.instance=ptp1.ptp=no-lock")
pps_signal_loss_alarm_obj = AlarmListObject()
pps_signal_loss_alarm_obj.set_alarm_id("100.119")
@@ -697,15 +734,15 @@ def test_ptp_operation_gnss_off_and_on():
gnss_signal_loss_alarm_obj.set_reason_text("controller-0 GNSS signal loss state: holdover")
gnss_signal_loss_alarm_obj.set_entity_id(f"host=controller-0.interface={interface}.ptp=GNSS-signal-loss")
AlarmListKeywords(ssh_connection).wait_for_alarms_to_appear([ptp1_not_locked_alarm_obj, ptp4_not_locked_alarm_obj, pps_signal_loss_alarm_obj, gnss_signal_loss_alarm_obj])
AlarmListKeywords(ssh_connection).wait_for_alarms_to_appear([ptp1_not_locked_alarm_obj, pps_signal_loss_alarm_obj, gnss_signal_loss_alarm_obj])
get_logger().log_info("Verifying clock class degradation after GNSS is off.")
# The clock is in "Holdover" or "Degraded" mode
ptp_readiness_keywords = PTPReadinessKeywords(LabConnectionKeywords().get_ssh_for_hostname("controller-0"))
ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp1", 248)
ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp3", 248)
ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp1", 7)
ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp3", 7)
# GNSS loss
ptp_readiness_keywords.wait_for_gm_clock_class_appear_in_parent_data_set("ptp1", 165)
ptp_readiness_keywords.wait_for_gm_clock_class_appear_in_parent_data_set("ptp1", 7)
get_logger().log_info("Verifying PMC configuration after GNSS is off.")
ptp_verify_config_keywords = PTPVerifyConfigKeywords(ssh_connection, ctrl0_nic1_gnss_disable_exp_ptp_setup)
@@ -715,7 +752,7 @@ def test_ptp_operation_gnss_off_and_on():
gnss_keywords.gnss_power_on("controller-0", "nic1")
get_logger().log_info("Waiting for alarm 100.119 to clear after GNSS is back on.")
AlarmListKeywords(ssh_connection).wait_for_alarms_cleared([ptp1_not_locked_alarm_obj, ptp4_not_locked_alarm_obj, pps_signal_loss_alarm_obj, gnss_signal_loss_alarm_obj])
AlarmListKeywords(ssh_connection).wait_for_alarms_cleared([ptp1_not_locked_alarm_obj, pps_signal_loss_alarm_obj, gnss_signal_loss_alarm_obj])
get_logger().log_info("Verifying clock class restoration after GNSS is on.")
ptp_readiness_keywords.wait_for_clock_class_appear_in_grandmaster_settings_np("ptp1", 6)
@@ -723,8 +760,7 @@ def test_ptp_operation_gnss_off_and_on():
ptp_readiness_keywords.wait_for_gm_clock_class_appear_in_parent_data_set("ptp1", 6)
get_logger().log_info("Verifying PMC configuration after GNSS is restored.")
ctrl0_nic1_gnss_enable_exp_dict_overrides = {"ptp4l": [{"name": "ptp4", "controller-1": {"grandmaster_settings": {"clock_class": 165}}}]}
ctrl0_nic1_gnss_enable_exp_ptp_setup = ptp_setup_keywords.filter_and_render_ptp_config(ptp_setup_template_path, selected_instances, expected_dict_overrides=ctrl0_nic1_gnss_enable_exp_dict_overrides)
ctrl0_nic1_gnss_enable_exp_ptp_setup = ptp_setup_keywords.generate_ptp_setup_from_template(ptp_setup_template_path)
ptp_verify_config_keywords = PTPVerifyConfigKeywords(ssh_connection, ctrl0_nic1_gnss_enable_exp_ptp_setup)
ptp_verify_config_keywords.verify_ptp_pmc_values()