11import ast
2+ from functools import cmp_to_key
23import logging
34import pytest
45
@@ -45,45 +46,99 @@ def ensure_dut_readiness(duthost):
4546 delete_checkpoint (duthost )
4647
4748
48- def ensure_application_of_updated_config (duthost , configdb_field , values ):
49+ def get_asic_db_values (duthost , fields ):
50+ """
51+ Args:
52+ duthost: DUT host object
53+ fields: CONFIG DB field(s) under test
54+
55+ Returns:
56+ A dictionary where keys are WRED profile OIDs in ASIC DB and values are the field-value pairs
57+ for the fields in configdb_field.
58+ """
59+ wred_objects = duthost .shell ('sonic-db-cli ASIC_DB keys *WRED*' )["stdout" ]
60+ wred_objects = wred_objects .split ("\n " )
61+ asic_db_values = {}
62+ for wred_object in wred_objects :
63+ oid = wred_object [wred_object .rfind (':' ) + 1 :]
64+ asic_db_values [oid ] = {}
65+ wred_data = duthost .shell ('sonic-db-cli ASIC_DB hgetall {}' .format (wred_object ))["stdout" ]
66+ if "NULL" in wred_data :
67+ continue
68+ wred_data = ast .literal_eval (wred_data )
69+ for field in fields :
70+ value = int (wred_data [WRED_MAPPING [field ]])
71+ asic_db_values [oid ][field ] = value
72+ return asic_db_values
73+
74+
75+ def get_wred_objects (duthost ):
76+ """
77+ Args:
78+ duthost: DUT host object
79+
80+ Returns:
81+ A list of WRED profile objects in ASIC DB.
82+ """
83+ wred_objects = duthost .shell ('sonic-db-cli ASIC_DB keys *WRED*' )["stdout" ]
84+ wred_objects = wred_objects .split ("\n " )
85+ return wred_objects
86+
87+
88+ def dict_compare (fields ):
89+ """
90+ Compares two dictionaries for equality based on a subset of keys.
91+
92+ Args:
93+ fields: The keys to compare.
94+
95+ Returns:
96+ A function that compares two dictionaries.
97+ """
98+ def compare (dict1 , dict2 ):
99+ for field in fields :
100+ if dict1 .get (field , 0 ) < dict2 .get (field , 0 ):
101+ return - 1
102+ elif dict1 .get (field , 0 ) > dict2 .get (field , 0 ):
103+ return 1
104+ # If all compared fields are equal, return 0
105+ return 0
106+
107+ return compare
108+
109+
110+ def ensure_application_of_updated_config (duthost , fields , new_values ):
49111 """
50112 Ensures application of the JSON patch config update
51113
52114 Args:
53115 duthost: DUT host object
54- configdb_field: config db field(s) under test
55- values: expected value(s) of configdb_field
116+ fields: config db field(s) under test
117+ new_values: expected value(s) of fields. It is a dictionary where keys are WRED profile names
118+ and values are dictionaries of field-value pairs for all fields in fields.
56119 """
57- def _confirm_value_in_asic_db ():
58- wred_objects = duthost .shell ('sonic-db-cli ASIC_DB keys *WRED*' )["stdout" ]
59- wred_objects = wred_objects .split ("\n " )
60- if (len (wred_objects ) > 1 ):
61- for wred_object in wred_objects :
62- wred_data = duthost .shell ('sonic-db-cli ASIC_DB hgetall {}' .format (wred_object ))["stdout" ]
63- if ('NULL' in wred_data ):
64- continue
65- wred_data = ast .literal_eval (wred_data )
66- for field , value in zip (configdb_field .split (',' ), values .split (',' )):
67- if value != wred_data [WRED_MAPPING [field ]]:
68- return False
69- return True
70- return False
71- else :
72- wred_data = duthost .shell ('sonic-db-cli ASIC_DB hgetall {}' .format (wred_objects [0 ]))["stdout" ]
73- wred_data = ast .literal_eval (wred_data )
74- for field , value in zip (configdb_field .split (',' ), values .split (',' )):
75- if value != wred_data [WRED_MAPPING [field ]]:
76- return False
77- return True
78-
79- logger .info ("Validating fields in ASIC DB..." )
120+ # Since there is no direct way to obtain the WRED profile name to oid mapping, we will just make sure
121+ # that the set of values in ASIC DB matches the set of values in CONFIG DB.
122+ def validate_wred_objects_in_asic_db ():
123+ asic_db_values = get_asic_db_values (duthost , fields )
124+ asic_db_values_list = sorted (list (asic_db_values .values ()), key = cmp_to_key (dict_compare (fields )))
125+ new_values_list = sorted (list (new_values .values ()), key = cmp_to_key (dict_compare (fields )))
126+ return asic_db_values_list == new_values_list
127+
128+ logger .info ("Validating WRED objects in ASIC DB..." )
80129 pytest_assert (
81- wait_until (READ_ASICDB_TIMEOUT , READ_ASICDB_INTERVAL , 0 , _confirm_value_in_asic_db ),
130+ wait_until (READ_ASICDB_TIMEOUT , READ_ASICDB_INTERVAL , 0 , validate_wred_objects_in_asic_db ),
82131 "ASIC DB does not properly reflect newly configured field(s): {} expected value(s): {}"
83- .format (configdb_field , values )
132+ .format (fields , new_values )
84133 )
85134
86135
136+ def get_wred_profiles (duthost ):
137+ wred_profiles = duthost .shell ("sonic-db-cli CONFIG_DB keys 'WRED_PROFILE|*' | cut -d '|' -f 2" )["stdout" ]
138+ wred_profiles = wred_profiles .split ('\n ' )
139+ return wred_profiles
140+
141+
87142@pytest .mark .parametrize ("configdb_field" , ["green_min_threshold" , "green_max_threshold" , "green_drop_probability" ,
88143 "green_min_threshold,green_max_threshold,green_drop_probability" ])
89144@pytest .mark .parametrize ("operation" , ["replace" ])
@@ -92,28 +147,37 @@ def test_ecn_config_updates(duthost, ensure_dut_readiness, configdb_field, opera
92147 logger .info ("tmpfile {} created for json patch of field: {} and operation: {}"
93148 .format (tmpfile , configdb_field , operation ))
94149
150+ fields = configdb_field .split (',' )
151+ wred_profiles = get_wred_profiles (duthost )
152+ if not wred_profiles :
153+ pytest .skip ("No WRED profiles found in CONFIG_DB, skipping test." )
95154 json_patch = list ()
96- values = list ()
97- ecn_data = duthost .shell ('sonic-db-cli CONFIG_DB hgetall "WRED_PROFILE|AZURE_LOSSLESS"' )['stdout' ]
98- ecn_data = ast .literal_eval (ecn_data )
99- for field in configdb_field .split (',' ):
100- value = int (ecn_data [field ]) + 1
101- values .append (str (value ))
102-
103- logger .info ("value to be added to json patch: {}, operation: {}, field: {}"
104- .format (value , operation , field ))
105-
106- json_patch .append (
107- {"op" : "{}" .format (operation ),
108- "path" : "/WRED_PROFILE/AZURE_LOSSLESS/{}" .format (field ),
109- "value" : "{}" .format (value )})
155+ # new_values is a dictionary from WRED profile name to its field-value mapping (with new values)
156+ # for the fields in configdb_field.
157+ new_values = {}
158+ # Creating a JSON patch for all WRED profiles in CONFIG_DB.
159+ for wred_profile in wred_profiles :
160+ ecn_data = duthost .shell (f"sonic-db-cli CONFIG_DB hgetall 'WRED_PROFILE|{ wred_profile } '" )["stdout" ]
161+ ecn_data = ast .literal_eval (ecn_data )
162+ new_values [wred_profile ] = {}
163+ for field in fields :
164+ value = int (ecn_data [field ]) + 1
165+ new_values [wred_profile ][field ] = value
166+
167+ logger .info ("value to be added to json patch: {}, operation: {}, field: {}"
168+ .format (value , operation , field ))
169+
170+ json_patch .append (
171+ {"op" : "{}" .format (operation ),
172+ "path" : f"/WRED_PROFILE/{ wred_profile } /{ field } " ,
173+ "value" : "{}" .format (value )})
110174
111175 json_patch = format_json_patch_for_multiasic (duthost = duthost , json_data = json_patch , is_asic_specific = True )
112176 try :
113177 output = apply_patch (duthost , json_data = json_patch , dest_file = tmpfile )
114178 if is_valid_platform_and_version (duthost , "WRED_PROFILE" , "ECN tuning" , operation ):
115179 expect_op_success (duthost , output )
116- ensure_application_of_updated_config (duthost , configdb_field , "," . join ( values ) )
180+ ensure_application_of_updated_config (duthost , fields , new_values )
117181 else :
118182 expect_op_failure (output )
119183 finally :
0 commit comments