Skip to content

Commit c27e644

Browse files
authored
Merge pull request #12240 from yarbcy/pr/add-new-tests-softap-2
Cypress: Initial commit of SoftAP host tests
2 parents b96d3ad + c53d2f1 commit c27e644

File tree

3 files changed

+324
-0
lines changed

3 files changed

+324
-0
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
"""
2+
Copyright (c) 2011-2020 ARM Limited
3+
SPDX-License-Identifier: Apache-2.0
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
"""
17+
18+
19+
from mbed_host_tests import BaseHostTest
20+
from mbed_host_tests.host_tests_logger import HtrunLogger
21+
import platform
22+
import time, re, os
23+
import subprocess
24+
25+
26+
class SoftAPBasicHostTests(BaseHostTest):
27+
""" Basic SoftAP test with host as STA
28+
29+
[Following configuration is required before test]
30+
1. Identify and update the host wifi device name self.wifi_dev
31+
2. Add user as sudoer without password to allow script to run sudo command. Restrict the sudo command pattern to enhance security
32+
### sudoer config begin ###
33+
# Allow members of group sudo to execute any command
34+
%sudo ALL=(ALL:ALL) ALL
35+
<user> ALL=(ALL) NOPASSWD: /usr/sbin/rfkill unblock wifi, /sbin/wpa_supplicant -B -i * -c *, /usr/bin/killall wpa_supplicant, /sbin/wpa_cli -i * status, /sbin/dhclient -r *, /sbin/dhclient -nw -1 *
36+
### sudoer config end ###
37+
38+
[Test behavior]
39+
1. Host wait for DUT SoftAP to start
40+
2. Upon receive ('softap', 'xxx') message from DUT SoftAP to perform corresponding test
41+
"""
42+
# Class constants
43+
HOST_WIFI_CONNECTION_WAIT_SEC = 8
44+
HOST_WIFI_DHCP_GET_IP_WAIT_SEC = 3
45+
HOST_WIFI_INTER_CMDS_WAIT_SEC = 1
46+
HOST_WIFI_SEND_PING_ECHO_CNT = 1
47+
HOST_WPA_STATUS_REGEX = re.compile("^wpa_state=(\w+)$", re.MULTILINE)
48+
HOST_WPA_SSID_REGEX = re.compile("^ssid=(\w+)$", re.MULTILINE)
49+
HOST_PING_SOFTAP_REGEX = re.compile("^(\d+) packets transmitted, (\d+) received", re.MULTILINE)
50+
51+
def __init__(self):
52+
super(SoftAPBasicHostTests, self).__init__()
53+
self.logger = HtrunLogger('TEST')
54+
self.log = self.logger.prn_inf
55+
56+
self.__result = False
57+
self.wifi_dev = 'wlan0'
58+
59+
# The SoftAP config must be consisten with client side
60+
self.softap_ssid = 'MBEDSoftAPTest'
61+
self.softap_password = 'abcd1234'
62+
self.softap_ip_address = '192.168.10.1'
63+
64+
self.softap_event_action_table = {
65+
'up' : self.host_wifi_softap_up_test
66+
}
67+
68+
def _callback_os_type(self, key, value, timestamp):
69+
''' Get host OS type
70+
'''
71+
system_name = platform.system()
72+
self.log('os_type = {}'.format(system_name))
73+
self.send_kv("os_type", system_name)
74+
self.__result = True
75+
76+
def _callback_softap_events(self, key, value, timestamp):
77+
''' DUT SoftAP event handler
78+
Root handler of all 'softap' events, dispatch secondary handler based on "value"
79+
'''
80+
self.log('Get ({}, {}) from DUT'.format(key, value))
81+
82+
if not value in self.softap_event_action_table:
83+
self.log('Unknown softap event {}'.format(value))
84+
self.report_error('Unknow softap event')
85+
return None
86+
87+
if not self.softap_event_action_table[value]():
88+
self.report_error('Response to ({}, {}) FAILED!'.format(key, value))
89+
else:
90+
self.report_success()
91+
self.__result = True
92+
return None
93+
94+
def setup(self):
95+
# all functions that can be called from the client
96+
self.register_callback('softap', self._callback_softap_events)
97+
self.register_callback('get_os_type', self._callback_os_type)
98+
try:
99+
cmd = ['sudo', 'rfkill', 'unblock', 'wifi']
100+
output = subprocess.check_output(cmd, universal_newlines=True)
101+
self.log('SETUP: {} => {}'.format(cmd, output))
102+
time.sleep(SoftAPBasicHostTests.HOST_WIFI_INTER_CMDS_WAIT_SEC)
103+
except subprocess.CalledProcessError:
104+
self.log ('WARNING: Setup commands may not all scceeed.')
105+
106+
107+
def result(self):
108+
return self.__result
109+
110+
def teardown(self):
111+
# release existing dhclient
112+
try:
113+
cmd = ['sudo', 'dhclient', '-r', self.wifi_dev]
114+
output = subprocess.check_output(cmd, universal_newlines=True)
115+
self.log('TEARDOWN: {} => {}'.format(cmd, output))
116+
time.sleep(SoftAPBasicHostTests.HOST_WIFI_INTER_CMDS_WAIT_SEC)
117+
118+
cmd = ['sudo', 'killall', 'wpa_supplicant']
119+
output = subprocess.check_output(cmd, universal_newlines=True)
120+
self.log('TEARDOWN: {} => {}'.format(cmd, output))
121+
except subprocess.CalledProcessError:
122+
self.log ('WARNING: TearDown commands may not all scceeed.')
123+
124+
def host_wifi_softap_up_test(self):
125+
''' Run host side test for ('softap', 'up') event
126+
'''
127+
if not self.host_wifi_connect_softap_linux():
128+
return False
129+
if not self.host_wifi_restart_dhcp_linux():
130+
return False
131+
if not self.host_wifi_ping_softap():
132+
return False
133+
return True
134+
135+
def host_wifi_connect_softap_linux(self):
136+
''' Host Linux as STA to connect to DUT SoftAP
137+
Test will run after receiving ('softap', 'up') message from DUT SoftAP
138+
'''
139+
# killall is expected to fail when the host does NOT run wpa_supplicant by default
140+
try:
141+
cmd = ['sudo', 'killall', 'wpa_supplicant']
142+
output = subprocess.check_output(cmd, universal_newlines=True)
143+
self.log('kill existing wpa_supplicant: {}'.format(cmd, universal_newlines=True))
144+
except subprocess.CalledProcessError:
145+
self.log('INFO: no prior wpa_supplicant found')
146+
147+
try:
148+
dir_path = os.path.dirname(os.path.realpath(__file__))
149+
time.sleep(SoftAPBasicHostTests.HOST_WIFI_INTER_CMDS_WAIT_SEC)
150+
cmd = ['sudo', 'wpa_supplicant', '-B', '-i', self.wifi_dev, '-c', \
151+
dir_path+'/softap_wpa_supplicant.conf']
152+
output = subprocess.check_output(cmd, universal_newlines=True)
153+
self.log('start wpa_supplicant: {} => {}'.format(cmd, output))
154+
155+
self.log('Wait {} sec to connecct to {} ...'.format(\
156+
SoftAPBasicHostTests.HOST_WIFI_CONNECTION_WAIT_SEC, self.softap_ssid))
157+
time.sleep(SoftAPBasicHostTests.HOST_WIFI_CONNECTION_WAIT_SEC)
158+
cmd = ['sudo', 'wpa_cli', '-i', self.wifi_dev, 'status']
159+
output = subprocess.check_output(cmd, universal_newlines=True)
160+
self.log('{}: {}'.format(cmd, output))
161+
except subprocess.CalledProcessError as error:
162+
self.log("ERROR: {} => {}".format(error.cmd, error.output))
163+
return False
164+
165+
match = SoftAPBasicHostTests.HOST_WPA_STATUS_REGEX.search(output)
166+
if match is None or (match.group(1) != 'COMPLETED' and match.group(1) != 'ASSOCIATED'):
167+
self.log('ERROR: status => {}'.format(output))
168+
return False
169+
170+
match = SoftAPBasicHostTests.HOST_WPA_SSID_REGEX.search(output)
171+
if match is None or match.group(1) != self.softap_ssid:
172+
self.log('ERROR: status => {}'.format(output))
173+
return False
174+
self.log('SoftAP join PASS')
175+
return True
176+
177+
def host_wifi_restart_dhcp_linux(self):
178+
''' Restart host dhcp client to obtain IP
179+
'''
180+
try:
181+
# release existing dhclient
182+
cmd = ['sudo', 'dhclient', '-r', self.wifi_dev]
183+
output = subprocess.check_output(cmd, universal_newlines=True)
184+
self.log('{} => {}'.format(cmd, output))
185+
time.sleep(SoftAPBasicHostTests.HOST_WIFI_INTER_CMDS_WAIT_SEC)
186+
187+
cmd = ['sudo', 'dhclient', '-nw', '-1', self.wifi_dev]
188+
output = subprocess.check_output(cmd, universal_newlines=True)
189+
self.log('{} => {}'.format(cmd, output))
190+
self.log('Wait {} sec for dhcp to get IP from SoftAP'.format( \
191+
SoftAPBasicHostTests.HOST_WIFI_DHCP_GET_IP_WAIT_SEC))
192+
time.sleep(SoftAPBasicHostTests.HOST_WIFI_DHCP_GET_IP_WAIT_SEC)
193+
except subprocess.CalledProcessError as error:
194+
self.log("ERROR: {} => {}".format(error.cmd, error.output))
195+
return False
196+
return True
197+
198+
def host_wifi_ping_softap(self):
199+
''' Ping SoftAP with self.softap_ip_address
200+
'''
201+
try:
202+
cmd = ['ping', '-c', str(SoftAPBasicHostTests.HOST_WIFI_SEND_PING_ECHO_CNT), \
203+
self.softap_ip_address]
204+
output = subprocess.check_output(cmd, universal_newlines=True)
205+
self.log('{} => {}'.format(cmd, output))
206+
except subprocess.CalledProcessError as error:
207+
self.log("ERROR: {} => {}".format(error.cmd, error.output))
208+
return False
209+
210+
match = SoftAPBasicHostTests.HOST_PING_SOFTAP_REGEX.search(output)
211+
if match is None or match.group(2) == '0':
212+
self.log('Ping ERROR: {} => {}'.format(cmd, output))
213+
return False
214+
self.log('Ping PASS: {}/{} echo received'.format(match.group(2), match.group(1)))
215+
return True
216+
217+
def get_wpa_supplicant_conf_path(self):
218+
''' Report host side test success to DUT
219+
'''
220+
self.send_kv("passed", "0")
221+
222+
def report_success(self):
223+
''' Report host side test success to DUT
224+
'''
225+
self.send_kv("passed", "0")
226+
227+
def report_error(self, msg):
228+
''' Report host side test error to DUT
229+
'''
230+
self.log('{} failed !!!'.format(msg))
231+
self.send_kv("failed", "0")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ctrl_interface=/run/wpa_supplicant
2+
update_config=1
3+
4+
network={
5+
ssid="MBEDSoftAPTest"
6+
#psk="abcd1234"
7+
psk=a2a7f7f2d84390b6c6ba644a3b5f5fbe2113c18734dd992dc0d976529ba684c4
8+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2017-2019, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#if !defined(MBED_CONF_APP_SOFTAP_SSID) || \
19+
!defined(MBED_CONF_APP_SOFTAP_CHANNEL) || \
20+
!defined(MBED_CONF_APP_SOFTAP_PASSWORD)
21+
22+
#error [NOT_SUPPORTED] Requires parameters from mbed_app.json
23+
#endif
24+
25+
#define SOFTAP 1
26+
27+
#if MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE != SOFTAP
28+
29+
#error [NOT_SUPPORTED] SoftAP testing need to be enabled
30+
#endif
31+
32+
#if !defined(TARGET_PSOC6)
33+
#error [NOT_SUPPORTED] Wifi tests are not valid for the target
34+
#endif
35+
36+
#define SOFTAP_IP_ADDRESS "192.168.10.1"
37+
#define NETMASK "255.255.255.0"
38+
#define GATEWAY "192.168.10.1"
39+
40+
#include "greentea-client/test_env.h"
41+
#include "unity.h"
42+
#include "utest.h"
43+
44+
#include "WhdSoftAPInterface.h"
45+
46+
using namespace utest::v1;
47+
48+
static char _key[256] = { 0 };
49+
static char _value[128] = { 0 };
50+
51+
void host_os_type_verification() {
52+
greentea_send_kv("get_os_type", "host");
53+
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
54+
TEST_ASSERT_EQUAL_STRING("Linux", _value);
55+
}
56+
57+
void softap_test() {
58+
WhdSoftAPInterface *softap = WhdSoftAPInterface::get_default_instance();
59+
TEST_ASSERT_TRUE(softap != NULL);
60+
61+
softap->set_network(SOFTAP_IP_ADDRESS, NETMASK, GATEWAY);
62+
int ret = softap->start(MBED_CONF_APP_SOFTAP_SSID, MBED_CONF_APP_SOFTAP_PASSWORD, NSAPI_SECURITY_WPA_WPA2,
63+
MBED_CONF_APP_SOFTAP_CHANNEL);
64+
TEST_ASSERT_EQUAL_INT(0, ret);
65+
greentea_send_kv("softap", "up");
66+
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
67+
TEST_ASSERT_EQUAL_STRING("passed", _key);
68+
}
69+
70+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
71+
// here, we specify the timeout (150) and the host runner (the name of our Python file)
72+
GREENTEA_SETUP(150, "softap_basic");
73+
return greentea_test_setup_handler(number_of_cases);
74+
}
75+
76+
Case cases[] = {
77+
Case("Host OS Type Verification", host_os_type_verification),
78+
Case("SoftAP test", softap_test)
79+
};
80+
81+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
82+
83+
int main() {
84+
return Harness::run(specification);
85+
}

0 commit comments

Comments
 (0)