|
2 | 2 | import pytest |
3 | 3 | from pathlib import Path |
4 | 4 | from collections import defaultdict |
5 | | -import re |
6 | 5 | import os |
7 | 6 | import json |
8 | | -import ast |
9 | 7 | import time |
10 | 8 |
|
11 | 9 | from tests.common.config_reload import config_reload |
12 | 10 | from tests.common.helpers.constants import DEFAULT_NAMESPACE |
13 | | -from tests.common.utilities import wait_until |
14 | | -from common.ha.smartswitch_ha_helper import PtfTcpTestAdapter |
15 | | -from common.ha.smartswitch_ha_io import SmartSwitchHaTrafficTest |
16 | | -from common.ha.smartswitch_ha_helper import ( |
| 11 | +from tests.common.ha.smartswitch_ha_helper import PtfTcpTestAdapter |
| 12 | +from tests.common.ha.smartswitch_ha_io import SmartSwitchHaTrafficTest |
| 13 | +from tests.common.ha.smartswitch_ha_helper import ( |
17 | 14 | add_port_to_namespace, |
18 | 15 | remove_namespace, |
19 | 16 | add_static_route_to_ptf, |
20 | 17 | add_static_route_to_dut |
21 | 18 | ) |
22 | 19 |
|
| 20 | +from ha_utils import ( |
| 21 | + |
| 22 | + build_dash_ha_scope_args, |
| 23 | + wait_for_pending_operation_id, |
| 24 | + build_dash_ha_scope_activate_args, |
| 25 | + wait_for_ha_state, |
| 26 | + build_dash_ha_set_args, |
| 27 | + proto_utils_hset |
| 28 | +) |
| 29 | + |
23 | 30 | logger = logging.getLogger(__name__) |
24 | 31 |
|
25 | 32 |
|
@@ -417,194 +424,7 @@ def setup_ha_config(duthosts): |
417 | 424 | return final_cfg |
418 | 425 |
|
419 | 426 |
|
420 | | -def build_dash_ha_set_args(fields): |
421 | | - """ |
422 | | - Build args for DASH_HA_SET_CONFIG_TABLE |
423 | | - EXACTLY following the working CLI |
424 | | - """ |
425 | | - |
426 | | - version = str(fields["version"]) |
427 | | - if version.endswith(".0"): |
428 | | - version = version[:-2] |
429 | | - |
430 | | - return ( |
431 | | - f'version \\"{version}\\" ' |
432 | | - f'vip_v4 "{fields["vip_v4"]}" ' |
433 | | - f'vip_v6 "{fields["vip_v6"]}" ' |
434 | | - f'scope "{fields["scope"]}" ' |
435 | | - f'preferred_vdpu_id "{fields["preferred_vdpu_id"]}" ' |
436 | | - f'preferred_standalone_vdpu_index 0 ' |
437 | | - f'vdpu_ids \'["vdpu0_0","vdpu1_0"]\'' |
438 | | - ) |
439 | | - |
440 | | - |
441 | | -def build_dash_ha_scope_args(fields): |
442 | | - """ |
443 | | - Build args for DASH_HA_SCOPE_CONFIG_TABLE |
444 | | - EXACTLY following the working CLI |
445 | | - """ |
446 | | - |
447 | | - version = str(fields["version"]) |
448 | | - if version.endswith(".0"): |
449 | | - version = version[:-2] |
450 | | - |
451 | | - return ( |
452 | | - f'version \\"{version}\\" ' |
453 | | - f'disabled "{fields["disabled"]}" ' |
454 | | - f'desired_ha_state "{fields["desired_ha_state"]}" ' |
455 | | - f'ha_set_id "{fields["ha_set_id"]}" ' |
456 | | - f'owner "{fields["owner"]}"' |
457 | | - ) |
458 | | - |
459 | | - |
460 | | -def extract_pending_operations(text): |
461 | | - """ |
462 | | - Extract pending_operation_ids and pending_operation_types |
463 | | - and return list of (type, id) tuples. |
464 | | - """ |
465 | | - ids_match = re.search( |
466 | | - r'pending_operation_ids\s*\|\s*([^\|\r\n]+)', |
467 | | - text, |
468 | | - re.DOTALL, |
469 | | - ) |
470 | | - types_match = re.search( |
471 | | - r'pending_operation_types\s*\|\s*([^\|\r\n]+)', |
472 | | - text, |
473 | | - re.DOTALL, |
474 | | - ) |
475 | | - if not ids_match or not types_match: |
476 | | - return [] |
477 | | - |
478 | | - try: |
479 | | - ids = ast.literal_eval(f"'{ids_match.group(1)}'") |
480 | | - id_list = ids.split() |
481 | | - ids = id_list[0].split(',') |
482 | | - types = ast.literal_eval(f"'{types_match.group(1)}'") |
483 | | - type_list = types.split() |
484 | | - types = type_list[0].split(',') |
485 | | - except Exception: |
486 | | - return [] |
487 | | - |
488 | | - return list(zip(types, ids)) |
489 | | - |
490 | | - |
491 | | -def get_pending_operation_id(duthost, scope_key, expected_op_type): |
492 | | - """ |
493 | | - scope_key example: vdpu0_0:haset0_0 |
494 | | - expected_op_type example: ACTIVATE_ROLE |
495 | | - """ |
496 | | - cmd = ( |
497 | | - "docker exec dash-hadpu0 swbus-cli show hamgrd actor " |
498 | | - f"/hamgrd/0/ha-scope/{scope_key}" |
499 | | - ) |
500 | | - res = duthost.shell(cmd) |
501 | | - |
502 | | - pending_ops = extract_pending_operations(res["stdout"]) |
503 | | - |
504 | | - for op_type, op_id in pending_ops: |
505 | | - if op_type == expected_op_type: |
506 | | - return op_id |
507 | | - |
508 | | - return None |
509 | | - |
510 | | - |
511 | | -def build_dash_ha_scope_activate_args(fields, pending_id): |
512 | | - return ( |
513 | | - f'version \\"{fields["version"]}\\" ' |
514 | | - f'disabled {fields["disabled"]} ' |
515 | | - f'desired_ha_state "{fields["desired_ha_state"]}" ' |
516 | | - f'ha_set_id "{fields["ha_set_id"]}" ' |
517 | | - f'owner "{fields["owner"]}" ' |
518 | | - f'approved_pending_operation_ids ' |
519 | | - f'[\\\"{pending_id}\\\"]' |
520 | | - ) |
521 | | - |
522 | | - |
523 | | -def proto_utils_hset(duthost, table, key, args): |
524 | | - """ |
525 | | - Wrapper around proto_utils.py hset |
526 | | -
|
527 | | - Args: |
528 | | - duthost: pytest duthost fixture |
529 | | - table (str): Redis table name |
530 | | - key (str): Redis key |
531 | | - args (str): Already-built proto args string |
532 | | - """ |
533 | | - cmd = ( |
534 | | - "docker exec swss python /etc/sonic/proto_utils.py hset " |
535 | | - f'"{table}:{key}" {args}' |
536 | | - ) |
537 | | - duthost.shell(cmd) |
538 | | - |
539 | | - |
540 | | -def wait_for_pending_operation_id( |
541 | | - duthost, |
542 | | - scope_key, |
543 | | - expected_op_type, |
544 | | - timeout=60, |
545 | | - interval=2, |
546 | | -): |
547 | | - """ |
548 | | - Wait until the expected pending_operation_id appears. |
549 | | - """ |
550 | | - pending_id = None |
551 | | - |
552 | | - def _condition(): |
553 | | - nonlocal pending_id |
554 | | - pending_id = get_pending_operation_id( |
555 | | - duthost, |
556 | | - scope_key, |
557 | | - expected_op_type, |
558 | | - ) |
559 | | - return pending_id is not None |
560 | | - |
561 | | - success = wait_until( |
562 | | - timeout, |
563 | | - interval, |
564 | | - 0, # REQUIRED delay argument |
565 | | - _condition, # condition callable |
566 | | - ) |
567 | | - |
568 | | - return pending_id if success else None |
569 | | - |
570 | | - |
571 | | -def extract_ha_state(text): |
572 | | - """ |
573 | | - Extract ha_state from swbus-cli output |
574 | | - """ |
575 | | - match = re.search(r'ha_state\s+\|\s+(\w+)', text) |
576 | | - return match.group(1) if match else None |
577 | | - |
578 | | - |
579 | | -def wait_for_ha_state( |
580 | | - duthost, |
581 | | - scope_key, |
582 | | - expected_state, |
583 | | - timeout=120, |
584 | | - interval=5, |
585 | | -): |
586 | | - """ |
587 | | - Wait until HA reaches the expected state |
588 | | - """ |
589 | | - def _check_ha_state(): |
590 | | - cmd = ( |
591 | | - "docker exec dash-hadpu0 swbus-cli show hamgrd actor " |
592 | | - f"/hamgrd/0/ha-scope/{scope_key}" |
593 | | - ) |
594 | | - res = duthost.shell(cmd) |
595 | | - return extract_ha_state(res["stdout"]) == expected_state |
596 | | - |
597 | | - success = wait_until( |
598 | | - timeout, |
599 | | - interval, |
600 | | - 0, |
601 | | - _check_ha_state |
602 | | - ) |
603 | | - |
604 | | - return success |
605 | | - |
606 | | - |
607 | | -@pytest.fixture(scope="module") |
| 427 | +@pytest.fixture(scope="function") |
608 | 428 | def setup_dash_ha_from_json(duthosts): |
609 | 429 | base_dir = "/data/tests/common/ha" |
610 | 430 | ha_set_file = os.path.join(base_dir, "dash_ha_set_dpu_config_table.json") |
@@ -659,7 +479,7 @@ def setup_dash_ha_from_json(duthosts): |
659 | 479 | ) |
660 | 480 |
|
661 | 481 |
|
662 | | -@pytest.fixture(scope="module") |
| 482 | +@pytest.fixture(scope="function") |
663 | 483 | def activate_dash_ha_from_json(duthosts): |
664 | 484 | # ------------------------------------------------- |
665 | 485 | # Step 4: Activate Role (using pending_operation_ids) |
|
0 commit comments