Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ce-oem] Add wifi AP mode test (New) #1606

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
1ce1084
Resolve code conflict while rebasing
rickwu666666 Dec 10, 2024
97b5f1f
Fix black format
rickwu666666 Nov 19, 2024
db6b368
Fix shell check fail
rickwu666666 Nov 19, 2024
ab308d9
Fix flake8
rickwu666666 Nov 19, 2024
e1d35f5
Remove manual test jobs, since those jobs are the same as automated jobs
rickwu666666 Nov 20, 2024
838b76b
Rename --manual arg to --set-ap-only
rickwu666666 Nov 20, 2024
e5602c0
Update contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/wifi_test.py
rickwu666666 Dec 4, 2024
02d3621
Move run_command function out of WiFiManager class
rickwu666666 Dec 3, 2024
7fead1a
Add connect_dut function in WiFiManager class to generate the related…
rickwu666666 Dec 4, 2024
47dd62d
Modify args type/interface/band/channel as required args
rickwu666666 Dec 4, 2024
a423212
Add arg type in the job
rickwu666666 Dec 4, 2024
27d2cfb
Update contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/wifi_test.py
rickwu666666 Dec 10, 2024
a8538b5
Update contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/wifi_test.py
rickwu666666 Dec 10, 2024
9a77b08
Move set_secured and up_conn as part of __enter__ function
rickwu666666 Dec 10, 2024
4396f43
Add log for the running command
rickwu666666 Dec 10, 2024
8e4df5d
Remove --set-ap-only related code
rickwu666666 Dec 11, 2024
f29442a
Modify argparser as two subparser for wifi and wifi-p2p to make comma…
rickwu666666 Dec 11, 2024
da9c11b
Move type wifi initial steps into init_conn function
rickwu666666 Dec 11, 2024
c6f4b96
Add some description of this script about the limitation of network-m…
rickwu666666 Dec 11, 2024
812a99e
Fix argparse issue
rickwu666666 Dec 12, 2024
bd7c1de
Modify test and add a defualt set to test
rickwu666666 Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
303 changes: 303 additions & 0 deletions contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/wifi_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
#!/usr/bin/env python3
"""
This script base on network-manager. And network-manager has it own
limitation about wifi ap mode and wifi-p2p.
For wifi ap mode:
Only band a and bg are supported

For wifi-p2p:
We are not able to validate the result even following the user
manual of network-manager.

Please refer to following for more details:
[1] https://networkmanager.dev/docs/api/latest/nm-settings-nmcli.html
[2] https://netplan.readthedocs.io/en/stable/netplan-yaml
[3] https://bugs.launchpad.net/carmel/+bug/2080353/comments/2

"""
import argparse
import subprocess
import sys
import time
import logging
import re
import random
import string

# Configure logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)


class WiFiManager:
def __init__(self, **kwargs):
"""
Initialize the WiFiManager with dynamic arguments.
kwargs: Dictionary of configuration arguments.
"""
self._command = "nmcli"
self.interface = kwargs.get("interface")
self.type = kwargs.get("type")
self.mode = kwargs.get("mode")
self.band = kwargs.get("band")
self.channel = kwargs.get("channel")
self.key_mgmt = kwargs.get("key_mgmt")
self.group = kwargs.get("group")
self.peer = kwargs.get("peer")
self.ssid = kwargs.get("ssid", "qa-test-ssid")
self.ssid_pwd = kwargs.get("ssid_pwd", "insecure")
self.conname = "qa-test-ap"

def init_conn(self):
logging.info("Initializing connection")
if self.type == "wifi":
run_command(
"{} c add type {} ifname {} con-name {} "
"autoconnect no wifi.ssid {} "
"wifi.mode {} ipv4.method shared".format(
self._command,
self.type,
self.interface,
self.conname,
self.ssid,
self.mode,
)
)
self.set_band_channel()
if self.key_mgmt is not None:
self.set_secured()
elif self.type == "wifi-p2p":
run_command(
"{} c add type {} ifname {} con-name {} \
wifi-p2p.peer {}".format(
self._command,
self.type,
self.interface,
self.conname,
self.peer,
)
)
else:
raise ValueError("Unsupported type: {}".format(self.type))

def set_band_channel(self):
"""
Set band, channel and channel-width.
If channel and channel-width in 0, run command with setting band only.
"""
cmd = "{} c modify {} wifi.band {} ".format(
self._command, self.conname, self.band
)
if self.channel:
cmd += "wifi.channel {} ".format(self.channel)
run_command(cmd)

def set_secured(self):
run_command(
"{} c modify {} wifi-sec.key-mgmt {} wifi-sec.psk {}\
wifi-sec.group {}".format(
self._command,
self.conname,
self.key_mgmt,
self.ssid_pwd,
self.group,
)
)

def get_ip_addr(self):
"""
nmcli -g IP4.ADDRESS command will return the IPv4 address of the
interface with netmask.
e.g. 10.102.99.224/22
"""
ip_addr = run_command(
"{} -g IP4.ADDRESS device show {}".format(
self._command,
self.interface,
)
)
ip_addr = ip_addr.split("/")[0] if ip_addr.find("/") != -1 else ""
return ip_addr

def up_conn(self):
try:
run_command("{} c up {}".format(self._command, self.conname))
logging.info("Initialized connection successful!")
except Exception:
raise SystemError("Bring up connection failed!")
for i in range(1, 6):
try:
ip_addr = self.get_ip_addr()
if ip_addr:
logging.info("IP address is {}".format(ip_addr))
return True
except subprocess.CalledProcessError:
pass
time.sleep(5)
return False

def del_conn(self):
run_command("{} c delete {}".format(self._command, self.conname))

def connect_dut(self):
connect_cmd = "{} d wifi c {}".format(self._command, self.ssid)
if self.key_mgmt != "none":
connect_cmd += " password {}".format(self.ssid_pwd)
if self.mode == "adhoc":
connect_cmd += " wifi.mode {}".format(self.mode)
return connect_cmd

def __enter__(self):
self.init_conn()
if not self.up_conn():
raise RuntimeError("Connection initialization failed!")

def __exit__(self, exc_type, exc_value, traceback):
logging.info("Exiting context and cleaning up connection")
self.del_conn()


def run_command(command):
logging.info("Run command: %s", command)
output = subprocess.check_output(
command, shell=True, stderr=subprocess.STDOUT
)
return output.decode()


def sshpass_cmd_gen(ip, user, pwd, cmd):
return "sshpass -p {} ssh -o StrictHostKeyChecking=no {}@{} {}".format(
pwd, user, ip, cmd
)


def ping_cmd(ip):
return "ping {} -c 4".format(ip)


def connect_host_device(manager, ip, user, pwd):
connect_cmd = manager.connect_dut()
ssid = manager.ssid
logging.info("Ping target Host first ...")
try:
run_command(ping_cmd(ip))
logging.info("Ping target Host %s successful...", ip)
logging.info("Attempting to connect DUT AP %s...", ssid)
for i in range(1, 11):
logging.info("Attempting to connect DUT AP %s %d time...", ssid, i)
try:
run_command(sshpass_cmd_gen(ip, user, pwd, connect_cmd))
logging.info("Connect successful!")
return True
except Exception:
logging.warning("Not able to found SSID %s", ssid)
time.sleep(10)
logging.error("Not able to connect to DUT AP SSID %s", ssid)
except Exception:
logging.error("Not able to ping the HOST!")


def ping_test(manager, ip, user, pwd):
try:
logging.info("Attempting to ping DUT...")
ping_result = run_command(
sshpass_cmd_gen(ip, user, pwd, ping_cmd(manager.get_ip_addr()))
)
packet_loss = re.search(r"(\d+)% packet loss", ping_result).group(1)
logging.info("Packet loss: %s %%", packet_loss)
if packet_loss == "0":
logging.info("Ping DUT pass")
exit_code = 0
else:
logging.error("Ping DUT fail with %s %% packet loss!", packet_loss)
exit_code = 1
except Exception as e:
logging.error("An error occurred during ping_test: %s", str(e))
exit_code = 1
finally:
del_host_conn = "{} c delete {}".format(manager._command, manager.ssid)
try:
run_command(sshpass_cmd_gen(ip, user, pwd, del_host_conn))
logging.info("Deleted host connection successfully.")
except Exception as e:
logging.error("Failed to delete host connection: %s", str(e))
sys.exit(exit_code)


def main():
parser = argparse.ArgumentParser(description="WiFi test")
subparsers = parser.add_subparsers(
dest="type",
required=True,
help="Type of connection. " 'Currentlly support "wifi" and "wifi-p2p"',
)
# Subparser for 'wifi'
wifi_parser = subparsers.add_parser("wifi", help="WiFi configuration")
wifi_parser.add_argument(
"--mode",
choices=["ap", "adhoc"],
required=True,
help="WiFi mode: ap or adhoc",
)
wifi_parser.add_argument("--band", required=True, help="WiFi band to use")
wifi_parser.add_argument(
"--channel", required=True, type=int, help="WiFi channel to use"
)
wifi_parser.add_argument(
"--keymgmt", required=False, help="Key management method"
)
wifi_parser.add_argument(
"--group", required=False, help="Group key management method"
)
wifi_parser.add_argument(
"--ssid",
default="".join(
[random.choice(string.ascii_letters) for _ in range(10)]
),
required=False,
help="SSID for AP mode",
)
wifi_parser.add_argument(
"--ssid-pwd", required=False, help="Password for SSID"
)

# Subparser for 'wifi-p2p'
wifi_p2p_parser = subparsers.add_parser(
"wifi-p2p", help="WiFi P2P configuration"
)
wifi_p2p_parser.add_argument(
"--peer", required=True, help="MAC address for P2P peer"
)
parser.add_argument(
"--interface", required=True, help="WiFi interface to use"
)
parser.add_argument(
"--host-ip",
required=True,
help="IP address of the Host device to connect to."
"The HOST is a device to access the DUT's AP.",
)
parser.add_argument(
"--host-user",
required=True,
help="Username of the Host device for SSH connection",
)
parser.add_argument(
"--host-pwd",
required=True,
help="Password of the Host device for SSH connection",
)

args = parser.parse_args()
rickwu666666 marked this conversation as resolved.
Show resolved Hide resolved
config = vars(args)
manager = WiFiManager(**config)
with manager:
if connect_host_device(
manager, args.host_ip, args.host_user, args.host_pwd
):
ping_test(manager, args.host_ip, args.host_user, args.host_pwd)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ nested_part:
before-suspend-ce-oem-spi-automated
ce-oem-gadget-automated
ce-oem-mir-automated
ce-oem-wifi-ap-automated
certification_status_overrides:
apply blocker to .*

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# This is a file introducing WiFi AP mode test jobs.
To perform WiFi AP mode test, you will need following environment:
>Both DUT and HOST with Netwrok-Manager installed and wireless interface is managed by Network-Manager\
And must have network connection between DUT and HOST via ethernet port, since we are intend to test wireless.

## id: ce_oem_wifi_ap_mode
This resource job requires the checkbox environment variable `WIFI_AP_MODE`.
It defines which WiFi AP mode should be test includes different wireless interface,
band, key_mgmt, group and password.\
Usage of parameter:\
WIFI_AP_MODE={interface_name}:{band in a|bg}:{channel}:{key_mgmt}:{group in one of ciphers wep40|wep104|tkip|ccmp}
>WIFI_AP_MODE=wlan0:a:44:wpa-psk:ccmp wlan0:bg:5:none:none

Above config defined two different AP mode that intend to test.
The following will break down first part of the config.\
>wlan0:a:44:wpa-psk:ccmp:insecure
>>wlan0: The interface name to use\
a: The band to use\
44: The channel to use\
wpa-psk: The key_magmt to use\
ccmp: The cipher group to use

>waln0:bg:5:none:none
>>wlan0: The interface name to use\
bg: The band to use\
5: The channel to use\
none: Setup as open AP\
none: No need cipher group for a open AP

>Note: Netwrok Manager support only band A and BG. Please refer to follows for more detail.
https://networkmanager.dev/docs/api/latest/settings-802-11-wireless.html
https://networkmanager.dev/docs/api/latest/settings-802-11-wireless-security.html

## id: ce-oem-wireless/ap_open_{band}_ch{channel}_{group}_{interface}_manual
A template job for open AP mode manual test. It will depend on resource job `ce_oem_wifi_ap_mode` to generate the related jobs.\
In this job. It will setup the target AP mode on DUT, and tester need to connect to
the ssid `qa-test-ssid` and ping the DUT default IP address `10.42.0.1` on a HOST machine.

## id: ce-oem-wireless/ap_wpa_{key_mgmt}_{band}_ch{channel}_{group}_{interface}_manual
A template job for WPA AP mode manual test. It will depend on resource job `ce_oem_wifi_ap_mode` to generate the related jobs.\
In this job. It will setup the target AP mode on DUT, and tester need to connect to
the ssid `qa-test-ssid` with password `insecure`, and ping the DUT default IP address
`10.42.0.1` on a HOST machine.

## id: ce-oem-wireless/ap_open_{band}_ch{channel}_{group}_{interface}_automated
A template job for open AP mode automated test. It will depend on resource job `ce_oem_wifi_ap_mode` to generate the related jobs.\
This job requires the checkbox environment variables `WIFI_AP_HOST_DEVICE_IP` `WIFI_AP_HOST_DEVICE_USER` `WIFI_AP_HOST_DEVICE_PWD` to allow auto login to HOST machine
and perform connecting AP and ping DUT automaticlly by using `sshpass` command.

## id: ce-oem-wireless/ap_wpa_{key_mgmt}_{band}_ch{channel}_{group}_{interface}_automated
A template job for WPA AP mode automated test. It will depend on resource job `ce_oem_wifi_ap_mode` to generate the related jobs.\
This job requires the checkbox environment variables `WIFI_AP_HOST_DEVICE_IP` `WIFI_AP_HOST_DEVICE_USER` `WIFI_AP_HOST_DEVICE_PWD` to allow auto login to HOST machine
and perform connecting AP and ping DUT automaticlly by using `sshpass` command.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
id: ce-oem-wifi-ap-full
unit: test plan
_name: ce-oem WiFi AP mode tests
_description: Full WiFi AP mode tests for ce-oem
include:
nested_part:
ce-oem-wifi-ap-manual
ce-oem-wifi-ap-automated

id: ce-oem-wifi-ap-manual
unit: test plan
_name: ce-oem manual WiFi AP mode tests
_description: Manual WiFi AP mode tests
mandatory_include:
bootstrap_include:
include:

id: ce-oem-wifi-ap-automated
unit: test plan
_name: ce-oem automated WiFi AP mode tests
_description: automated WiFi AP mode tests for ce-oem
mandatory_include:
bootstrap_include:
com.canonical.certification::device
com.canonical.certification::wifi_interface_mode
com.canonical.certification::net_if_management
ce_oem_wifi_ap_mode
include:
ce-oem-wireless/ap_open_.*_automated
ce-oem-wireless/ap_wpa_.*_automated
Loading
Loading