blob: f414c8e3cf375c7eda0178ad35572c4ac4669d92 [file] [log] [blame]
Etan Cohen872a6be2017-05-16 08:08:15 -07001#!/usr/bin/python3.4
2#
3# Copyright 2017 - The Android Open Source Project
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
17import string
Etan Cohenfb7f3b12017-05-19 06:54:03 -070018import time
Etan Cohen872a6be2017-05-16 08:08:15 -070019
20from acts import asserts
21from acts.test_utils.wifi.aware import aware_const as aconsts
22from acts.test_utils.wifi.aware import aware_test_utils as autils
23from acts.test_utils.wifi.aware.AwareBaseTest import AwareBaseTest
24
25
26class DiscoveryTest(AwareBaseTest):
27 """Set of tests for Wi-Fi Aware discovery."""
28
29 # configuration parameters used by tests
30 PAYLOAD_SIZE_MIN = 0
31 PAYLOAD_SIZE_TYPICAL = 1
32 PAYLOAD_SIZE_MAX = 2
33
34 # message strings
35 query_msg = "How are you doing? 你好嗎?"
36 response_msg = "Doing ok - thanks! 做的不錯 - 謝謝!"
37
38 # message re-transmit counter (increases reliability in open-environment)
39 # Note: reliability of message transmission is tested elsewhere
40 msg_retx_count = 5 # hard-coded max value, internal API
41
42 def __init__(self, controllers):
43 AwareBaseTest.__init__(self, controllers)
44
Etan Cohenfb7f3b12017-05-19 06:54:03 -070045 def create_base_config(self, caps, is_publish, ptype, stype, payload_size,
46 ttl, term_ind_on, null_match):
Etan Cohen872a6be2017-05-16 08:08:15 -070047 """Create a base configuration based on input parameters.
48
49 Args:
Etan Cohenfb7f3b12017-05-19 06:54:03 -070050 caps: device capability dictionary
Etan Cohen872a6be2017-05-16 08:08:15 -070051 is_publish: True if a publish config, else False
52 ptype: unsolicited or solicited (used if is_publish is True)
53 stype: passive or active (used if is_publish is False)
54 payload_size: min, typical, max (PAYLOAD_SIZE_xx)
55 ttl: time-to-live configuration (0 - forever)
56 term_ind_on: is termination indication enabled
57 null_match: null-out the middle match filter
58 Returns:
59 publish discovery configuration object.
60 """
61 config = {}
62 if is_publish:
63 config[aconsts.DISCOVERY_KEY_DISCOVERY_TYPE] = ptype
64 else:
65 config[aconsts.DISCOVERY_KEY_DISCOVERY_TYPE] = stype
66 config[aconsts.DISCOVERY_KEY_TTL] = ttl
67 config[aconsts.DISCOVERY_KEY_TERM_CB_ENABLED] = term_ind_on
68 if payload_size == self.PAYLOAD_SIZE_MIN:
69 config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "a"
70 config[aconsts.DISCOVERY_KEY_SSI] = None
Etan Cohen0bc1cab2017-05-18 15:30:41 -070071 config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = []
Etan Cohen872a6be2017-05-16 08:08:15 -070072 elif payload_size == self.PAYLOAD_SIZE_TYPICAL:
73 config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "GoogleTestServiceX"
74 if is_publish:
75 config[aconsts.DISCOVERY_KEY_SSI] = string.ascii_letters
76 else:
77 config[aconsts.DISCOVERY_KEY_SSI] = string.ascii_letters[::
78 -1] # reverse
79 config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
80 [(10).to_bytes(1, byteorder="big"), "hello there string"
81 if not null_match else None,
82 bytes(range(40))])
Etan Cohen5a629a62017-05-19 15:11:18 -070083 else: # PAYLOAD_SIZE_MAX
84 config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "VeryLong" + "X" * (
85 caps[aconsts.CAP_MAX_SERVICE_NAME_LEN] - 8)
86 config[aconsts.DISCOVERY_KEY_SSI] = ("P" if is_publish else "S") * caps[
87 aconsts.CAP_MAX_SERVICE_SPECIFIC_INFO_LEN]
88 mf = autils.construct_max_match_filter(
89 caps[aconsts.CAP_MAX_MATCH_FILTER_LEN])
90 if null_match:
91 mf[2] = None
92 config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(mf)
93
Etan Cohen872a6be2017-05-16 08:08:15 -070094 return config
95
Etan Cohenfb7f3b12017-05-19 06:54:03 -070096 def create_publish_config(self, caps, ptype, payload_size, ttl, term_ind_on,
Etan Cohen872a6be2017-05-16 08:08:15 -070097 null_match):
98 """Create a publish configuration based on input parameters.
99
100 Args:
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700101 caps: device capability dictionary
Etan Cohen872a6be2017-05-16 08:08:15 -0700102 ptype: unsolicited or solicited
103 payload_size: min, typical, max (PAYLOAD_SIZE_xx)
104 ttl: time-to-live configuration (0 - forever)
105 term_ind_on: is termination indication enabled
106 null_match: null-out the middle match filter
107 Returns:
108 publish discovery configuration object.
109 """
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700110 return self.create_base_config(caps, True, ptype, None, payload_size, ttl,
Etan Cohen872a6be2017-05-16 08:08:15 -0700111 term_ind_on, null_match)
112
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700113 def create_subscribe_config(self, caps, stype, payload_size, ttl, term_ind_on,
Etan Cohen872a6be2017-05-16 08:08:15 -0700114 null_match):
115 """Create a subscribe configuration based on input parameters.
116
117 Args:
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700118 caps: device capability dictionary
Etan Cohen872a6be2017-05-16 08:08:15 -0700119 stype: passive or active
120 payload_size: min, typical, max (PAYLOAD_SIZE_xx)
121 ttl: time-to-live configuration (0 - forever)
122 term_ind_on: is termination indication enabled
123 null_match: null-out the middle match filter
124 Returns:
125 subscribe discovery configuration object.
126 """
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700127 return self.create_base_config(caps, False, None, stype, payload_size, ttl,
Etan Cohen872a6be2017-05-16 08:08:15 -0700128 term_ind_on, null_match)
129
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700130 def positive_discovery_test_utility(self, ptype, stype, payload_size):
Etan Cohen872a6be2017-05-16 08:08:15 -0700131 """Utility which runs a positive discovery test:
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700132 - Discovery (publish/subscribe) with TTL=0 (non-self-terminating)
Etan Cohen872a6be2017-05-16 08:08:15 -0700133 - Exchange messages
134 - Update publish/subscribe
135 - Terminate
136
137 Args:
138 ptype: Publish discovery type
139 stype: Subscribe discovery type
140 payload_size: One of PAYLOAD_SIZE_* constants - MIN, TYPICAL, MAX
Etan Cohen872a6be2017-05-16 08:08:15 -0700141 """
142 p_dut = self.android_devices[0]
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700143 p_dut.pretty_name = "Publisher"
Etan Cohen872a6be2017-05-16 08:08:15 -0700144 s_dut = self.android_devices[1]
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700145 s_dut.pretty_name = "Subscriber"
Etan Cohen872a6be2017-05-16 08:08:15 -0700146
147 # Publisher+Subscriber: attach and wait for confirmation
148 p_id = p_dut.droid.wifiAwareAttach(False)
149 autils.wait_for_event(p_dut, aconsts.EVENT_CB_ON_ATTACHED)
150 s_id = s_dut.droid.wifiAwareAttach(False)
151 autils.wait_for_event(s_dut, aconsts.EVENT_CB_ON_ATTACHED)
152
153 # Publisher: start publish and wait for confirmation
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700154 p_config = self.create_publish_config(
155 p_dut.aware_capabilities,
156 ptype,
157 payload_size,
158 ttl=0,
159 term_ind_on=False,
160 null_match=False)
Etan Cohen872a6be2017-05-16 08:08:15 -0700161 p_disc_id = p_dut.droid.wifiAwarePublish(p_id, p_config)
162 autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
163
164 # Subscriber: start subscribe and wait for confirmation
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700165 s_config = self.create_subscribe_config(
166 s_dut.aware_capabilities,
167 stype,
168 payload_size,
169 ttl=0,
170 term_ind_on=False,
171 null_match=True)
Etan Cohen872a6be2017-05-16 08:08:15 -0700172 s_disc_id = s_dut.droid.wifiAwareSubscribe(s_id, s_config)
173 autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
174
175 # Subscriber: wait for service discovery
176 discovery_event = autils.wait_for_event(
177 s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
178 peer_id_on_sub = discovery_event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
179
180 # Subscriber: validate contents of discovery (specifically that getting the
181 # Publisher's SSI and MatchFilter!)
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700182 autils.assert_equal_strings(
Etan Cohen872a6be2017-05-16 08:08:15 -0700183 bytes(discovery_event["data"][
184 aconsts.SESSION_CB_KEY_SERVICE_SPECIFIC_INFO]).decode("utf-8"),
185 p_config[aconsts.DISCOVERY_KEY_SSI],
186 "Discovery mismatch: service specific info (SSI)")
187 asserts.assert_equal(
188 autils.decode_list(
189 discovery_event["data"][aconsts.SESSION_CB_KEY_MATCH_FILTER_LIST]),
190 autils.decode_list(p_config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]),
191 "Discovery mismatch: match filter")
192
193 # Subscriber: send message to peer (Publisher)
194 s_dut.droid.wifiAwareSendMessage(s_disc_id, peer_id_on_sub,
195 self.get_next_msg_id(), self.query_msg,
196 self.msg_retx_count)
197 autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_MESSAGE_SENT)
198
199 # Publisher: wait for received message
200 pub_rx_msg_event = autils.wait_for_event(
201 p_dut, aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
202 peer_id_on_pub = pub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
203
204 # Publisher: validate contents of message
205 asserts.assert_equal(
206 pub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING],
207 self.query_msg, "Subscriber -> Publisher message corrupted")
208
209 # Publisher: send message to peer (Subscriber)
210 p_dut.droid.wifiAwareSendMessage(p_disc_id, peer_id_on_pub,
211 self.get_next_msg_id(), self.response_msg,
212 self.msg_retx_count)
213 autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_MESSAGE_SENT)
214
215 # Subscriber: wait for received message
216 sub_rx_msg_event = autils.wait_for_event(
217 s_dut, aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
218
219 # Subscriber: validate contents of message
220 asserts.assert_equal(
221 sub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_PEER_ID],
222 peer_id_on_sub,
223 "Subscriber received message from different peer ID then discovery!?")
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700224 autils.assert_equal_strings(
Etan Cohen872a6be2017-05-16 08:08:15 -0700225 sub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING],
226 self.response_msg, "Publisher -> Subscriber message corrupted")
227
228 # Subscriber: validate that we're not getting another Service Discovery
229 autils.fail_on_event(s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
230
231 # Publisher: update publish and wait for confirmation
232 p_config[aconsts.DISCOVERY_KEY_SSI] = "something else"
233 p_dut.droid.wifiAwareUpdatePublish(p_disc_id, p_config)
234 autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED)
235
236 # Subscriber: expect a new service discovery
237 discovery_event = autils.wait_for_event(
238 s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
239
240 # Subscriber: validate contents of discovery
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700241 autils.assert_equal_strings(
Etan Cohen872a6be2017-05-16 08:08:15 -0700242 bytes(discovery_event["data"][
243 aconsts.SESSION_CB_KEY_SERVICE_SPECIFIC_INFO]).decode("utf-8"),
244 p_config[aconsts.DISCOVERY_KEY_SSI],
245 "Discovery mismatch (after pub update): service specific info (SSI)")
246 asserts.assert_equal(
247 autils.decode_list(
248 discovery_event["data"][aconsts.SESSION_CB_KEY_MATCH_FILTER_LIST]),
249 autils.decode_list(p_config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]),
250 "Discovery mismatch: match filter")
251
252 # Subscribe: update subscribe and wait for confirmation
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700253 s_config = self.create_subscribe_config(
254 s_dut.aware_capabilities,
255 stype,
256 payload_size,
257 ttl=0,
258 term_ind_on=False,
259 null_match=False)
Etan Cohen872a6be2017-05-16 08:08:15 -0700260 s_dut.droid.wifiAwareUpdateSubscribe(s_disc_id, s_config)
261 autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED)
262
Etan Cohen872a6be2017-05-16 08:08:15 -0700263 # Publisher+Subscriber: Terminate sessions
264 p_dut.droid.wifiAwareDestroyDiscoverySession(p_disc_id)
265 s_dut.droid.wifiAwareDestroyDiscoverySession(s_disc_id)
266
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700267 # sleep for timeout period and then verify all 'fail_on_event' together
268 time.sleep(autils.EVENT_TIMEOUT)
269
270 # Subscriber: should not get a new service discovery (no new information)
271 autils.fail_on_event(
272 s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, timeout=0)
273
274 # Publisher: should never get a service discovery event!
275 autils.fail_on_event(
276 p_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, timeout=0)
277
278 # Publisher+Subscriber: should not get termination indication (since we're
279 # destroying sessions explicitly)
280 autils.fail_on_event(
281 p_dut, aconsts.SESSION_CB_ON_SESSION_TERMINATED, timeout=0)
282 autils.fail_on_event(
283 s_dut, aconsts.SESSION_CB_ON_SESSION_TERMINATED, timeout=0)
284
285 # verify that there were no other events
286 autils.verify_no_more_events(p_dut)
287 autils.verify_no_more_events(s_dut)
Etan Cohen872a6be2017-05-16 08:08:15 -0700288
289 #######################################
290 # Positive tests key:
291 #
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700292 # names is: test_<pub_type>_<sub_type>_<size>
Etan Cohen872a6be2017-05-16 08:08:15 -0700293 # where:
294 #
295 # pub_type: Type of publish discovery session: unsolicited or solicited.
296 # sub_type: Type of subscribe discovery session: passive or active.
297 # size: Size of payload fields (service name, service specific info, and match
298 # filter: typical, max, or min.
Etan Cohen872a6be2017-05-16 08:08:15 -0700299 #######################################
300
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700301 def test_positive_unsolicited_passive_typical(self):
Etan Cohen872a6be2017-05-16 08:08:15 -0700302 """Functional test case / Discovery test cases / positive test case:
303 - Solicited publish + passive subscribe
304 - Typical payload fields size
Etan Cohen872a6be2017-05-16 08:08:15 -0700305
306 Verifies that discovery and message exchange succeeds.
307 """
308 self.positive_discovery_test_utility(
309 ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
310 stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700311 payload_size=self.PAYLOAD_SIZE_TYPICAL)
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700312
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700313 def test_positive_unsolicited_passive_min(self):
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700314 """Functional test case / Discovery test cases / positive test case:
315 - Solicited publish + passive subscribe
316 - Minimal payload fields size
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700317
318 Verifies that discovery and message exchange succeeds.
319 """
320 self.positive_discovery_test_utility(
321 ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
322 stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700323 payload_size=self.PAYLOAD_SIZE_MIN)
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700324
Etan Cohen5a629a62017-05-19 15:11:18 -0700325 def test_positive_unsolicited_passive_max(self):
326 """Functional test case / Discovery test cases / positive test case:
327 - Solicited publish + passive subscribe
328 - Maximal payload fields size
329
330 Verifies that discovery and message exchange succeeds.
331 """
332 self.positive_discovery_test_utility(
333 ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
334 stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
335 payload_size=self.PAYLOAD_SIZE_MAX)
336
337
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700338 def test_positive_solicited_active_typical(self):
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700339 """Functional test case / Discovery test cases / positive test case:
340 - Unsolicited publish + active subscribe
341 - Typical payload fields size
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700342
343 Verifies that discovery and message exchange succeeds.
344 """
345 self.positive_discovery_test_utility(
346 ptype=aconsts.PUBLISH_TYPE_SOLICITED,
347 stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700348 payload_size=self.PAYLOAD_SIZE_TYPICAL)
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700349
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700350 def test_positive_solicited_active_min(self):
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700351 """Functional test case / Discovery test cases / positive test case:
352 - Unsolicited publish + active subscribe
353 - Minimal payload fields size
Etan Cohen0bc1cab2017-05-18 15:30:41 -0700354
355 Verifies that discovery and message exchange succeeds.
356 """
357 self.positive_discovery_test_utility(
358 ptype=aconsts.PUBLISH_TYPE_SOLICITED,
359 stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
Etan Cohenfb7f3b12017-05-19 06:54:03 -0700360 payload_size=self.PAYLOAD_SIZE_MIN)
Etan Cohen5a629a62017-05-19 15:11:18 -0700361
362 def test_positive_solicited_active_max(self):
363 """Functional test case / Discovery test cases / positive test case:
364 - Unsolicited publish + active subscribe
365 - Maximal payload fields size
366
367 Verifies that discovery and message exchange succeeds.
368 """
369 self.positive_discovery_test_utility(
370 ptype=aconsts.PUBLISH_TYPE_SOLICITED,
371 stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
372 payload_size=self.PAYLOAD_SIZE_MAX)