|
13 | 13 | from concurrent.futures import as_completed, ThreadPoolExecutor |
14 | 14 | from contextlib import contextmanager, suppress |
15 | 15 | from time import sleep, time |
16 | | -from typing import Dict, Generator, List, Optional, Sequence, Tuple |
| 16 | +from typing import Dict, Generator, List, Optional, Sequence, Tuple, Union |
17 | 17 |
|
18 | 18 | import grpc |
19 | 19 | import pytest |
|
22 | 22 | from google.protobuf.text_format import MessageToString |
23 | 23 | from google.protobuf.wrappers_pb2 import StringValue, UInt32Value |
24 | 24 | from retina.client.exception import ErrorReportedByAgent |
| 25 | +from retina.client.manager import RetinaTestManager |
25 | 26 | from retina.launcher.artifacts import RetinaTestData |
| 27 | +from retina.launcher.public import MetricsSummary |
| 28 | +from retina.launcher.utils import configure_artifacts |
26 | 29 | from retina.protocol import RanStub |
27 | 30 | from retina.protocol.base_pb2 import ( |
28 | 31 | ChannelEmulatorType, |
|
57 | 60 | ) |
58 | 61 | from retina.protocol.ue_pb2_grpc import UEStub |
59 | 62 |
|
| 63 | +from .configuration import configure_test_parameters |
| 64 | +from .kpis import get_kpis |
| 65 | + |
| 66 | +BITRATE_THRESHOLD: float = 0.1 |
60 | 67 | RF_MAX_TIMEOUT: int = 5 * 60 # Time enough in RF when loading a new image in the sdr |
61 | 68 | UE_STARTUP_TIMEOUT: int = RF_MAX_TIMEOUT |
62 | 69 | GNB_STARTUP_TIMEOUT: int = 2 # GNB delay (we wait x seconds and check it's still alive). UE later and has a big timeout |
@@ -856,6 +863,160 @@ def ue_move( |
856 | 863 | logging.info("UE [%s] moved to position %s, %s, %s", id(ue_stub), x_coordinate, y_coordinate, z_coordinate) |
857 | 864 |
|
858 | 865 |
|
| 866 | +# pylint: disable=too-many-arguments,too-many-positional-arguments,too-many-locals |
| 867 | +@contextmanager |
| 868 | +def multi_ue_mobility_iperf( |
| 869 | + *, # This enforces keyword-only arguments |
| 870 | + retina_manager: RetinaTestManager, |
| 871 | + retina_data: RetinaTestData, |
| 872 | + ue_array: Sequence[UEStub], |
| 873 | + fivegc: FiveGCStub, |
| 874 | + gnb_array: Sequence[GNBStub], |
| 875 | + metrics_summary: Optional[MetricsSummary], |
| 876 | + band: int, |
| 877 | + common_scs: int, |
| 878 | + bandwidth: int, |
| 879 | + bitrate: int, |
| 880 | + protocol: IPerfProto, |
| 881 | + direction: IPerfDir, |
| 882 | + sample_rate: Optional[int], |
| 883 | + global_timing_advance: int, |
| 884 | + time_alignment_calibration: Union[int, str], |
| 885 | + always_download_artifacts: bool, |
| 886 | + noise_spd: int, |
| 887 | + warning_as_errors: bool = True, |
| 888 | + movement_steps: int = 10, |
| 889 | + sleep_between_movement_steps: int = 2, |
| 890 | + cell_position_offset: Tuple[float, float, float] = (1000, 0, 0), |
| 891 | + allow_failure: bool = False, |
| 892 | +) -> Generator[ |
| 893 | + Tuple[ |
| 894 | + Dict[UEStub, UEAttachedInfo], |
| 895 | + Tuple[Tuple[Tuple[float, float, float], Tuple[float, float, float], int, int], ...], |
| 896 | + int, |
| 897 | + ], |
| 898 | + None, |
| 899 | + None, |
| 900 | +]: |
| 901 | + """ |
| 902 | + Do mobility with multiple UEs |
| 903 | + """ |
| 904 | + |
| 905 | + logging.info("Mobility Test (iPerf%s)", ", allowing failure)" if allow_failure else "") |
| 906 | + |
| 907 | + original_position = (0, 0, 0) |
| 908 | + |
| 909 | + configure_test_parameters( |
| 910 | + retina_manager=retina_manager, |
| 911 | + retina_data=retina_data, |
| 912 | + band=band, |
| 913 | + common_scs=common_scs, |
| 914 | + bandwidth=bandwidth, |
| 915 | + sample_rate=sample_rate, |
| 916 | + global_timing_advance=global_timing_advance, |
| 917 | + time_alignment_calibration=time_alignment_calibration, |
| 918 | + noise_spd=noise_spd, |
| 919 | + num_cells=2, |
| 920 | + cell_position_offset=cell_position_offset, |
| 921 | + log_ip_level="debug", |
| 922 | + warning_allowlist=[ |
| 923 | + "MAC max KOs reached", |
| 924 | + "Reached maximum number of RETX", |
| 925 | + "UL buffering timed out", |
| 926 | + 'RRC Setup Procedure" timed out', |
| 927 | + 'RRC Reconfiguration Procedure" timed out', |
| 928 | + 'Intra CU Handover Target Routine" failed', |
| 929 | + "RRC reconfiguration failed", |
| 930 | + "Some or all PDUSessionResourceSetupItems failed to setup", |
| 931 | + "UL buffering timed out", |
| 932 | + "Discarding SDU", |
| 933 | + "Discarding PDU", |
| 934 | + "PDCP unpacking did not provide any SDU", |
| 935 | + "Could not allocate Paging's DCI in PDCCH", |
| 936 | + ], |
| 937 | + ) |
| 938 | + |
| 939 | + configure_artifacts( |
| 940 | + retina_data=retina_data, |
| 941 | + always_download_artifacts=always_download_artifacts, |
| 942 | + ) |
| 943 | + |
| 944 | + start_network( |
| 945 | + ue_array=ue_array, |
| 946 | + gnb_array=gnb_array, |
| 947 | + fivegc=fivegc, |
| 948 | + gnb_post_cmd=("log --cu_level=debug --hex_max_size=32", "log --mac_level=debug"), |
| 949 | + ) |
| 950 | + |
| 951 | + ue_attach_info_dict = ue_start_and_attach( |
| 952 | + ue_array=ue_array, |
| 953 | + du_definition=[gnb.GetDefinition(UInt32Value(value=idx)) for idx, gnb in enumerate(gnb_array)], |
| 954 | + fivegc=fivegc, |
| 955 | + ) |
| 956 | + |
| 957 | + try: |
| 958 | + # HO while iPerf |
| 959 | + movement_duration = (movement_steps + 1) * sleep_between_movement_steps |
| 960 | + movements: Tuple[Tuple[Tuple[float, float, float], Tuple[float, float, float], int, int], ...] = ( |
| 961 | + (original_position, cell_position_offset, movement_steps, sleep_between_movement_steps), |
| 962 | + (cell_position_offset, original_position, movement_steps, sleep_between_movement_steps), |
| 963 | + (original_position, cell_position_offset, movement_steps, sleep_between_movement_steps), |
| 964 | + (cell_position_offset, original_position, movement_steps, sleep_between_movement_steps), |
| 965 | + ) |
| 966 | + traffic_seconds = (len(movements) * movement_duration) + len(ue_array) |
| 967 | + |
| 968 | + # Starting iperf in the UEs |
| 969 | + iperf_array = [] |
| 970 | + for ue_stub in ue_array: |
| 971 | + iperf_array.append( |
| 972 | + ( |
| 973 | + ue_attach_info_dict[ue_stub], |
| 974 | + *iperf_start( |
| 975 | + ue_stub=ue_stub, |
| 976 | + ue_attached_info=ue_attach_info_dict[ue_stub], |
| 977 | + fivegc=fivegc, |
| 978 | + protocol=protocol, |
| 979 | + direction=direction, |
| 980 | + duration=traffic_seconds, |
| 981 | + bitrate=bitrate, |
| 982 | + ), |
| 983 | + ) |
| 984 | + ) |
| 985 | + |
| 986 | + yield ue_attach_info_dict, movements, traffic_seconds |
| 987 | + |
| 988 | + # Stop and validate iperfs. |
| 989 | + if allow_failure: |
| 990 | + # The BITRATE_THRESHOLD is reduced because of noise and possible handover failures |
| 991 | + bitrate_threshold = BITRATE_THRESHOLD * 0.05 |
| 992 | + else: |
| 993 | + bitrate_threshold = BITRATE_THRESHOLD |
| 994 | + |
| 995 | + for ue_attached_info, task, iperf_request in iperf_array: |
| 996 | + iperf_wait_until_finish( |
| 997 | + ue_attached_info=ue_attached_info, |
| 998 | + fivegc=fivegc, |
| 999 | + task=task, |
| 1000 | + iperf_request=iperf_request, |
| 1001 | + bitrate_threshold_ratio=bitrate_threshold, |
| 1002 | + ) |
| 1003 | + |
| 1004 | + if not allow_failure: |
| 1005 | + for ue_stub in ue_array: |
| 1006 | + ue_validate_no_reattaches(ue_stub) |
| 1007 | + |
| 1008 | + stop( |
| 1009 | + ue_array=ue_array, |
| 1010 | + gnb_array=gnb_array, |
| 1011 | + fivegc=fivegc, |
| 1012 | + retina_data=retina_data, |
| 1013 | + ue_stop_timeout=16, |
| 1014 | + warning_as_errors=warning_as_errors, |
| 1015 | + ) |
| 1016 | + finally: |
| 1017 | + get_kpis(du_or_gnb_array=gnb_array, ue_array=ue_array, metrics_summary=metrics_summary) |
| 1018 | + |
| 1019 | + |
859 | 1020 | def ue_expect_handover(*, ue_stub: UEStub, timeout: int) -> grpc.Future: # The "*" enforces keyword-only arguments |
860 | 1021 | """ |
861 | 1022 | Creates a future object that will finish when a HO takes places or when the timeout is reached |
|
0 commit comments