From 832c2afe61d82996af055dfb352f44a0b4a9df97 Mon Sep 17 00:00:00 2001 From: Jitendrakumar Kushavah <78074038+jitendracandela@users.noreply.github.com> Date: Thu, 20 Jun 2024 17:06:22 +0530 Subject: [PATCH 01/18] Add hfcl_ion4xi to the overview page (#948) Signed-off-by: jitendracandela --- .allure-overview/overviews.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.allure-overview/overviews.json b/.allure-overview/overviews.json index a63207ce60..54c96e6287 100644 --- a/.allure-overview/overviews.json +++ b/.allure-overview/overviews.json @@ -1,7 +1,7 @@ { "sanity": { "OVERVIEW_TITLE": "'OpenWifi sanity results'", - "OVERVIEW_TESTBEDS": ["edgecore_oap101-6e","edgecore_eap101","cig_wf188n","cig_wf196","edgecore_eap102","edgecore_eap104","cig_wf186w","hfcl_ion4xe","yuncore_fap655","yuncore_ax820","edgecore_eap111"] + "OVERVIEW_TESTBEDS": ["edgecore_oap101-6e","edgecore_eap101","cig_wf188n","cig_wf196","edgecore_eap102","edgecore_eap104","cig_wf186w","hfcl_ion4xe","yuncore_fap655","yuncore_ax820","edgecore_eap111","hfcl_ion4xi"] }, "interop": { "OVERVIEW_TITLE": "'OpenWifi interop results'", @@ -15,6 +15,6 @@ "performance": { "OVERVIEW_TITLE": "'OpenWifi performance results'", - "OVERVIEW_TESTBEDS": ["edgecore_oap101-6e","edgecore_eap101","cig_wf188n","cig_wf196","edgecore_eap102","edgecore_eap104","cig_wf186w","hfcl_ion4xe","yuncore_fap655","yuncore_ax820","edgecore_eap111"] + "OVERVIEW_TESTBEDS": ["edgecore_oap101-6e","edgecore_eap101","cig_wf188n","cig_wf196","edgecore_eap102","edgecore_eap104","cig_wf186w","hfcl_ion4xe","yuncore_fap655","yuncore_ax820","edgecore_eap111","hfcl_ion4xi"] } } From 8c4ec7bd53216c1ec07154698c9f207d656c9d69 Mon Sep 17 00:00:00 2001 From: mythri-candela <168416732+mythri-candela@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:26:47 +0530 Subject: [PATCH 02/18] Update ucentralgw-qa-deployment.yaml (#949) --- .github/workflows/ucentralgw-qa-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ucentralgw-qa-deployment.yaml b/.github/workflows/ucentralgw-qa-deployment.yaml index 2b76c1d4c1..4d887c24b4 100644 --- a/.github/workflows/ucentralgw-qa-deployment.yaml +++ b/.github/workflows/ucentralgw-qa-deployment.yaml @@ -34,7 +34,7 @@ env: { "namespace": "qa01", "deploy_method": "git", - "chart_version": "v3.1.0-RC1", + "chart_version": "v3.1.0-RC2", "owgw_version": "master", "owsec_version": "main", "owfms_version": "main", From c56c4f8e80118d5d203141cde25f1ec907cadb53 Mon Sep 17 00:00:00 2001 From: Jitendrakumar Kushavah <78074038+jitendracandela@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:52:48 +0530 Subject: [PATCH 03/18] Added udaya_a6-id2 to the sanity and performance overview page (#950) Signed-off-by: jitendracandela --- .allure-overview/overviews.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.allure-overview/overviews.json b/.allure-overview/overviews.json index 54c96e6287..4c61b96bec 100644 --- a/.allure-overview/overviews.json +++ b/.allure-overview/overviews.json @@ -1,7 +1,7 @@ { "sanity": { "OVERVIEW_TITLE": "'OpenWifi sanity results'", - "OVERVIEW_TESTBEDS": ["edgecore_oap101-6e","edgecore_eap101","cig_wf188n","cig_wf196","edgecore_eap102","edgecore_eap104","cig_wf186w","hfcl_ion4xe","yuncore_fap655","yuncore_ax820","edgecore_eap111","hfcl_ion4xi"] + "OVERVIEW_TESTBEDS": ["edgecore_oap101-6e","edgecore_eap101","cig_wf188n","cig_wf196","edgecore_eap102","edgecore_eap104","cig_wf186w","hfcl_ion4xe","yuncore_fap655","yuncore_ax820","edgecore_eap111","hfcl_ion4xi","udaya_a6-id2"] }, "interop": { "OVERVIEW_TITLE": "'OpenWifi interop results'", @@ -15,6 +15,6 @@ "performance": { "OVERVIEW_TITLE": "'OpenWifi performance results'", - "OVERVIEW_TESTBEDS": ["edgecore_oap101-6e","edgecore_eap101","cig_wf188n","cig_wf196","edgecore_eap102","edgecore_eap104","cig_wf186w","hfcl_ion4xe","yuncore_fap655","yuncore_ax820","edgecore_eap111","hfcl_ion4xi"] + "OVERVIEW_TESTBEDS": ["edgecore_oap101-6e","edgecore_eap101","cig_wf188n","cig_wf196","edgecore_eap102","edgecore_eap104","cig_wf186w","hfcl_ion4xe","yuncore_fap655","yuncore_ax820","edgecore_eap111","hfcl_ion4xi","udaya_a6-id2"] } } From e96df54c0241b1a5e2e813c32b79907b61da0bb6 Mon Sep 17 00:00:00 2001 From: Carsten Schafer <49571202+carsten989@users.noreply.github.com> Date: Wed, 26 Jun 2024 17:22:10 -0400 Subject: [PATCH 04/18] WIFI-13871 CGW deploy testing (#951) Signed-off-by: Carsten Schafer Co-authored-by: Carsten Schafer --- .github/workflows/cgw-dev-deployment.yaml | 126 ++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 .github/workflows/cgw-dev-deployment.yaml diff --git a/.github/workflows/cgw-dev-deployment.yaml b/.github/workflows/cgw-dev-deployment.yaml new file mode 100644 index 0000000000..8a3c4efe42 --- /dev/null +++ b/.github/workflows/cgw-dev-deployment.yaml @@ -0,0 +1,126 @@ +name: Update CGW01 OpenLAN Cloud Gateway on tip-wlan-main + +defaults: + run: + shell: bash + +env: + AWS_EKS_NAME: tip-wlan-main + AWS_DEFAULT_OUTPUT: json + AWS_DEFAULT_REGION: ap-south-1 + AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_CLIENT_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_CLIENT_KEY }} + +# # https://stackoverflow.com/questions/59977364/github-actions-how-use-strategy-matrix-with-script +# # Required object fiels per environment: +# # - namespace - namespace suffix that will used added for the Kubernetes environment (i.e. if you pass 'test', kubernetes namespace will be named 'openlan-test') +# # - cgw_version - OpenLAN Cloud Gateway version to deploy (will be used for Docker image tag and git branch for Helm chart if git deployment is required) +# # - just_component - if true then deploy only cgw chart + testbeds: '[ + { + "namespace": "cgw01", + "cgw_version": "main", + "just_component": "false" + } + ]' + +on: + workflow_dispatch: + inputs: + just_component: + default: 'false' + description: 'Just deploy component, not all the other services' + required: true + id: + description: 'run identifier' + required: false + +jobs: + id: + name: Workflow ID Provider + runs-on: ubuntu-latest + steps: + - name: ${{ github.event.inputs.id }} + run: echo run identifier ${{ inputs.id }} + + generate-matrix: + name: Generate matrix for build + runs-on: ubuntu-latest + needs: + - id + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - name: generate-matrix + id: set-matrix + run: | + cat >> $GITHUB_OUTPUT << EOF + matrix={"include":${{ env.testbeds }}} + EOF + + deploy: + name: Update OpenLAN Cloud SDK instances + runs-on: ubuntu-latest + needs: + - id + - generate-matrix + strategy: + matrix: ${{ fromJson( needs.generate-matrix.outputs.matrix ) }} + fail-fast: false + steps: + + - name: Checkout repo with Helm values + uses: actions/checkout@v4 + with: + repository: Telecominfraproject/wlan-cloud-ucentral-deploy + path: wlan-cloud-ucentral-deploy + ref: ${{ matrix.chart_version }} + + - name: Fetch kubeconfig + run: | + aws eks update-kubeconfig --name ${{ env.AWS_EKS_NAME }} + + - name: Install kubectl, helmfile and plugins + run: | + curl -s -LO "https://dl.k8s.io/release/v1.27.14/bin/linux/amd64/kubectl" + sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + curl -s -LO "https://github.com/helmfile/helmfile/releases/download/v0.165.0/helmfile_0.165.0_linux_amd64.tar.gz" + tar xvzf helmfile_0.165.0_linux_amd64.tar.gz helmfile + sudo install -o root -g root -m 0755 helmfile /usr/local/bin/helmfile + helm plugin install https://github.com/aslafy-z/helm-git --version 0.16.0 + helm plugin install https://github.com/databus23/helm-diff + helm plugin install https://github.com/jkroepke/helm-secrets + + - name: Deploy OpenLAN Cloud Gateway and services + if: {{ github.event.inputs.just_component }} == "false" + working-directory: wlan-cloud-ucentral-deploy/cgw + run: | + helmfile --environment ${{ matrix.namespace }} apply + + - name: Deploy OpenLAN Cloud Gateway only + if: {{ github.event.inputs.just_component }} == "true" + working-directory: wlan-cloud-ucentral-deploy/cgw + run: | + helmfile --environment ${{ matrix.namespace }} -l app=cgw apply + + - name: Show resource state on deployment failure + if: failure() + run: | + echo "Pods:" + kubectl get pods --namespace openlan-${{ matrix.namespace }} + echo "Pod Descriptions:" + kubectl describe pods --namespace openlan-${{ matrix.namespace }} + echo "Services:" + kubectl get services --namespace openlan-${{ matrix.namespace }} + echo "Service Descriptions:" + kubectl describe services --namespace openlan-${{ matrix.namespace }} + echo "PVCs:" + kubectl get persistentvolumeclaims --namespace openlan-${{ matrix.namespace }} + echo "PVC Descriptions:" + kubectl describe persistentvolumeclaims --namespace openlan-${{ matrix.namespace }} + +# - name: Rollback Cloud SDK +# if: failure() +# run: | +# helm rollback tip-openlan --namespace openlan-${{ matrix.namespace }} --wait --timeout 20m From 8d98e38daaac5465120fd99a2b93e7cabec680f2 Mon Sep 17 00:00:00 2001 From: Anil Kumar Tegala Date: Thu, 27 Jun 2024 15:08:02 +0530 Subject: [PATCH 05/18] add roam ota twog & fiveg wpa2psk test (#952) * add roam ota twog and fiveg wpa2 psk test Signed-off-by: anil-tegala * set missing band in 2G config Signed-off-by: anil-tegala --------- Signed-off-by: anil-tegala --- .../roam_test/hard_roam/OTA/test_roam_ota.py | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py index 3aece8bd15..8a62170cb4 100644 --- a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py +++ b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py @@ -1568,3 +1568,124 @@ def test_roam_6g_to_6g_sc_eap_wpa3(self, get_target_object, get_test_library, ge pytest.fail(f"Test failed with the following reasons: \n{message}") else: assert True + + @pytest.mark.roam + @pytest.mark.fiveg + @pytest.mark.twog + @pytest.mark.wpa2_personal + def test_roam_5g_and_2g_wpa2psk(self, get_target_object, get_test_library, get_lab_info, selected_testbed): + """ + Test Roaming between two APs, 2G & 5G, WPA2 Personal + pytest -m "roam and fiveg and twog and wpa2_personal and ota" + """ + ap_data = dict() + dut_list = [str(selected_testbed)] + dut_names = list() + bssid_list = list() + freqs_ = "" + testbed_info = get_lab_info.CONFIGURATION + config = copy.deepcopy(config_data) + temp_list = list() + for key, val in testbed_info.items(): + tb_type, tb_name = selected_testbed.split("-") + if tb_type in key and tb_name[0] in key: + temp_list.append(key) + temp_list.sort() + dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] + config['radios'] = [ + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] + if len(dut_list) < 2: + logging.error( + f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") + assert False, f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}" + for ap in range(len(dut_list)): + serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] + dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) + if ap == 1: + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] + config['radios'] = [ + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 20, "country": "CA"}] + logging.info(config) + payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} + uri = get_target_object.controller_library_object.build_uri( + "device/" + serial_number + "/configure") + logging.info("Sending Command: " + "\n" + str(uri) + "\n" + + "TimeStamp: " + str(datetime.datetime.utcnow()) + "\n" + + "Data: " + str(json.dumps(payload, indent=2)) + "\n" + + "Headers: " + str(get_target_object.controller_library_object.make_headers())) + allure.attach(name=f"Push roam config on {serial_number}: ", body="Sending Command: " + str(uri) + "\n" + + "TimeStamp: " + str( + datetime.datetime.utcnow()) + "\n" + + "Data: " + str(payload) + "\n" + + "Headers: " + str( + get_target_object.controller_library_object.make_headers())) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + allure.attach(name=f"Response - {resp.status_code} {resp.reason}", body=str(resp.json())) + if resp.status_code != 200: + if resp.status_code == 400 and "Device is already executing a command. Please try later." in \ + resp.json()["ErrorDescription"]: + time.sleep(30) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + else: + assert False, f"push configuration to {serial_number} got failed" + get_target_object.dut_library_object.device_under_tests_data = testbed_info[dut_list[ap]][ + "device_under_tests"] + ap_iwinfo = get_target_object.dut_library_object.get_iwinfo(attach_allure=True) + if str(ap_iwinfo) != "Error: pop from empty list": + include_essid = config['interfaces'][0]["ssids"][0]["name"] + re_obj = re.compile( + rf'(wlan\d(?:-\d)?)\s+ESSID: "{re.escape(include_essid)}".*?\s+Access Point:\s+([0-9A-Fa-f:]+).*?Channel:\s+(' + r'\d+)\s+\(([\d.]+) GHz\)', + re.DOTALL + ) + # find all matches + interface_matches = re_obj.finditer(ap_iwinfo) + if interface_matches: + for match in interface_matches: + interface_name = match.group(1) + access_point = match.group(2) + channel = match.group(3) + frequency = match.group(4).replace('.', '') + ap_data.update( + {serial_number: {'Access Point': access_point, 'Channel': channel, 'frequency': frequency}}) + logging.info(f"AP Data from iwinfo: {ap_data}") + else: + logging.error("Failed to get iwinfo") + pytest.exit("Failed to get iwinfo") + elif ap_iwinfo == {}: + pytest.fail("Empty iwinfo reponse from AP through minicom") + else: + pytest.fail("Failed to get iwinfo from minicom") + for serial in ap_data: + bssid_list.append(ap_data[serial]['Access Point']) + if not ap_data[serial]['frequency'].endswith(","): + freqs_ = freqs_ + ap_data[serial]['frequency'] + "," + else: + freqs_ = freqs_ + ap_data[serial]['frequency'] + ssid = config['interfaces'][0]["ssids"][0]["name"] + key = config['interfaces'][0]["ssids"][0]["encryption"]["key"] + try: + pass_fail, message = get_test_library.roam_test(ap1_bssid=bssid_list[0], ap2_bssid=bssid_list[1], + scan_freq=freqs_, + band="both", num_sta=2, security="wpa2", security_key=key, + ssid=ssid, upstream="1.1.eth1", duration=None, + iteration=1, channel="36", option="ota", dut_name=dut_names, + traffic_type="lf_udp", sta_type="11r") + except Exception as e: + logging.error(f"Exception in roam test : {e}") + pass_fail, message = False, e + finally: + get_target_object.dut_library_object.get_dut_logs(print_log=False) + if not pass_fail: + pytest.fail(f"Test failed with the following reasons: \n{message}") + else: + assert True \ No newline at end of file From 016f766466562b50e8f7dd5691c4ed5ad3d809c6 Mon Sep 17 00:00:00 2001 From: Jitendrakumar Kushavah <78074038+jitendracandela@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:38:17 +0530 Subject: [PATCH 06/18] Wifi 13874 (#953) * Added more logs to asb script Signed-off-by: jitendracandela * Increased sleep time after factory reset for ASB tests Signed-off-by: jitendracandela --------- Signed-off-by: jitendracandela --- libs/tip_2x/ap_lib.py | 2 +- libs/tip_2x/controller.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/tip_2x/ap_lib.py b/libs/tip_2x/ap_lib.py index ab4b9a49f9..c4ec2fc534 100644 --- a/libs/tip_2x/ap_lib.py +++ b/libs/tip_2x/ap_lib.py @@ -579,7 +579,7 @@ def add_restrictions(self, restrictions_file, developer_mode): expected_attachment_type=allure.attachment_type.TEXT, restrictions=True) self.factory_reset(print_log=False) - time.sleep(120) + time.sleep(300) return output diff --git a/libs/tip_2x/controller.py b/libs/tip_2x/controller.py index a6b9d38cf7..e30e101929 100644 --- a/libs/tip_2x/controller.py +++ b/libs/tip_2x/controller.py @@ -918,8 +918,10 @@ def check_restrictions(self, serial_number): def asb_script(self, serial_number, payload): uri = self.build_uri("device/" + serial_number + "/script") + logging.info("uri:- " + str(uri)) payload = json.dumps(payload) resp = requests.post(uri, data=payload, headers=self.make_headers(), verify=False, timeout=120) + logging.info("resp:- " + str(resp)) resp = resp.json() resp = resp['UUID'] return resp From bcf55b6f4585e5d42f522cd58e0737e9c790980c Mon Sep 17 00:00:00 2001 From: Anil Kumar Tegala Date: Thu, 27 Jun 2024 15:42:34 +0530 Subject: [PATCH 07/18] roam ota twog and fiveg wpa3psk test (#954) * add roam ota twog and fiveg wpa2 psk test Signed-off-by: anil-tegala * add roam ota twog and fiveg wpa3 psk test Signed-off-by: anil-tegala * set missing band in 2G config Signed-off-by: anil-tegala --------- Signed-off-by: anil-tegala --- .../roam_test/hard_roam/OTA/test_roam_ota.py | 247 +++++++++++++++++- 1 file changed, 246 insertions(+), 1 deletion(-) diff --git a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py index 8a62170cb4..52280b8cc9 100644 --- a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py +++ b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py @@ -1688,4 +1688,249 @@ def test_roam_5g_and_2g_wpa2psk(self, get_target_object, get_test_library, get_l if not pass_fail: pytest.fail(f"Test failed with the following reasons: \n{message}") else: - assert True \ No newline at end of file + assert True + + @pytest.mark.roam + @pytest.mark.fiveg + @pytest.mark.twog + @pytest.mark.wpa2_personal + def test_roam_5g_and_2g_wpa2psk(self, get_target_object, get_test_library, get_lab_info, selected_testbed): + """ + Test Roaming between two APs, 2G & 5G, WPA2 Personal + pytest -m "roam and fiveg and twog and wpa2_personal and ota" + """ + ap_data = dict() + dut_list = [str(selected_testbed)] + dut_names = list() + bssid_list = list() + freqs_ = "" + testbed_info = get_lab_info.CONFIGURATION + config = copy.deepcopy(config_data) + temp_list = list() + for key, val in testbed_info.items(): + tb_type, tb_name = selected_testbed.split("-") + if tb_type in key and tb_name[0] in key: + temp_list.append(key) + temp_list.sort() + dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] + config['radios'] = [ + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] + if len(dut_list) < 2: + logging.error( + f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") + assert False, f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}" + for ap in range(len(dut_list)): + serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] + dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) + if ap == 1: + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] + config['radios'] = [ + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 20, "country": "CA"}] + logging.info(config) + payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} + uri = get_target_object.controller_library_object.build_uri( + "device/" + serial_number + "/configure") + logging.info("Sending Command: " + "\n" + str(uri) + "\n" + + "TimeStamp: " + str(datetime.datetime.utcnow()) + "\n" + + "Data: " + str(json.dumps(payload, indent=2)) + "\n" + + "Headers: " + str(get_target_object.controller_library_object.make_headers())) + allure.attach(name=f"Push roam config on {serial_number}: ", body="Sending Command: " + str(uri) + "\n" + + "TimeStamp: " + str( + datetime.datetime.utcnow()) + "\n" + + "Data: " + str(payload) + "\n" + + "Headers: " + str( + get_target_object.controller_library_object.make_headers())) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + allure.attach(name=f"Response - {resp.status_code} {resp.reason}", body=str(resp.json())) + if resp.status_code != 200: + if resp.status_code == 400 and "Device is already executing a command. Please try later." in \ + resp.json()["ErrorDescription"]: + time.sleep(30) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + else: + assert False, f"push configuration to {serial_number} got failed" + get_target_object.dut_library_object.device_under_tests_data = testbed_info[dut_list[ap]][ + "device_under_tests"] + ap_iwinfo = get_target_object.dut_library_object.get_iwinfo(attach_allure=True) + if str(ap_iwinfo) != "Error: pop from empty list": + include_essid = config['interfaces'][0]["ssids"][0]["name"] + re_obj = re.compile( + rf'(wlan\d(?:-\d)?)\s+ESSID: "{re.escape(include_essid)}".*?\s+Access Point:\s+([0-9A-Fa-f:]+).*?Channel:\s+(' + r'\d+)\s+\(([\d.]+) GHz\)', + re.DOTALL + ) + # find all matches + interface_matches = re_obj.finditer(ap_iwinfo) + if interface_matches: + for match in interface_matches: + interface_name = match.group(1) + access_point = match.group(2) + channel = match.group(3) + frequency = match.group(4).replace('.', '') + ap_data.update( + {serial_number: {'Access Point': access_point, 'Channel': channel, 'frequency': frequency}}) + logging.info(f"AP Data from iwinfo: {ap_data}") + else: + logging.error("Failed to get iwinfo") + pytest.exit("Failed to get iwinfo") + elif ap_iwinfo == {}: + pytest.fail("Empty iwinfo reponse from AP through minicom") + else: + pytest.fail("Failed to get iwinfo from minicom") + for serial in ap_data: + bssid_list.append(ap_data[serial]['Access Point']) + if not ap_data[serial]['frequency'].endswith(","): + freqs_ = freqs_ + ap_data[serial]['frequency'] + "," + else: + freqs_ = freqs_ + ap_data[serial]['frequency'] + ssid = config['interfaces'][0]["ssids"][0]["name"] + key = config['interfaces'][0]["ssids"][0]["encryption"]["key"] + try: + pass_fail, message = get_test_library.roam_test(ap1_bssid=bssid_list[0], ap2_bssid=bssid_list[1], + scan_freq=freqs_, + band="both", num_sta=2, security="wpa2", security_key=key, + ssid=ssid, upstream="1.1.eth1", duration=None, + iteration=1, channel="36", option="ota", dut_name=dut_names, + traffic_type="lf_udp", sta_type="11r") + except Exception as e: + logging.error(f"Exception in roam test : {e}") + pass_fail, message = False, e + finally: + get_target_object.dut_library_object.get_dut_logs(print_log=False) + if not pass_fail: + pytest.fail(f"Test failed with the following reasons: \n{message}") + else: + assert True + + @pytest.mark.roam + @pytest.mark.fiveg + @pytest.mark.twog + @pytest.mark.sae + @pytest.mark.wpa3_personal + def test_roam_5g_and_2g_wpa3psk(self, get_target_object, get_test_library, get_lab_info, selected_testbed): + """ + Test Roaming between two APs, 2G & 5G, WPA3 Personal + pytest -m "roam and fiveg and twog and wpa3_personal and ota" + """ + ap_data = dict() + dut_list = [str(selected_testbed)] + dut_names = list() + bssid_list = list() + freqs_ = "" + testbed_info = get_lab_info.CONFIGURATION + config = copy.deepcopy(config_data) + temp_list = list() + for key, val in testbed_info.items(): + tb_type, tb_name = selected_testbed.split("-") + if tb_type in key and tb_name[0] in key: + temp_list.append(key) + temp_list.sort() + dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] + config['radios'] = [ + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] + # change ssid config data to sae + config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "sae" + if len(dut_list) < 2: + logging.error( + f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") + assert False, f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}" + for ap in range(len(dut_list)): + serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] + dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) + if ap == 1: + config['radios'] = [ + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 20, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] + logging.info(config) + payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} + uri = get_target_object.controller_library_object.build_uri( + "device/" + serial_number + "/configure") + logging.info("Sending Command: " + "\n" + str(uri) + "\n" + + "TimeStamp: " + str(datetime.datetime.utcnow()) + "\n" + + "Data: " + str(json.dumps(payload, indent=2)) + "\n" + + "Headers: " + str(get_target_object.controller_library_object.make_headers())) + allure.attach(name=f"Push roam config on {serial_number}: ", body="Sending Command: " + str(uri) + "\n" + + "TimeStamp: " + str( + datetime.datetime.utcnow()) + "\n" + + "Data: " + str(payload) + "\n" + + "Headers: " + str( + get_target_object.controller_library_object.make_headers())) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + allure.attach(name=f"Response - {resp.status_code} {resp.reason}", body=str(resp.json())) + if resp.status_code != 200: + if resp.status_code == 400 and "Device is already executing a command. Please try later." in \ + resp.json()["ErrorDescription"]: + time.sleep(30) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + else: + assert False, f"push configuration to {serial_number} got failed" + get_target_object.dut_library_object.device_under_tests_data = testbed_info[dut_list[ap]][ + "device_under_tests"] + ap_iwinfo = get_target_object.dut_library_object.get_iwinfo(attach_allure=True) + if str(ap_iwinfo) != "Error: pop from empty list": + include_essid = config['interfaces'][0]["ssids"][0]["name"] + re_obj = re.compile( + rf'(wlan\d(?:-\d)?)\s+ESSID: "{re.escape(include_essid)}".*?\s+Access Point:\s+([0-9A-Fa-f:]+).*?Channel:\s+(' + r'\d+)\s+\(([\d.]+) GHz\)', + re.DOTALL + ) + # find all matches + interface_matches = re_obj.finditer(ap_iwinfo) + if interface_matches: + for match in interface_matches: + interface_name = match.group(1) + access_point = match.group(2) + channel = match.group(3) + frequency = match.group(4).replace('.', '') + ap_data.update( + {serial_number: {'Access Point': access_point, 'Channel': channel, 'frequency': frequency}}) + logging.info(f"AP Data from iwinfo: {ap_data}") + else: + logging.error("Failed to get iwinfo") + pytest.exit("Failed to get iwinfo") + elif ap_iwinfo == {}: + pytest.fail("Empty iwinfo reponse from AP through minicom") + else: + pytest.fail("Failed to get iwinfo from minicom") + for serial in ap_data: + bssid_list.append(ap_data[serial]['Access Point']) + if not ap_data[serial]['frequency'].endswith(","): + freqs_ = freqs_ + ap_data[serial]['frequency'] + "," + else: + freqs_ = freqs_ + ap_data[serial]['frequency'] + ssid = config['interfaces'][0]["ssids"][0]["name"] + key = config['interfaces'][0]["ssids"][0]["encryption"]["key"] + try: + pass_fail, message = get_test_library.roam_test(ap1_bssid=bssid_list[0], ap2_bssid=bssid_list[1], + scan_freq=freqs_, + band="both", num_sta=2, security="wpa2", security_key=key, + ssid=ssid, upstream="1.1.eth1", duration=None, + iteration=1, channel="36", option="ota", dut_name=dut_names, + traffic_type="lf_udp", sta_type="11r") + except Exception as e: + logging.error(f"Exception in roam test : {e}") + pass_fail, message = False, e + finally: + get_target_object.dut_library_object.get_dut_logs(print_log=False) + if not pass_fail: + pytest.fail(f"Test failed with the following reasons: \n{message}") + else: + assert True From a5762cec29577911f214eb360669db8a86898616 Mon Sep 17 00:00:00 2001 From: Anil Kumar Tegala Date: Thu, 27 Jun 2024 16:10:12 +0530 Subject: [PATCH 08/18] add roam ota twog and fiveg wpa2-eap test (#955) Signed-off-by: anil-tegala --- .../roam_test/hard_roam/OTA/test_roam_ota.py | 69 ++++++++++++------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py index 52280b8cc9..e0247d5082 100644 --- a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py +++ b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py @@ -1693,11 +1693,12 @@ def test_roam_5g_and_2g_wpa2psk(self, get_target_object, get_test_library, get_l @pytest.mark.roam @pytest.mark.fiveg @pytest.mark.twog - @pytest.mark.wpa2_personal - def test_roam_5g_and_2g_wpa2psk(self, get_target_object, get_test_library, get_lab_info, selected_testbed): + @pytest.mark.sae + @pytest.mark.wpa3_personal + def test_roam_5g_and_2g_wpa3psk(self, get_target_object, get_test_library, get_lab_info, selected_testbed): """ - Test Roaming between two APs, 2G & 5G, WPA2 Personal - pytest -m "roam and fiveg and twog and wpa2_personal and ota" + Test Roaming between two APs, 2G & 5G, WPA3 Personal + pytest -m "roam and fiveg and twog and wpa3_personal and ota" """ ap_data = dict() dut_list = [str(selected_testbed)] @@ -1716,6 +1717,8 @@ def test_roam_5g_and_2g_wpa2psk(self, get_target_object, get_test_library, get_l config['radios'] = [ {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] + # change ssid config data to sae + config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "sae" if len(dut_list) < 2: logging.error( f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") @@ -1724,9 +1727,9 @@ def test_roam_5g_and_2g_wpa2psk(self, get_target_object, get_test_library, get_l serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) if ap == 1: - config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] config['radios'] = [ {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 20, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] logging.info(config) payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} uri = get_target_object.controller_library_object.build_uri( @@ -1812,14 +1815,14 @@ def test_roam_5g_and_2g_wpa2psk(self, get_target_object, get_test_library, get_l assert True @pytest.mark.roam - @pytest.mark.fiveg @pytest.mark.twog - @pytest.mark.sae - @pytest.mark.wpa3_personal - def test_roam_5g_and_2g_wpa3psk(self, get_target_object, get_test_library, get_lab_info, selected_testbed): + @pytest.mark.fiveg + @pytest.mark.wpa2_enterprise + def test_roam_5g_and_2g_wpa2eap(self, get_target_object, get_test_library, get_lab_info, selected_testbed, + radius_info): """ - Test Roaming between two APs, 2G & 5G, WPA3 Personal - pytest -m "roam and fiveg and twog and wpa3_personal and ota" + Test Roaming between two APs, 2G & 5G, WPA2 Enterprise + pytest -m "roam and fiveg and twog and wpa2_enterprise and ota" """ ap_data = dict() dut_list = [str(selected_testbed)] @@ -1835,11 +1838,25 @@ def test_roam_5g_and_2g_wpa3psk(self, get_target_object, get_test_library, get_l temp_list.append(key) temp_list.sort() dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] + config['interfaces'][0]["ssids"][0]["radius"] = { + "accounting": { + "host": radius_info["ip"], + "port": radius_info["port"], + "secret": radius_info["secret"] + }, + "authentication": { + "host": radius_info["ip"], + "port": radius_info["port"], + "secret": radius_info["secret"] + } + } config['radios'] = [ - {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] - # change ssid config data to sae - config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "sae" + if "proto" in config['interfaces'][0]["ssids"][0]["encryption"]: + config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa2" + if "key" in config['interfaces'][0]["ssids"][0]["encryption"]: + config['interfaces'][0]["ssids"][0]["encryption"].pop("key") if len(dut_list) < 2: logging.error( f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") @@ -1903,11 +1920,9 @@ def test_roam_5g_and_2g_wpa3psk(self, get_target_object, get_test_library, get_l ap_data.update( {serial_number: {'Access Point': access_point, 'Channel': channel, 'frequency': frequency}}) logging.info(f"AP Data from iwinfo: {ap_data}") - else: - logging.error("Failed to get iwinfo") - pytest.exit("Failed to get iwinfo") - elif ap_iwinfo == {}: - pytest.fail("Empty iwinfo reponse from AP through minicom") + if ap_data == {}: + logging.error("Failed to get required iwinfo from minicom") + pytest.fail("Failed to get required iwinfo from minicom") else: pytest.fail("Failed to get iwinfo from minicom") for serial in ap_data: @@ -1917,14 +1932,20 @@ def test_roam_5g_and_2g_wpa3psk(self, get_target_object, get_test_library, get_l else: freqs_ = freqs_ + ap_data[serial]['frequency'] ssid = config['interfaces'][0]["ssids"][0]["name"] - key = config['interfaces'][0]["ssids"][0]["encryption"]["key"] + pass_fail, message = True, "Test Passed" try: pass_fail, message = get_test_library.roam_test(ap1_bssid=bssid_list[0], ap2_bssid=bssid_list[1], - scan_freq=freqs_, - band="both", num_sta=2, security="wpa2", security_key=key, - ssid=ssid, upstream="1.1.eth1", duration=None, + band="both", num_sta=1, security="wpa2", ssid=ssid, + upstream="1.1.eth1", eap_method="TLS", + pairwise_cipher="DEFAULT ", + groupwise_cipher="DEFAULT ", + eap_identity=radius_info["user"], + eap_password=radius_info["password"], + private_key="/home/lanforge/client.p12", + pk_passwd=radius_info["pk_password"], + ca_cert='/home/lanforge/ca.pem', sta_type="11r-eap", iteration=1, channel="36", option="ota", dut_name=dut_names, - traffic_type="lf_udp", sta_type="11r") + traffic_type="lf_udp") except Exception as e: logging.error(f"Exception in roam test : {e}") pass_fail, message = False, e From 57b8b09c99de56b8ed04670c32c2f96f0efd17d5 Mon Sep 17 00:00:00 2001 From: Carsten Schafer <49571202+carsten989@users.noreply.github.com> Date: Thu, 27 Jun 2024 08:35:26 -0400 Subject: [PATCH 09/18] WIFI-13871: CGW deployment (#956) * WIFI-13871 CGW deploy testing Signed-off-by: Carsten Schafer * WIFI-13871 CGW deploy testing Signed-off-by: Carsten Schafer --------- Signed-off-by: Carsten Schafer Co-authored-by: Carsten Schafer --- .github/workflows/cgw-dev-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cgw-dev-deployment.yaml b/.github/workflows/cgw-dev-deployment.yaml index 8a3c4efe42..e0d79d7345 100644 --- a/.github/workflows/cgw-dev-deployment.yaml +++ b/.github/workflows/cgw-dev-deployment.yaml @@ -20,6 +20,7 @@ env: testbeds: '[ { "namespace": "cgw01", + "chart_version": "next", "cgw_version": "main", "just_component": "false" } @@ -69,7 +70,6 @@ jobs: matrix: ${{ fromJson( needs.generate-matrix.outputs.matrix ) }} fail-fast: false steps: - - name: Checkout repo with Helm values uses: actions/checkout@v4 with: From bcf6a1e2f2adb508db45a9f6ea016e9a2c3f301a Mon Sep 17 00:00:00 2001 From: Carsten Schafer <49571202+carsten989@users.noreply.github.com> Date: Thu, 27 Jun 2024 08:53:53 -0400 Subject: [PATCH 10/18] Update cgw-dev-deployment.yaml --- .github/workflows/cgw-dev-deployment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cgw-dev-deployment.yaml b/.github/workflows/cgw-dev-deployment.yaml index e0d79d7345..d2851a4853 100644 --- a/.github/workflows/cgw-dev-deployment.yaml +++ b/.github/workflows/cgw-dev-deployment.yaml @@ -93,13 +93,13 @@ jobs: helm plugin install https://github.com/jkroepke/helm-secrets - name: Deploy OpenLAN Cloud Gateway and services - if: {{ github.event.inputs.just_component }} == "false" + if: ${{ github.event.inputs.just_component }} == "false" working-directory: wlan-cloud-ucentral-deploy/cgw run: | helmfile --environment ${{ matrix.namespace }} apply - name: Deploy OpenLAN Cloud Gateway only - if: {{ github.event.inputs.just_component }} == "true" + if: ${{ github.event.inputs.just_component }} == "true" working-directory: wlan-cloud-ucentral-deploy/cgw run: | helmfile --environment ${{ matrix.namespace }} -l app=cgw apply From f49bc511b3120e2aa25dbba117cc4677ba368bf9 Mon Sep 17 00:00:00 2001 From: Carsten Schafer Date: Thu, 27 Jun 2024 09:25:54 -0400 Subject: [PATCH 11/18] WIFI-13871 Correct branch for deploy repo Signed-off-by: Carsten Schafer --- .github/workflows/cgw-dev-deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cgw-dev-deployment.yaml b/.github/workflows/cgw-dev-deployment.yaml index d2851a4853..45df40ce65 100644 --- a/.github/workflows/cgw-dev-deployment.yaml +++ b/.github/workflows/cgw-dev-deployment.yaml @@ -20,7 +20,7 @@ env: testbeds: '[ { "namespace": "cgw01", - "chart_version": "next", + "chart_version": "main", "cgw_version": "main", "just_component": "false" } From f983a5c668c3255236deb77dca68e2e247ca0f63 Mon Sep 17 00:00:00 2001 From: Anil Kumar Tegala Date: Thu, 27 Jun 2024 18:56:58 +0530 Subject: [PATCH 12/18] add roam ota twog and fiveg wpa3 enterprise test (#958) Signed-off-by: anil-tegala --- .../roam_test/hard_roam/OTA/test_roam_ota.py | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py index e0247d5082..b5d60db9b4 100644 --- a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py +++ b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py @@ -1955,3 +1955,145 @@ def test_roam_5g_and_2g_wpa2eap(self, get_target_object, get_test_library, get_l pytest.fail(f"Test failed with the following reasons: \n{message}") else: assert True + + @pytest.mark.roam + @pytest.mark.twog + @pytest.mark.fiveg + @pytest.mark.wpa3_enterprise + def test_roam_5g_and_2g_wpa3eap(self, get_target_object, get_test_library, get_lab_info, selected_testbed, + radius_info): + """ + Test Roaming between two APs, 2G & 5G, WPA3 Enterprise + pytest -m "roam and fiveg and twog and wpa3_enterprise and ota" + """ + ap_data = dict() + dut_list = [str(selected_testbed)] + dut_names = list() + bssid_list = list() + freqs_ = "" + testbed_info = get_lab_info.CONFIGURATION + config = copy.deepcopy(config_data) + temp_list = list() + for key, val in testbed_info.items(): + tb_type, tb_name = selected_testbed.split("-") + if tb_type in key and tb_name[0] in key: + temp_list.append(key) + temp_list.sort() + dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] + config['interfaces'][0]["ssids"][0]["radius"] = { + "accounting": { + "host": radius_info["ip"], + "port": radius_info["port"], + "secret": radius_info["secret"] + }, + "authentication": { + "host": radius_info["ip"], + "port": radius_info["port"], + "secret": radius_info["secret"] + } + } + config['radios'] = [ + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] + if "proto" in config['interfaces'][0]["ssids"][0]["encryption"]: + config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa3" + if "key" in config['interfaces'][0]["ssids"][0]["encryption"]: + config['interfaces'][0]["ssids"][0]["encryption"].pop("key") + if len(dut_list) < 2: + logging.error( + f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") + assert False, f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}" + for ap in range(len(dut_list)): + serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] + dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) + if ap == 1: + config['radios'] = [ + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 20, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] + logging.info(config) + payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} + uri = get_target_object.controller_library_object.build_uri( + "device/" + serial_number + "/configure") + logging.info("Sending Command: " + "\n" + str(uri) + "\n" + + "TimeStamp: " + str(datetime.datetime.utcnow()) + "\n" + + "Data: " + str(json.dumps(payload, indent=2)) + "\n" + + "Headers: " + str(get_target_object.controller_library_object.make_headers())) + allure.attach(name=f"Push roam config on {serial_number}: ", body="Sending Command: " + str(uri) + "\n" + + "TimeStamp: " + str( + datetime.datetime.utcnow()) + "\n" + + "Data: " + str(payload) + "\n" + + "Headers: " + str( + get_target_object.controller_library_object.make_headers())) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + allure.attach(name=f"Response - {resp.status_code} {resp.reason}", body=str(resp.json())) + if resp.status_code != 200: + if resp.status_code == 400 and "Device is already executing a command. Please try later." in \ + resp.json()["ErrorDescription"]: + time.sleep(30) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + else: + assert False, f"push configuration to {serial_number} got failed" + get_target_object.dut_library_object.device_under_tests_data = testbed_info[dut_list[ap]][ + "device_under_tests"] + ap_iwinfo = get_target_object.dut_library_object.get_iwinfo(attach_allure=True) + if str(ap_iwinfo) != "Error: pop from empty list": + include_essid = config['interfaces'][0]["ssids"][0]["name"] + re_obj = re.compile( + rf'(wlan\d(?:-\d)?)\s+ESSID: "{re.escape(include_essid)}".*?\s+Access Point:\s+([0-9A-Fa-f:]+).*?Channel:\s+(' + r'\d+)\s+\(([\d.]+) GHz\)', + re.DOTALL + ) + # find all matches + interface_matches = re_obj.finditer(ap_iwinfo) + if interface_matches: + for match in interface_matches: + interface_name = match.group(1) + access_point = match.group(2) + channel = match.group(3) + frequency = match.group(4).replace('.', '') + ap_data.update( + {serial_number: {'Access Point': access_point, 'Channel': channel, 'frequency': frequency}}) + logging.info(f"AP Data from iwinfo: {ap_data}") + if ap_data == {}: + logging.error("Failed to get required iwinfo from minicom") + pytest.fail("Failed to get required iwinfo from minicom") + else: + pytest.fail("Failed to get iwinfo from minicom") + for serial in ap_data: + bssid_list.append(ap_data[serial]['Access Point']) + if not ap_data[serial]['frequency'].endswith(","): + freqs_ = freqs_ + ap_data[serial]['frequency'] + "," + else: + freqs_ = freqs_ + ap_data[serial]['frequency'] + ssid = config['interfaces'][0]["ssids"][0]["name"] + pass_fail, message = True, "Test Passed" + try: + pass_fail, message = get_test_library.roam_test(ap1_bssid=bssid_list[0], ap2_bssid=bssid_list[1], + band="both", num_sta=1, security="wpa2", ssid=ssid, + upstream="1.1.eth1", eap_method="TLS", + pairwise_cipher="DEFAULT ", + groupwise_cipher="DEFAULT ", + eap_identity=radius_info["user"], + eap_password=radius_info["password"], + private_key="/home/lanforge/client.p12", + pk_passwd=radius_info["pk_password"], + ca_cert='/home/lanforge/ca.pem', sta_type="11r-eap", + iteration=1, channel="36", option="ota", dut_name=dut_names, + traffic_type="lf_udp") + except Exception as e: + logging.error(f"Exception in roam test : {e}") + pass_fail, message = False, e + finally: + get_target_object.dut_library_object.get_dut_logs(print_log=False) + if not pass_fail: + pytest.fail(f"Test failed with the following reasons: \n{message}") + else: + assert True \ No newline at end of file From d129528c623d6978ee8b9fa77b5a22cc5f554902 Mon Sep 17 00:00:00 2001 From: Carsten Schafer Date: Thu, 27 Jun 2024 10:11:34 -0400 Subject: [PATCH 13/18] WIFI-13871 Need sops installed as well Signed-off-by: Carsten Schafer --- .github/workflows/cgw-dev-deployment.yaml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cgw-dev-deployment.yaml b/.github/workflows/cgw-dev-deployment.yaml index 45df40ce65..7f70324fd1 100644 --- a/.github/workflows/cgw-dev-deployment.yaml +++ b/.github/workflows/cgw-dev-deployment.yaml @@ -85,6 +85,9 @@ jobs: run: | curl -s -LO "https://dl.k8s.io/release/v1.27.14/bin/linux/amd64/kubectl" sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + # Download the binary + curl -s -LO "https://github.com/getsops/sops/releases/download/v3.8.1/sops-v3.8.1.linux.amd64" + sudo install -o root -g root -m 0755 sops-v3.8.1.linux.amd64 /usr/local/bin/sops curl -s -LO "https://github.com/helmfile/helmfile/releases/download/v0.165.0/helmfile_0.165.0_linux_amd64.tar.gz" tar xvzf helmfile_0.165.0_linux_amd64.tar.gz helmfile sudo install -o root -g root -m 0755 helmfile /usr/local/bin/helmfile @@ -96,7 +99,13 @@ jobs: if: ${{ github.event.inputs.just_component }} == "false" working-directory: wlan-cloud-ucentral-deploy/cgw run: | - helmfile --environment ${{ matrix.namespace }} apply + # service components can't be reinstalled easily + helm ls -n ${{ matrix.namespace }} + if ! helm ls -n ${{ matrix.namespace }} | grep "^kafka" >/dev/null ; then + helmfile --environment ${{ matrix.namespace }} apply + else + helmfile --environment ${{ matrix.namespace }} -l app=cgw apply + fi - name: Deploy OpenLAN Cloud Gateway only if: ${{ github.event.inputs.just_component }} == "true" From 845b261ad7349cbe9cabbe8d95bc8bc3145fbc8a Mon Sep 17 00:00:00 2001 From: Anil Kumar Tegala Date: Mon, 1 Jul 2024 16:24:33 +0530 Subject: [PATCH 14/18] add roam ota 5g and 6g wpa2psk test (#959) * add roam ota fiveg and sixg wpa2psk test Signed-off-by: anil-tegala * change security type to wpa3 Signed-off-by: anil-tegala --------- Signed-off-by: anil-tegala --- .../roam_test/hard_roam/OTA/test_roam_ota.py | 125 +++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py index b5d60db9b4..942b0e5ce3 100644 --- a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py +++ b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py @@ -2096,4 +2096,127 @@ def test_roam_5g_and_2g_wpa3eap(self, get_target_object, get_test_library, get_l if not pass_fail: pytest.fail(f"Test failed with the following reasons: \n{message}") else: - assert True \ No newline at end of file + assert True + + @pytest.mark.roam + @pytest.mark.fiveg + @pytest.mark.sixg + @pytest.mark.sae + @pytest.mark.wpa3_personal + def test_roam_5g_and_6g_wpa3psk(self, get_target_object, get_test_library, get_lab_info, selected_testbed): + """ + Test Roaming between two APs, 5G & 6G, WPA3 Personal + pytest -m "roam and fiveg and sixg and wpa3_personal and ota" + """ + ap_data = dict() + dut_list = [str(selected_testbed)] + dut_names = list() + bssid_list = list() + freqs_ = "" + testbed_info = get_lab_info.CONFIGURATION + config = copy.deepcopy(config_data) + temp_list = list() + for key, val in testbed_info.items(): + tb_type, tb_name = selected_testbed.split("-") + if tb_type in key and tb_name[0] in key: + temp_list.append(key) + temp_list.sort() + dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] + config['radios'] = [ + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] + # change ssid config data to sae + config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "sae" + if len(dut_list) < 2: + logging.error( + f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") + assert False, f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}" + for ap in range(len(dut_list)): + serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] + dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) + if ap == 1: + config['radios'] = [{"band": "6G", "channel": 161, "channel-mode": "HE", "channel-width": 80, "country": "US"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["6G"] + logging.info(config) + payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} + uri = get_target_object.controller_library_object.build_uri( + "device/" + serial_number + "/configure") + logging.info("Sending Command: " + "\n" + str(uri) + "\n" + + "TimeStamp: " + str(datetime.datetime.utcnow()) + "\n" + + "Data: " + str(json.dumps(payload, indent=2)) + "\n" + + "Headers: " + str(get_target_object.controller_library_object.make_headers())) + allure.attach(name=f"Push roam config on {serial_number}: ", body="Sending Command: " + str(uri) + "\n" + + "TimeStamp: " + str( + datetime.datetime.utcnow()) + "\n" + + "Data: " + str(payload) + "\n" + + "Headers: " + str( + get_target_object.controller_library_object.make_headers())) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + allure.attach(name=f"Response - {resp.status_code} {resp.reason}", body=str(resp.json())) + if resp.status_code != 200: + if resp.status_code == 400 and "Device is already executing a command. Please try later." in \ + resp.json()["ErrorDescription"]: + time.sleep(30) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + else: + assert False, f"push configuration to {serial_number} got failed" + get_target_object.dut_library_object.device_under_tests_data = testbed_info[dut_list[ap]][ + "device_under_tests"] + ap_iwinfo = get_target_object.dut_library_object.get_iwinfo(attach_allure=True) + if str(ap_iwinfo) != "Error: pop from empty list": + include_essid = config['interfaces'][0]["ssids"][0]["name"] + re_obj = re.compile( + rf'(wlan\d(?:-\d)?)\s+ESSID: "{re.escape(include_essid)}".*?\s+Access Point:\s+([0-9A-Fa-f:]+).*?Channel:\s+(' + r'\d+)\s+\(([\d.]+) GHz\)', + re.DOTALL + ) + # find all matches + interface_matches = re_obj.finditer(ap_iwinfo) + if interface_matches: + for match in interface_matches: + interface_name = match.group(1) + access_point = match.group(2) + channel = match.group(3) + frequency = match.group(4).replace('.', '') + ap_data.update( + {serial_number: {'Access Point': access_point, 'Channel': channel, 'frequency': frequency}}) + logging.info(f"AP Data from iwinfo: {ap_data}") + else: + logging.error("Failed to get iwinfo") + pytest.exit("Failed to get iwinfo") + elif ap_iwinfo == {}: + pytest.fail("Empty iwinfo reponse from AP through minicom") + else: + pytest.fail("Failed to get iwinfo from minicom") + for serial in ap_data: + bssid_list.append(ap_data[serial]['Access Point']) + if not ap_data[serial]['frequency'].endswith(","): + freqs_ = freqs_ + ap_data[serial]['frequency'] + "," + else: + freqs_ = freqs_ + ap_data[serial]['frequency'] + ssid = config['interfaces'][0]["ssids"][0]["name"] + key = config['interfaces'][0]["ssids"][0]["encryption"]["key"] + try: + pass_fail, message = get_test_library.roam_test(ap1_bssid=bssid_list[0], ap2_bssid=bssid_list[1], + scan_freq=freqs_, + band="both", num_sta=2, security="wpa3", security_key=key, + ssid=ssid, upstream="1.1.eth1", duration=None, + iteration=1, channel="36", option="ota", dut_name=dut_names, + traffic_type="lf_udp", sta_type="11r") + except Exception as e: + logging.error(f"Exception in roam test : {e}") + pass_fail, message = False, e + finally: + get_target_object.dut_library_object.get_dut_logs(print_log=False) + if not pass_fail: + pytest.fail(f"Test failed with the following reasons: \n{message}") + else: + assert True From b8703913df8bb6e757423c2c7f0238107adeb2b2 Mon Sep 17 00:00:00 2001 From: Jitendrakumar Kushavah <78074038+jitendracandela@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:11:39 +0530 Subject: [PATCH 15/18] Wifi 13853 (#960) * Removed >/dev/null 2>&1 for logs purpose Signed-off-by: jitendracandela * Added Verbosity for logs Signed-off-by: jitendracandela * Added retries=3 in the kubectl cp command Signed-off-by: jitendracandela * Added list of files in the pod /tmp/allure-results Signed-off-by: jitendracandela --------- Signed-off-by: jitendracandela --- .github/actions/run-tests/action.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml index de8bb935b9..0e6cf5b4a8 100644 --- a/.github/actions/run-tests/action.yml +++ b/.github/actions/run-tests/action.yml @@ -130,7 +130,9 @@ runs: done echo "tests completed" echo "downloading allure results..." - kubectl cp $podname:/tmp/allure-results allure-results >/dev/null 2>&1 + echo "list files in the pod /tmp/allure-results directory" + kubectl exec $podname -- ls -la /tmp/allure-results + kubectl cp --v=10 --retries=3 $podname:/tmp/allure-results allure-results echo "waiting for pod to exit" kubectl logs -f $podname >/dev/null 2>&1 From f1d88e5c218def63c3a289a42cfb15a9324a59d4 Mon Sep 17 00:00:00 2001 From: Jitendrakumar Kushavah <78074038+jitendracandela@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:12:47 +0530 Subject: [PATCH 16/18] Wifi 13859 (#961) * Added hfcl_ion4xi in the sanity, performance, regression workflows and overview page Signed-off-by: jitendracandela * Removed hfcl_ion4xi from overview page Signed-off-by: jitendracandela --------- Signed-off-by: jitendracandela --- .github/workflows/performance.yml | 187 ++++++++++++++++- .github/workflows/quali.yml | 95 ++++++++- .github/workflows/regression.yml | 328 +++++++++++++++++++++++++++++- 3 files changed, 599 insertions(+), 11 deletions(-) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 1c78661c16..a66073f2e9 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -22,7 +22,7 @@ on: description: "revision of the Open Wifi Helm chart" ap_models: required: true - default: "cig_wf188n,cig_wf196,hfcl_ion4xe,yuncore_fap655,yuncore_ax820,edgecore_oap101-6e,edgecore_eap102,edgecore_eap101,edgecore_eap104,cig_wf186w,edgecore_eap111" + default: "cig_wf188n,cig_wf196,hfcl_ion4xe,yuncore_fap655,yuncore_ax820,edgecore_oap101-6e,edgecore_eap102,edgecore_eap101,edgecore_eap104,cig_wf186w,edgecore_eap111,hfcl_ion4xi" description: "the AP models to test" ap_version: required: true @@ -302,7 +302,7 @@ jobs: test-hfcl-ion4xe: - needs: ["vars", "build"] + needs: ["vars", "build", "test-edgecore-eap101"] runs-on: [ self-hosted, small ] timeout-minutes: 1440 if: "!cancelled() && contains(fromJSON(needs.vars.outputs.ap_models), 'hfcl_ion4xe')" @@ -478,8 +478,185 @@ jobs: run: kubectl -n openwifi-${{ needs.vars.outputs.existing_controller }} logs deployment/owsec + test-hfcl-ion4xi: + needs: [ "vars", "build", "test-hfcl-ion4xe"] + runs-on: [ self-hosted, small ] + timeout-minutes: 1440 + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.ap_models), 'hfcl_ion4xi')" + env: + AP_MODEL: hfcl_ion4xi + steps: + - name: Set AP model output + id: ap_model + run: | + echo "model=${AP_MODEL}" >> $GITHUB_OUTPUT + + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.8" + + + # TODO WIFI-7839 delete when issue is resolved on AWS CLI side + - name: install kubectl + run: | + curl -s -LO "https://dl.k8s.io/release/v1.27.6/bin/linux/amd64/kubectl" + sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + + - name: install aws CLI tool + run: | + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + unzip awscliv2.zip + sudo ./aws/install + + - name: get EKS access credentials + run: aws eks update-kubeconfig --name ${{ env.AWS_EKS_NAME }} + + - name: prepare namespace name + id: namespace + run: | + NAMESPACE="performance-${{ github.run_id }}-$(echo ${{ steps.ap_model.outputs.model }} | tr '[:upper:]' '[:lower:]' | tr '_' '-')" + echo "name=${NAMESPACE}" >> $GITHUB_OUTPUT + + - name: prepare configuration + run: | + cat << EOF > lab_info.json + ${{ secrets.LAB_INFO_JSON }} + EOF + + + - name: run tests dataplane_tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'dataplane_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-dtt + testbed: basic-3b + marker_expression: "performance and dataplane_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + additional_args: '-o firmware="${{ needs.vars.outputs.ap_version }}"' + allure_results_artifact_name: "allure-results-${{ steps.ap_model.outputs.model }}-dataplane_tests" + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-dtt --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-dtt $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-dtt + + - name: run tests peak_throughput_tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'peak_throughput_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-ssdbt + testbed: basic-3b + marker_expression: "performance and peak_throughput_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + additional_args: '-o firmware="${{ needs.vars.outputs.ap_version }}"' + allure_results_artifact_name: "allure-results-${{ steps.ap_model.outputs.model }}-peak_throughput_tests" + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-ssdbt --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-ssdbt $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-ssdbt + + - name: run tests client_scale_tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'client_scale_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-wct + testbed: basic-3b + marker_expression: "performance and client_scale_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + additional_args: '-o firmware="${{ needs.vars.outputs.ap_version }}"' + allure_results_artifact_name: "allure-results-${{ steps.ap_model.outputs.model }}-client_scale_tests" + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-wct --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-wct $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-wct + + - name: run tests dual_band_tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'dual_band_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-wct + testbed: basic-3b + marker_expression: "performance and dual_band_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + additional_args: '-o firmware="${{ needs.vars.outputs.ap_version }}"' + allure_results_artifact_name: "allure-results-${{ steps.ap_model.outputs.model }}-dual_band_tests" + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-wct --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-wct $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-wct + + - name: show gw logs + if: failure() + run: kubectl -n openwifi-${{ needs.vars.outputs.existing_controller }} logs deployment/owgw + + - name: show fms logs + if: failure() + run: kubectl -n openwifi-${{ needs.vars.outputs.existing_controller }} logs deployment/owfms + + - name: show prov logs + if: failure() + run: kubectl -n openwifi-${{ needs.vars.outputs.existing_controller }} logs deployment/owprov + + - name: show analytics logs + if: failure() + run: kubectl -n openwifi-${{ needs.vars.outputs.existing_controller }} logs deployment/owanalytics + + - name: show subscription (userportal) logs + if: failure() + run: kubectl -n openwifi-${{ needs.vars.outputs.existing_controller }} logs deployment/owsub + + - name: show sec logs + if: failure() + run: kubectl -n openwifi-${{ needs.vars.outputs.existing_controller }} logs deployment/owsec + + test-edgecore-eap101: - needs: ["vars", "build", "test-hfcl-ion4xe"] + needs: ["vars", "build"] runs-on: [ self-hosted, small ] timeout-minutes: 1440 if: "!cancelled() && contains(fromJSON(needs.vars.outputs.ap_models), 'edgecore_eap101')" @@ -2078,7 +2255,7 @@ jobs: report: if: "!cancelled()" runs-on: ubuntu-latest - needs: [vars, test-cig-wf188n, test-edgecore-oap101-6e, test-cig-wf196, test-edgecore-eap102, test-hfcl-ion4xe, test-edgecore-eap101, test-yuncore-fap655, test-edgecore-eap104, test-yuncore-ax820, test-cig-wf186w, test-edgecore-eap111] + needs: [vars, test-cig-wf188n, test-edgecore-oap101-6e, test-cig-wf196, test-edgecore-eap102, test-hfcl-ion4xe, test-edgecore-eap101, test-yuncore-fap655, test-edgecore-eap104, test-yuncore-ax820, test-cig-wf186w, test-edgecore-eap111, test-hfcl-ion4xi] strategy: fail-fast: false matrix: @@ -2153,7 +2330,7 @@ jobs: # Cleanup cleanup: - needs: [test-cig-wf188n, test-edgecore-oap101-6e, test-cig-wf196, test-edgecore-eap102, test-hfcl-ion4xe, test-edgecore-eap101, test-yuncore-fap655, test-edgecore-eap104, test-yuncore-ax820, test-cig-wf186w, test-edgecore-eap111] + needs: [test-cig-wf188n, test-edgecore-oap101-6e, test-cig-wf196, test-edgecore-eap102, test-hfcl-ion4xe, test-edgecore-eap101, test-yuncore-fap655, test-edgecore-eap104, test-yuncore-ax820, test-cig-wf186w, test-edgecore-eap111, test-hfcl-ion4xi] runs-on: ubuntu-latest if: always() steps: diff --git a/.github/workflows/quali.yml b/.github/workflows/quali.yml index 23c9cfff9f..ec54d8745b 100644 --- a/.github/workflows/quali.yml +++ b/.github/workflows/quali.yml @@ -22,7 +22,7 @@ on: description: "revision of the Open Wifi Helm chart" ap_models: required: true - default: "cig_wf188n,cig_wf196,hfcl_ion4xe,yuncore_fap655,yuncore_ax820,edgecore_oap101-6e,edgecore_eap102,edgecore_eap101,edgecore_eap104,cig_wf186w,edgecore_eap111" + default: "cig_wf188n,cig_wf196,hfcl_ion4xe,yuncore_fap655,yuncore_ax820,edgecore_oap101-6e,edgecore_eap102,edgecore_eap101,edgecore_eap104,cig_wf186w,edgecore_eap111,hfcl_ion4xi" description: "the AP models to test" ap_version: required: true @@ -752,6 +752,95 @@ jobs: if: failure() run: kubectl -n openwifi-qa01 logs deployment/owsec + test-hfcl-ion4xi: + needs: [ "vars", "build" ] + runs-on: ubuntu-latest + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.ap_models), 'hfcl_ion4xi')" + env: + AP_MODEL: hfcl_ion4xi + steps: + - name: Set AP model output + id: ap_model + run: | + echo "model=${AP_MODEL}" >> $GITHUB_OUTPUT + + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.8" + + # TODO WIFI-7839 delete when issue is resolved on AWS CLI side + - name: install kubectl + run: | + curl -s -LO "https://dl.k8s.io/release/v1.27.6/bin/linux/amd64/kubectl" + sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + + - name: get EKS access credentials + run: aws eks update-kubeconfig --name ${{ env.AWS_EKS_NAME }} + + - name: prepare namespace name + id: namespace + run: | + NAMESPACE="testing-${{ github.run_id }}-$(echo ${{ steps.ap_model.outputs.model }} | tr '[:upper:]' '[:lower:]' | tr '_' '-')" + echo "name=${NAMESPACE}" >> $GITHUB_OUTPUT + + - name: prepare configuration + run: | + cat << EOF > lab_info.json + ${{ secrets.LAB_INFO_JSON }} + EOF + + + - name: run tests + uses: ./.github/actions/run-tests + with: + namespace: ${{ steps.namespace.outputs.name }} + testbed: basic-3b + marker_expression: "${{ needs.vars.outputs.marker_expression }}" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + additional_args: '-o firmware="${{ needs.vars.outputs.ap_version }}"' + allure_results_artifact_name: "allure-results-${{ steps.ap_model.outputs.model }}" + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }} --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }} $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }} + + - name: show gw logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owgw + + - name: show fms logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owfms + + - name: show prov logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owprov + + - name: show analytics logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owanalytics + + - name: show subscription (userportal) logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owsub + + - name: show sec logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owsec + test-edgecore-eap101: needs: ["vars", "build"] @@ -1116,7 +1205,7 @@ jobs: report: if: "!cancelled()" runs-on: ubuntu-latest - needs: [vars, test-cig-wf188n, test-cig-wf196, test-yuncore-fap655, test-yuncore-ax820, test-edgecore-eap104, test-edgecore-oap101-6e, test-hfcl-ion4xe, test-edgecore-eap101, test-edgecore-eap102, test-cig-wf186w, test-edgecore-eap111] + needs: [vars, test-cig-wf188n, test-cig-wf196, test-yuncore-fap655, test-yuncore-ax820, test-edgecore-eap104, test-edgecore-oap101-6e, test-hfcl-ion4xe, test-edgecore-eap101, test-edgecore-eap102, test-cig-wf186w, test-edgecore-eap111, test-hfcl-ion4xi] strategy: fail-fast: false matrix: @@ -1167,7 +1256,7 @@ jobs: # Cleanup cleanup: - needs: [test-cig-wf188n, test-cig-wf196, test-yuncore-fap655, test-yuncore-ax820, test-edgecore-eap104, test-edgecore-oap101-6e, test-hfcl-ion4xe, test-edgecore-eap101, test-edgecore-eap102, test-cig-wf186w, test-edgecore-eap111] + needs: [test-cig-wf188n, test-cig-wf196, test-yuncore-fap655, test-yuncore-ax820, test-edgecore-eap104, test-edgecore-oap101-6e, test-hfcl-ion4xe, test-edgecore-eap101, test-edgecore-eap102, test-cig-wf186w, test-edgecore-eap111, test-hfcl-ion4xi] runs-on: ubuntu-latest if: always() steps: diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index be1048e738..ba66fe6101 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -22,7 +22,7 @@ on: description: "revision of the Open Wifi Helm chart" ap_models: required: true - default: "cig_wf188n,cig_wf196,hfcl_ion4xe,yuncore_fap655,yuncore_ax820,edgecore_oap101-6e,edgecore_eap102,edgecore_eap101,edgecore_eap104,cig_wf186w,edgecore_eap111" + default: "cig_wf188n,cig_wf196,hfcl_ion4xe,yuncore_fap655,yuncore_ax820,edgecore_oap101-6e,edgecore_eap102,edgecore_eap101,edgecore_eap104,cig_wf186w,edgecore_eap111,hfcl_ion4xi" description: "the AP models to test" ap_version: required: true @@ -447,6 +447,328 @@ jobs: if: failure() run: kubectl -n openwifi-qa01 logs deployment/owsec + test-hfcl-ion4xi: + needs: [ "vars", "build", "test-hfcl-ion4xe" ] + runs-on: [ self-hosted, small ] + timeout-minutes: 1440 + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.ap_models), 'hfcl_ion4xi')" + env: + AP_MODEL: hfcl_ion4xi + steps: + - name: Set AP model output + id: ap_model + run: | + echo "model=${AP_MODEL}" >> $GITHUB_OUTPUT + + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.8" + + + # TODO WIFI-7839 delete when issue is resolved on AWS CLI side + - name: install kubectl + run: | + curl -s -LO "https://dl.k8s.io/release/v1.27.6/bin/linux/amd64/kubectl" + sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + + - name: install aws CLI tool + run: | + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + unzip awscliv2.zip + sudo ./aws/install + + - name: get EKS access credentials + run: aws eks update-kubeconfig --name ${{ env.AWS_EKS_NAME }} + + - name: prepare namespace name + id: namespace + run: | + NAMESPACE="regression-${{ github.run_id }}-$(echo ${{ steps.ap_model.outputs.model }} | tr '[:upper:]' '[:lower:]' | tr '_' '-')" + echo "name=${NAMESPACE}" >> $GITHUB_OUTPUT + + - name: prepare configuration + run: | + cat << EOF > lab_info.json + ${{ secrets.LAB_INFO_JSON }} + EOF + + + - name: run dfs tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'dfs_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-dfs + testbed: basic-3b + marker_expression: "ow_regression_lf and dfs_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-dfs_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-dfs --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-dfs $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-dfs + + - name: run multipsk tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'multi_psk_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-multipsk + testbed: basic-3b + marker_expression: "ow_regression_lf and multi_psk_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-multi_psk_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-multipsk --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-multipsk $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-multipsk + + - name: run rate_limiting tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'rate_limiting_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-rate-limiting + testbed: basic-3b + marker_expression: "ow_regression_lf and rate_limiting_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-rate_limiting_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-rate-limiting --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-rate-limiting $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-rate-limiting + + - name: run rate_limiting_with_radius tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'rate_limiting_with_radius_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-rate-limiting-radius + testbed: basic-3b + marker_expression: "ow_regression_lf and rate_limiting_with_radius_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-rate_limiting_with_radius_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-rate-limiting-radius --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-rate-limiting-radius $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-rate-limiting-radius + + - name: run dynamic_vlan tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'dynamic_vlan_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-dynamic-vlan + testbed: basic-3b + marker_expression: "ow_regression_lf and dynamic_vlan_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-dynamic_vlan_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-dynamic-vlan --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-dynamic-vlan $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-dynamic-vlan + + - name: run multi_vlan tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'multi_vlan_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-multi-vlan + testbed: basic-3b + marker_expression: "ow_regression_lf and multi_vlan_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-multi_vlan_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-multi-vlan --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-multi-vlan $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-multi-vlan + + - name: run strict forwarding tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'strict_forwarding_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-strict-forwarding + testbed: basic-3b + marker_expression: "ow_regression_lf and strict_forwarding_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-strict_forwarding_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-strict-forwarding --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-strict-forwarding $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-strict-forwarding + + - name: run captive portal tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'advanced_captive_portal_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-captive-portal + testbed: basic-3b + marker_expression: "ow_regression_lf and advanced_captive_portal_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-advanced_captive_portal_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-captive-portal --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-captive-portal $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-captive-portal + + - name: run firmware upgrade & downgrade tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'firmware_upgrade_downgrade')" + with: + namespace: ${{ steps.namespace.outputs.name }}-fw-upgrade-downgrade + testbed: basic-3b + marker_expression: "ow_regression_lf and firmware_upgrade_downgrade" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-firmware_upgrade_downgrade + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-firmware-upgrade-downgrade --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-firmware-upgrade-downgrade $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-firmware-upgrade-downgrade + + - name: run ap support bundle tests + uses: ./.github/actions/run-tests + if: "!cancelled() && contains(fromJSON(needs.vars.outputs.marker_expressions), 'asb_tests')" + with: + namespace: ${{ steps.namespace.outputs.name }}-asb + testbed: basic-3b + marker_expression: "ow_regression_lf and asb_tests" + configuration_file: "./lab_info.json" + testing_docker_image: tip-tip-wlan-cloud-docker-repo.jfrog.io/cloud-sdk-nightly:${{ github.run_id }} + allure_results_artifact_name: allure-results-${{ steps.ap_model.outputs.model }}-asb_tests + dns_records_to_resolve: "sec-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build gw-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build fms-${{ needs.vars.outputs.existing_controller }}.cicd.lab.wlan.tip.build" + + # necessary because if conditionals in composite actions are currently not respected + - name: get tests logs + if: always() + continue-on-error: true + run: | + podname=$(kubectl get pods -n ${{ steps.namespace.outputs.name }}-asb-tests --no-headers -o custom-columns=":metadata.name" -l job-name=testing | sed "s/pod\///") + kubectl logs --timestamps -n ${{ steps.namespace.outputs.name }}-asb-tests $podname || true + + - name: delete namespace + if: always() + continue-on-error: true + run: kubectl delete ns --ignore-not-found=true --wait ${{ steps.namespace.outputs.name }}-asb-tests + + - name: show gw logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owgw + + - name: show fms logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owfms + + - name: show prov logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owprov + + - name: show analytics logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owanalytics + + - name: show subscription (userportal) logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owsub + + - name: show sec logs + if: failure() + run: kubectl -n openwifi-qa01 logs deployment/owsec + test-edgecore-eap101: needs: ["vars", "build"] @@ -3677,7 +3999,7 @@ jobs: report: if: "!cancelled()" runs-on: ubuntu-latest - needs: [vars, test-hfcl-ion4xe, test-edgecore-eap101, test-yuncore-fap655, test-cig-wf188n, test-edgecore-eap102, test-edgecore-eap104, test-edgecore-oap101-6e, test-yuncore-ax820, test-cig-wf186w, test-cig-wf196, test-edgecore-eap111] + needs: [vars, test-hfcl-ion4xe, test-edgecore-eap101, test-yuncore-fap655, test-cig-wf188n, test-edgecore-eap102, test-edgecore-eap104, test-edgecore-oap101-6e, test-yuncore-ax820, test-cig-wf186w, test-cig-wf196, test-edgecore-eap111, test-hfcl-ion4xi] strategy: fail-fast: false matrix: @@ -3730,7 +4052,7 @@ jobs: # Cleanup cleanup: - needs: [test-hfcl-ion4xe, test-edgecore-eap101, test-yuncore-fap655, test-cig-wf188n, test-edgecore-eap102, test-edgecore-eap104, test-edgecore-oap101-6e, test-yuncore-ax820, test-cig-wf186w, test-cig-wf196, test-edgecore-eap111] + needs: [test-hfcl-ion4xe, test-edgecore-eap101, test-yuncore-fap655, test-cig-wf188n, test-edgecore-eap102, test-edgecore-eap104, test-edgecore-oap101-6e, test-yuncore-ax820, test-cig-wf186w, test-cig-wf196, test-edgecore-eap111, test-hfcl-ion4xi] runs-on: ubuntu-latest if: always() steps: From 5c913ea2911f4bc4ee9c541e0936963f020b2aec Mon Sep 17 00:00:00 2001 From: Anil Kumar Tegala Date: Wed, 3 Jul 2024 11:41:29 +0530 Subject: [PATCH 17/18] add roam ota fiveg and sixg wpa3 enterprise test (#963) Signed-off-by: anil-tegala --- .../roam_test/hard_roam/OTA/test_roam_ota.py | 179 ++++++++++++++++-- 1 file changed, 162 insertions(+), 17 deletions(-) diff --git a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py index 942b0e5ce3..6d2af27585 100644 --- a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py +++ b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py @@ -169,7 +169,7 @@ def test_roam_2g_to_2g_dc_psk_wpa2(self, get_target_object, get_test_library, ge temp_list.sort() dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] config['radios'] = [ - {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 40, "country": "CA"}] + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 40, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] if len(dut_list) < 2: logging.error( @@ -289,7 +289,7 @@ def test_roam_5g_to_5g_sc_psk_wpa2(self, get_target_object, get_test_library, ge temp_list.sort() dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] config['radios'] = [ - {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] if len(dut_list) < 2: logging.error( @@ -407,7 +407,7 @@ def test_roam_5g_to_5g_dc_psk_wpa2(self, get_target_object, get_test_library, ge temp_list.sort() dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] config['radios'] = [ - {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] if len(dut_list) < 2: logging.error( @@ -528,7 +528,7 @@ def test_roam_2g_to_2g_sc_psk_wpa3(self, get_target_object, get_test_library, ge temp_list.sort() dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] config['radios'] = [ - {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 40, "country": "CA"}] + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 40, "country": "CA"}] # change ssid config data to sae config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "sae" config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] @@ -649,7 +649,7 @@ def test_roam_5g_to_5g_sc_psk_wpa3(self, get_target_object, get_test_library, ge temp_list.sort() dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] config['radios'] = [ - {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] # change ssid security type to sae config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "sae" config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] @@ -859,7 +859,8 @@ def test_roam_6g_to_6g_sc_psk_wpa3(self, get_target_object, get_test_library, ge scan_freq=freqs_, band="sixg", num_sta=1, security="wpa3", security_key=key, ssid=ssid, upstream="1.1.eth1", duration=None, - iteration=1, channel="161", option="ota", dut_name=dut_names, + iteration=1, channel="161", option="ota", + dut_name=dut_names, traffic_type="lf_udp", sta_type="11r-sae") except Exception as e: logging.error(f"Exception in roam test : {e}") @@ -908,7 +909,7 @@ def test_roam_2g_to_2g_sc_eap_wpa2(self, get_target_object, get_test_library, ge } } config['radios'] = [ - {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 40, "country": "CA"}] + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 40, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] if "proto" in config['interfaces'][0]["ssids"][0]["encryption"]: config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa2" @@ -1046,7 +1047,7 @@ def test_roam_5g_to_5g_sc_eap_wpa2(self, get_target_object, get_test_library, ge } } config['radios'] = [ - {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] if "proto" in config['interfaces'][0]["ssids"][0]["encryption"]: config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa2" @@ -1184,7 +1185,7 @@ def test_roam_2g_to_2g_sc_eap_wpa3(self, get_target_object, get_test_library, ge } } config['radios'] = [ - {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 40, "country": "CA"}] + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 40, "country": "CA"}] # change ssid security type to sae config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa3" config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] @@ -1322,7 +1323,7 @@ def test_roam_5g_to_5g_sc_eap_wpa3(self, get_target_object, get_test_library, ge } } config['radios'] = [ - {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] # change ssid security type to sae config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa3" config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] @@ -1557,7 +1558,8 @@ def test_roam_6g_to_6g_sc_eap_wpa3(self, get_target_object, get_test_library, ge private_key="/home/lanforge/client.p12", pk_passwd=radius_info["pk_password"], ca_cert='/home/lanforge/ca.pem', sta_type="11r-eap-sha384", - iteration=1, channel="161", option="ota", dut_name=dut_names, + iteration=1, channel="161", option="ota", + dut_name=dut_names, traffic_type="lf_udp") except Exception as e: logging.error(f"Exception in roam test : {e}") @@ -1819,7 +1821,7 @@ def test_roam_5g_and_2g_wpa3psk(self, get_target_object, get_test_library, get_l @pytest.mark.fiveg @pytest.mark.wpa2_enterprise def test_roam_5g_and_2g_wpa2eap(self, get_target_object, get_test_library, get_lab_info, selected_testbed, - radius_info): + radius_info): """ Test Roaming between two APs, 2G & 5G, WPA2 Enterprise pytest -m "roam and fiveg and twog and wpa2_enterprise and ota" @@ -1851,7 +1853,7 @@ def test_roam_5g_and_2g_wpa2eap(self, get_target_object, get_test_library, get_l } } config['radios'] = [ - {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] if "proto" in config['interfaces'][0]["ssids"][0]["encryption"]: config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa2" @@ -1955,13 +1957,13 @@ def test_roam_5g_and_2g_wpa2eap(self, get_target_object, get_test_library, get_l pytest.fail(f"Test failed with the following reasons: \n{message}") else: assert True - + @pytest.mark.roam @pytest.mark.twog @pytest.mark.fiveg @pytest.mark.wpa3_enterprise def test_roam_5g_and_2g_wpa3eap(self, get_target_object, get_test_library, get_lab_info, selected_testbed, - radius_info): + radius_info): """ Test Roaming between two APs, 2G & 5G, WPA3 Enterprise pytest -m "roam and fiveg and twog and wpa3_enterprise and ota" @@ -1993,7 +1995,7 @@ def test_roam_5g_and_2g_wpa3eap(self, get_target_object, get_test_library, get_l } } config['radios'] = [ - {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] if "proto" in config['interfaces'][0]["ssids"][0]["encryption"]: config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa3" @@ -2135,7 +2137,8 @@ def test_roam_5g_and_6g_wpa3psk(self, get_target_object, get_test_library, get_l serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) if ap == 1: - config['radios'] = [{"band": "6G", "channel": 161, "channel-mode": "HE", "channel-width": 80, "country": "US"}] + config['radios'] = [ + {"band": "6G", "channel": 161, "channel-mode": "HE", "channel-width": 80, "country": "US"}] config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["6G"] logging.info(config) payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} @@ -2220,3 +2223,145 @@ def test_roam_5g_and_6g_wpa3psk(self, get_target_object, get_test_library, get_l pytest.fail(f"Test failed with the following reasons: \n{message}") else: assert True + + @pytest.mark.roam + @pytest.mark.sixg + @pytest.mark.fiveg + @pytest.mark.wpa3_enterprise + def test_roam_5g_and_6g_wpa3eap(self, get_target_object, get_test_library, get_lab_info, selected_testbed, + radius_info): + """ + Test Roaming between two APs, 5G & 6G, WPA3 Enterprise + pytest -m "roam and fiveg and sixg and wpa3_enterprise and ota" + """ + ap_data = dict() + dut_list = [str(selected_testbed)] + dut_names = list() + bssid_list = list() + freqs_ = "" + testbed_info = get_lab_info.CONFIGURATION + config = copy.deepcopy(config_data) + temp_list = list() + for key, val in testbed_info.items(): + tb_type, tb_name = selected_testbed.split("-") + if tb_type in key and tb_name[0] in key: + temp_list.append(key) + temp_list.sort() + dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] + config['interfaces'][0]["ssids"][0]["radius"] = { + "accounting": { + "host": radius_info["ip"], + "port": radius_info["port"], + "secret": radius_info["secret"] + }, + "authentication": { + "host": radius_info["ip"], + "port": radius_info["port"], + "secret": radius_info["secret"] + } + } + config['radios'] = [ + {"band": "5G", "channel": 36, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["5G"] + if "proto" in config['interfaces'][0]["ssids"][0]["encryption"]: + config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "wpa3" + if "key" in config['interfaces'][0]["ssids"][0]["encryption"]: + config['interfaces'][0]["ssids"][0]["encryption"].pop("key") + if len(dut_list) < 2: + logging.error( + f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") + assert False, f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}" + for ap in range(len(dut_list)): + serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] + dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) + if ap == 1: + config['radios'] = [ + {"band": "6G", "channel": 161, "channel-mode": "HE", "channel-width": 80, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["6G"] + logging.info(config) + payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} + uri = get_target_object.controller_library_object.build_uri( + "device/" + serial_number + "/configure") + logging.info("Sending Command: " + "\n" + str(uri) + "\n" + + "TimeStamp: " + str(datetime.datetime.utcnow()) + "\n" + + "Data: " + str(json.dumps(payload, indent=2)) + "\n" + + "Headers: " + str(get_target_object.controller_library_object.make_headers())) + allure.attach(name=f"Push roam config on {serial_number}: ", body="Sending Command: " + str(uri) + "\n" + + "TimeStamp: " + str( + datetime.datetime.utcnow()) + "\n" + + "Data: " + str(payload) + "\n" + + "Headers: " + str( + get_target_object.controller_library_object.make_headers())) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + allure.attach(name=f"Response - {resp.status_code} {resp.reason}", body=str(resp.json())) + if resp.status_code != 200: + if resp.status_code == 400 and "Device is already executing a command. Please try later." in \ + resp.json()["ErrorDescription"]: + time.sleep(30) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + else: + assert False, f"push configuration to {serial_number} got failed" + get_target_object.dut_library_object.device_under_tests_data = testbed_info[dut_list[ap]][ + "device_under_tests"] + ap_iwinfo = get_target_object.dut_library_object.get_iwinfo(attach_allure=True) + if str(ap_iwinfo) != "Error: pop from empty list": + include_essid = config['interfaces'][0]["ssids"][0]["name"] + re_obj = re.compile( + rf'(wlan\d(?:-\d)?)\s+ESSID: "{re.escape(include_essid)}".*?\s+Access Point:\s+([0-9A-Fa-f:]+).*?Channel:\s+(' + r'\d+)\s+\(([\d.]+) GHz\)', + re.DOTALL + ) + # find all matches + interface_matches = re_obj.finditer(ap_iwinfo) + if interface_matches: + for match in interface_matches: + interface_name = match.group(1) + access_point = match.group(2) + channel = match.group(3) + frequency = match.group(4).replace('.', '') + ap_data.update( + {serial_number: {'Access Point': access_point, 'Channel': channel, 'frequency': frequency}}) + logging.info(f"AP Data from iwinfo: {ap_data}") + if ap_data == {}: + logging.error("Failed to get required iwinfo from minicom") + pytest.fail("Failed to get required iwinfo from minicom") + else: + pytest.fail("Failed to get iwinfo from minicom") + for serial in ap_data: + bssid_list.append(ap_data[serial]['Access Point']) + if not ap_data[serial]['frequency'].endswith(","): + freqs_ = freqs_ + ap_data[serial]['frequency'] + "," + else: + freqs_ = freqs_ + ap_data[serial]['frequency'] + ssid = config['interfaces'][0]["ssids"][0]["name"] + pass_fail, message = True, "Test Passed" + try: + pass_fail, message = get_test_library.roam_test(ap1_bssid=bssid_list[0], ap2_bssid=bssid_list[1], + band="both", num_sta=1, security="wpa3", ssid=ssid, + upstream="1.1.eth1", eap_method="TLS", + pairwise_cipher="DEFAULT ", + groupwise_cipher="DEFAULT ", + eap_identity=radius_info["user"], + eap_password=radius_info["password"], + private_key="/home/lanforge/client.p12", + pk_passwd=radius_info["pk_password"], + ca_cert='/home/lanforge/ca.pem', sta_type="11r-eap", + iteration=1, channel="36", option="ota", dut_name=dut_names, + traffic_type="lf_udp") + except Exception as e: + logging.error(f"Exception in roam test : {e}") + pass_fail, message = False, e + finally: + get_target_object.dut_library_object.get_dut_logs(print_log=False) + if not pass_fail: + pytest.fail(f"Test failed with the following reasons: \n{message}") + else: + assert True From 4f905f70320f0302d39161f63079aebd1f0f11b8 Mon Sep 17 00:00:00 2001 From: Anil Kumar Tegala Date: Wed, 3 Jul 2024 12:42:12 +0530 Subject: [PATCH 18/18] add roam ota twog and sixg sae test (#964) Signed-off-by: anil-tegala --- .../roam_test/hard_roam/OTA/test_roam_ota.py | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py index 6d2af27585..1a8b7f1c21 100644 --- a/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py +++ b/tests/e2e/advanced/roam_test/hard_roam/OTA/test_roam_ota.py @@ -2365,3 +2365,126 @@ def test_roam_5g_and_6g_wpa3eap(self, get_target_object, get_test_library, get_l pytest.fail(f"Test failed with the following reasons: \n{message}") else: assert True + + @pytest.mark.roam + @pytest.mark.two + @pytest.mark.sixg + @pytest.mark.sae + @pytest.mark.wpa3_personal + def test_roam_2g_and_6g_wpa3psk(self, get_target_object, get_test_library, get_lab_info, selected_testbed): + """ + Test Roaming between two APs, 2G & 6G, WPA3 Personal + pytest -m "roam and two and sixg and wpa3_personal and ota" + """ + ap_data = dict() + dut_list = [str(selected_testbed)] + dut_names = list() + bssid_list = list() + freqs_ = "" + testbed_info = get_lab_info.CONFIGURATION + config = copy.deepcopy(config_data) + temp_list = list() + for key, val in testbed_info.items(): + tb_type, tb_name = selected_testbed.split("-") + if tb_type in key and tb_name[0] in key: + temp_list.append(key) + temp_list.sort() + dut_list = [temp_list[idx] for idx in range(len(temp_list)) if idx <= 1] + config['radios'] = [ + {"band": "2G", "channel": 11, "channel-mode": "HE", "channel-width": 20, "country": "CA"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["2G"] + # change ssid config data to sae + config['interfaces'][0]["ssids"][0]["encryption"]["proto"] = "sae" + if len(dut_list) < 2: + logging.error( + f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}") + assert False, f"This test need two AP's but number of DUT's available in the selected testbed is {dut_list}" + for ap in range(len(dut_list)): + serial_number = testbed_info[dut_list[ap]]["device_under_tests"][0]['identifier'] + dut_names.append(testbed_info[dut_list[ap]]["device_under_tests"][0]['model']) + if ap == 1: + config['radios'] = [{"band": "6G", "channel": 161, "channel-mode": "HE", "channel-width": 80, "country": "US"}] + config['interfaces'][0]["ssids"][0]["wifi-bands"] = ["6G"] + logging.info(config) + payload = {"configuration": json.dumps(config), "serialNumber": serial_number, "UUID": 2} + uri = get_target_object.controller_library_object.build_uri( + "device/" + serial_number + "/configure") + logging.info("Sending Command: " + "\n" + str(uri) + "\n" + + "TimeStamp: " + str(datetime.datetime.utcnow()) + "\n" + + "Data: " + str(json.dumps(payload, indent=2)) + "\n" + + "Headers: " + str(get_target_object.controller_library_object.make_headers())) + allure.attach(name=f"Push roam config on {serial_number}: ", body="Sending Command: " + str(uri) + "\n" + + "TimeStamp: " + str( + datetime.datetime.utcnow()) + "\n" + + "Data: " + str(payload) + "\n" + + "Headers: " + str( + get_target_object.controller_library_object.make_headers())) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + allure.attach(name=f"Response - {resp.status_code} {resp.reason}", body=str(resp.json())) + if resp.status_code != 200: + if resp.status_code == 400 and "Device is already executing a command. Please try later." in \ + resp.json()["ErrorDescription"]: + time.sleep(30) + resp = requests.post(uri, data=json.dumps(payload, indent=2), + headers=get_target_object.controller_library_object.make_headers(), + verify=False, timeout=120) + time.sleep(10) + logging.info(resp.json()) + else: + assert False, f"push configuration to {serial_number} got failed" + get_target_object.dut_library_object.device_under_tests_data = testbed_info[dut_list[ap]][ + "device_under_tests"] + ap_iwinfo = get_target_object.dut_library_object.get_iwinfo(attach_allure=True) + if str(ap_iwinfo) != "Error: pop from empty list": + include_essid = config['interfaces'][0]["ssids"][0]["name"] + re_obj = re.compile( + rf'(wlan\d(?:-\d)?)\s+ESSID: "{re.escape(include_essid)}".*?\s+Access Point:\s+([0-9A-Fa-f:]+).*?Channel:\s+(' + r'\d+)\s+\(([\d.]+) GHz\)', + re.DOTALL + ) + # find all matches + interface_matches = re_obj.finditer(ap_iwinfo) + if interface_matches: + for match in interface_matches: + interface_name = match.group(1) + access_point = match.group(2) + channel = match.group(3) + frequency = match.group(4).replace('.', '') + ap_data.update( + {serial_number: {'Access Point': access_point, 'Channel': channel, 'frequency': frequency}}) + logging.info(f"AP Data from iwinfo: {ap_data}") + else: + logging.error("Failed to get iwinfo") + pytest.exit("Failed to get iwinfo") + elif ap_iwinfo == {}: + pytest.fail("Empty iwinfo reponse from AP through minicom") + else: + pytest.fail("Failed to get iwinfo from minicom") + for serial in ap_data: + bssid_list.append(ap_data[serial]['Access Point']) + if not ap_data[serial]['frequency'].endswith(","): + freqs_ = freqs_ + ap_data[serial]['frequency'] + "," + else: + freqs_ = freqs_ + ap_data[serial]['frequency'] + ssid = config['interfaces'][0]["ssids"][0]["name"] + key = config['interfaces'][0]["ssids"][0]["encryption"]["key"] + try: + pass_fail, message = get_test_library.roam_test(ap1_bssid=bssid_list[0], ap2_bssid=bssid_list[1], + scan_freq=freqs_, + band="both", num_sta=2, security="wpa3", security_key=key, + ssid=ssid, upstream="1.1.eth1", duration=None, + iteration=1, channel="11", option="ota", dut_name=dut_names, + traffic_type="lf_udp", sta_type="11r") + except Exception as e: + logging.error(f"Exception in roam test : {e}") + pass_fail, message = False, e + finally: + get_target_object.dut_library_object.get_dut_logs(print_log=False) + if not pass_fail: + pytest.fail(f"Test failed with the following reasons: \n{message}") + else: + assert True