27
27
28
28
import config .main as config
29
29
import config .validated_config_db_connector as validated_config_db_connector
30
+ from config .main import config_file_yang_validation
30
31
31
32
# Add Test, module and script path.
32
33
test_path = os .path .dirname (os .path .abspath (__file__ ))
@@ -966,6 +967,16 @@ def setup_class(cls):
966
967
import config .main
967
968
importlib .reload (config .main )
968
969
970
+ def read_json_file_side_effect (self , filename ):
971
+ return {
972
+ 'DEVICE_METADATA' : {
973
+ 'localhost' : {
974
+ 'platform' : 'x86_64-mlnx_msn2700-r0' ,
975
+ 'mac' : '00:02:03:04:05:07'
976
+ }
977
+ }
978
+ }
979
+
969
980
@mock .patch ('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs' , mock .MagicMock (return_value = ("dummy_path" , None )))
970
981
@mock .patch ('config.main.subprocess.check_call' )
971
982
def test_load_minigraph (self , mock_check_call , get_cmd_module , setup_single_broadcom_asic ):
@@ -1135,12 +1146,9 @@ def test_load_minigraph_with_specified_golden_config_path(self, get_cmd_module):
1135
1146
def is_file_side_effect (filename ):
1136
1147
return True if 'golden_config' in filename else False
1137
1148
1138
- def read_json_file_side_effect (filename ):
1139
- return {}
1140
-
1141
1149
with mock .patch ("utilities_common.cli.run_command" , mock .MagicMock (side_effect = mock_run_command_side_effect )) as mock_run_command , \
1142
1150
mock .patch ('os.path.isfile' , mock .MagicMock (side_effect = is_file_side_effect )), \
1143
- mock .patch ('config.main.read_json_file' , mock .MagicMock (side_effect = read_json_file_side_effect )):
1151
+ mock .patch ('config.main.read_json_file' , mock .MagicMock (side_effect = self . read_json_file_side_effect )):
1144
1152
(config , show ) = get_cmd_module
1145
1153
runner = CliRunner ()
1146
1154
result = runner .invoke (config .config .commands ["load_minigraph" ], ["--override_config" , "--golden_config_path" , "golden_config.json" , "-y" ])
@@ -1152,18 +1160,32 @@ def test_load_minigraph_with_default_golden_config_path(self, get_cmd_module):
1152
1160
def is_file_side_effect (filename ):
1153
1161
return True if 'golden_config' in filename else False
1154
1162
1155
- def read_json_file_side_effect (filename ):
1156
- return {}
1157
-
1158
1163
with mock .patch ("utilities_common.cli.run_command" , mock .MagicMock (side_effect = mock_run_command_side_effect )) as mock_run_command , \
1159
1164
mock .patch ('os.path.isfile' , mock .MagicMock (side_effect = is_file_side_effect )), \
1160
- mock .patch ('config.main.read_json_file' , mock .MagicMock (side_effect = read_json_file_side_effect )):
1165
+ mock .patch ('config.main.read_json_file' , mock .MagicMock (side_effect = self . read_json_file_side_effect )):
1161
1166
(config , show ) = get_cmd_module
1162
1167
runner = CliRunner ()
1163
1168
result = runner .invoke (config .config .commands ["load_minigraph" ], ["--override_config" , "-y" ])
1164
1169
assert result .exit_code == 0
1165
1170
assert "config override-config-table /etc/sonic/golden_config_db.json" in result .output
1166
1171
1172
+ @mock .patch (
1173
+ 'sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs' ,
1174
+ mock .MagicMock (return_value = ("dummy_path" , None )))
1175
+ def test_load_minigraph_with_invalid_golden_config (self , get_cmd_module ):
1176
+ def is_file_side_effect (filename ):
1177
+ return True if 'golden_config' in filename else False
1178
+
1179
+ with mock .patch ("utilities_common.cli.run_command" ,
1180
+ mock .MagicMock (side_effect = mock_run_command_side_effect )), \
1181
+ mock .patch ('os.path.isfile' , mock .MagicMock (side_effect = is_file_side_effect )), \
1182
+ mock .patch ('config.main.read_json_file' , mock .MagicMock (return_value = [])):
1183
+ (config , show ) = get_cmd_module
1184
+ runner = CliRunner ()
1185
+ result = runner .invoke (config .config .commands ["load_minigraph" ], ["--override_config" , "-y" ])
1186
+ assert result .exit_code != 0
1187
+ assert "Invalid golden config file:" in result .output
1188
+
1167
1189
@mock .patch ('sonic_py_common.device_info.get_paths_to_platform_and_hwsku_dirs' ,
1168
1190
mock .MagicMock (return_value = ("dummy_path" , None )))
1169
1191
def test_load_minigraph_hard_dependency_check (self , get_cmd_module ):
@@ -1234,11 +1256,9 @@ def test_load_minigraph_with_traffic_shift_away_with_golden_config(self, get_cmd
1234
1256
def is_file_side_effect (filename ):
1235
1257
return True if 'golden_config' in filename else False
1236
1258
1237
- def read_json_file_side_effect (filename ):
1238
- return {}
1239
-
1240
1259
with mock .patch ('os.path.isfile' , mock .MagicMock (side_effect = is_file_side_effect )), \
1241
- mock .patch ('config.main.read_json_file' , mock .MagicMock (side_effect = read_json_file_side_effect )):
1260
+ mock .patch ('config.main.read_json_file' , mock .MagicMock (
1261
+ side_effect = self .read_json_file_side_effect )):
1242
1262
(config , show ) = get_cmd_module
1243
1263
db = Db ()
1244
1264
golden_config = {}
@@ -1251,6 +1271,51 @@ def read_json_file_side_effect(filename):
1251
1271
assert "TSA" in result .output
1252
1272
assert "[WARNING] Golden configuration may override Traffic-shift-away state" in result .output
1253
1273
1274
+ def test_config_file_yang_validation (self ):
1275
+ # Test with empty config
1276
+ with mock .patch ('config.main.read_json_file' , return_value = "" ) as mock_read_json_file :
1277
+ with mock .patch ('config.main.sonic_yang.SonicYang.loadYangModel' ) as mock_load_yang_model :
1278
+ assert not config_file_yang_validation ('dummy_file.json' )
1279
+ mock_read_json_file .assert_called_once_with ('dummy_file.json' )
1280
+ mock_load_yang_model .assert_not_called ()
1281
+
1282
+ # Test with non-dict config
1283
+ with mock .patch ('config.main.read_json_file' , return_value = []) as mock_read_json_file :
1284
+ with mock .patch ('config.main.sonic_yang.SonicYang.loadYangModel' ) as mock_load_yang_model :
1285
+ assert not config_file_yang_validation ('dummy_file.json' )
1286
+ mock_read_json_file .assert_called_once_with ('dummy_file.json' )
1287
+ mock_load_yang_model .assert_not_called ()
1288
+
1289
+ # Test with missing namespaces in multi-ASIC config
1290
+ with mock .patch ('config.main.read_json_file' , return_value = {'localhost' : {}}) as mock_read_json_file :
1291
+ with mock .patch ('config.main.multi_asic.is_multi_asic' , return_value = True ):
1292
+ with mock .patch ('config.main.multi_asic.get_namespace_list' , return_value = ['asic0' , 'asic1' ]):
1293
+ with mock .patch ('config.main.sonic_yang.SonicYang.loadYangModel' ) as mock_load_yang_model :
1294
+ assert not config_file_yang_validation ('dummy_file.json' )
1295
+ mock_read_json_file .assert_called_once_with ('dummy_file.json' )
1296
+ mock_load_yang_model .assert_not_called ()
1297
+
1298
+ # Test with valid config
1299
+ valid_config = {
1300
+ 'DEVICE_METADATA' : {
1301
+ 'localhost' : {
1302
+ 'platform' : 'x86_64-mlnx_msn2700-r0' ,
1303
+ 'mac' : '00:02:03:04:05:07'
1304
+ }
1305
+ }
1306
+ }
1307
+
1308
+ with mock .patch ('config.main.read_json_file' , return_value = valid_config ) as mock_read_json_file , \
1309
+ mock .patch ('config.main.multi_asic.is_multi_asic' , return_value = False ), \
1310
+ mock .patch ('config.main.sonic_yang.SonicYang.loadYangModel' ) as mock_load_yang_model , \
1311
+ mock .patch ('config.main.sonic_yang.SonicYang.loadData' ) as mock_load_data , \
1312
+ mock .patch ('config.main.sonic_yang.SonicYang.validate_data_tree' ) as mock_validate_data_tree :
1313
+ assert config_file_yang_validation ('dummy_file.json' )
1314
+ mock_read_json_file .assert_called_once_with ('dummy_file.json' )
1315
+ mock_load_yang_model .assert_called_once ()
1316
+ mock_load_data .assert_called_once_with (configdbJson = valid_config )
1317
+ mock_validate_data_tree .assert_called_once ()
1318
+
1254
1319
@classmethod
1255
1320
def teardown_class (cls ):
1256
1321
os .environ ['UTILITIES_UNIT_TESTING' ] = "0"
0 commit comments