xref: /aosp_15_r20/external/openthread/tools/harness-automation/autothreadharness/harness_case.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python
2*cfb92d14SAndroid Build Coastguard Worker#
3*cfb92d14SAndroid Build Coastguard Worker# Copyright (c) 2016, The OpenThread Authors.
4*cfb92d14SAndroid Build Coastguard Worker# All rights reserved.
5*cfb92d14SAndroid Build Coastguard Worker#
6*cfb92d14SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without
7*cfb92d14SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met:
8*cfb92d14SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright
9*cfb92d14SAndroid Build Coastguard Worker#    notice, this list of conditions and the following disclaimer.
10*cfb92d14SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright
11*cfb92d14SAndroid Build Coastguard Worker#    notice, this list of conditions and the following disclaimer in the
12*cfb92d14SAndroid Build Coastguard Worker#    documentation and/or other materials provided with the distribution.
13*cfb92d14SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the
14*cfb92d14SAndroid Build Coastguard Worker#    names of its contributors may be used to endorse or promote products
15*cfb92d14SAndroid Build Coastguard Worker#    derived from this software without specific prior written permission.
16*cfb92d14SAndroid Build Coastguard Worker#
17*cfb92d14SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*cfb92d14SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*cfb92d14SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*cfb92d14SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*cfb92d14SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*cfb92d14SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*cfb92d14SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*cfb92d14SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*cfb92d14SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*cfb92d14SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*cfb92d14SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE.
28*cfb92d14SAndroid Build Coastguard Worker#
29*cfb92d14SAndroid Build Coastguard Worker
30*cfb92d14SAndroid Build Coastguard Workerimport ConfigParser
31*cfb92d14SAndroid Build Coastguard Workerimport json
32*cfb92d14SAndroid Build Coastguard Workerimport logging
33*cfb92d14SAndroid Build Coastguard Workerimport os
34*cfb92d14SAndroid Build Coastguard Workerimport subprocess
35*cfb92d14SAndroid Build Coastguard Workerimport re
36*cfb92d14SAndroid Build Coastguard Workerimport time
37*cfb92d14SAndroid Build Coastguard Workerimport unittest
38*cfb92d14SAndroid Build Coastguard Worker
39*cfb92d14SAndroid Build Coastguard Workerfrom selenium import webdriver
40*cfb92d14SAndroid Build Coastguard Workerfrom selenium.webdriver import ActionChains
41*cfb92d14SAndroid Build Coastguard Workerfrom selenium.webdriver.support.ui import Select
42*cfb92d14SAndroid Build Coastguard Workerfrom selenium.common.exceptions import UnexpectedAlertPresentException
43*cfb92d14SAndroid Build Coastguard Workerfrom selenium.common.exceptions import NoSuchElementException
44*cfb92d14SAndroid Build Coastguard Workerfrom functools import reduce
45*cfb92d14SAndroid Build Coastguard Worker
46*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness import settings
47*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness.exceptions import FailError, FatalError, GoldenDeviceNotEnoughError
48*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness.harness_controller import HarnessController
49*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness.helpers import HistoryHelper
50*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness.open_thread_controller import OpenThreadController
51*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness.pdu_controller_factory import PduControllerFactory
52*cfb92d14SAndroid Build Coastguard Workerfrom autothreadharness.rf_shield_controller import get_rf_shield_controller
53*cfb92d14SAndroid Build Coastguard Worker
54*cfb92d14SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
55*cfb92d14SAndroid Build Coastguard Worker
56*cfb92d14SAndroid Build Coastguard WorkerTHREAD_CHANNEL_MAX = 26
57*cfb92d14SAndroid Build Coastguard Worker"""Maximum channel number of thread protocol"""
58*cfb92d14SAndroid Build Coastguard Worker
59*cfb92d14SAndroid Build Coastguard WorkerTHREAD_CHANNEL_MIN = 11
60*cfb92d14SAndroid Build Coastguard Worker"""Minimum channel number of thread protocol"""
61*cfb92d14SAndroid Build Coastguard Worker
62*cfb92d14SAndroid Build Coastguard WorkerDEFAULT_TIMEOUT = 2700
63*cfb92d14SAndroid Build Coastguard Worker"""Timeout for each test case in seconds"""
64*cfb92d14SAndroid Build Coastguard Worker
65*cfb92d14SAndroid Build Coastguard Worker
66*cfb92d14SAndroid Build Coastguard Workerdef wait_until(what, times=-1):
67*cfb92d14SAndroid Build Coastguard Worker    """Wait until `what` return True
68*cfb92d14SAndroid Build Coastguard Worker
69*cfb92d14SAndroid Build Coastguard Worker    Args:
70*cfb92d14SAndroid Build Coastguard Worker        what (Callable[bool]): Call `wait()` again and again until it returns True
71*cfb92d14SAndroid Build Coastguard Worker        times (int): Maximum times of trials before giving up
72*cfb92d14SAndroid Build Coastguard Worker
73*cfb92d14SAndroid Build Coastguard Worker    Returns:
74*cfb92d14SAndroid Build Coastguard Worker        True if success, False if times threshold reached
75*cfb92d14SAndroid Build Coastguard Worker
76*cfb92d14SAndroid Build Coastguard Worker    """
77*cfb92d14SAndroid Build Coastguard Worker    while times:
78*cfb92d14SAndroid Build Coastguard Worker        logger.info('Waiting times left %d', times)
79*cfb92d14SAndroid Build Coastguard Worker        try:
80*cfb92d14SAndroid Build Coastguard Worker            if what() is True:
81*cfb92d14SAndroid Build Coastguard Worker                return True
82*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
83*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Wait failed')
84*cfb92d14SAndroid Build Coastguard Worker        else:
85*cfb92d14SAndroid Build Coastguard Worker            logger.warning('Trial[%d] failed', times)
86*cfb92d14SAndroid Build Coastguard Worker        times -= 1
87*cfb92d14SAndroid Build Coastguard Worker        time.sleep(1)
88*cfb92d14SAndroid Build Coastguard Worker
89*cfb92d14SAndroid Build Coastguard Worker    return False
90*cfb92d14SAndroid Build Coastguard Worker
91*cfb92d14SAndroid Build Coastguard Worker
92*cfb92d14SAndroid Build Coastguard Workerclass HarnessCase(unittest.TestCase):
93*cfb92d14SAndroid Build Coastguard Worker    """This is the case class of all automation test cases.
94*cfb92d14SAndroid Build Coastguard Worker
95*cfb92d14SAndroid Build Coastguard Worker    All test case classes MUST define properties `role`, `case` and `golden_devices_required`
96*cfb92d14SAndroid Build Coastguard Worker    """
97*cfb92d14SAndroid Build Coastguard Worker
98*cfb92d14SAndroid Build Coastguard Worker    channel = settings.THREAD_CHANNEL
99*cfb92d14SAndroid Build Coastguard Worker    """int: Thread channel.
100*cfb92d14SAndroid Build Coastguard Worker
101*cfb92d14SAndroid Build Coastguard Worker    Thread channel ranges from 11 to 26.
102*cfb92d14SAndroid Build Coastguard Worker    """
103*cfb92d14SAndroid Build Coastguard Worker
104*cfb92d14SAndroid Build Coastguard Worker    ROLE_LEADER = 1
105*cfb92d14SAndroid Build Coastguard Worker    ROLE_ROUTER = 2
106*cfb92d14SAndroid Build Coastguard Worker    ROLE_SED = 4
107*cfb92d14SAndroid Build Coastguard Worker    ROLE_BORDER = 8
108*cfb92d14SAndroid Build Coastguard Worker    ROLE_REED = 16
109*cfb92d14SAndroid Build Coastguard Worker    ROLE_ED = 32
110*cfb92d14SAndroid Build Coastguard Worker    ROLE_COMMISSIONER = 64
111*cfb92d14SAndroid Build Coastguard Worker    ROLE_JOINER = 128
112*cfb92d14SAndroid Build Coastguard Worker    ROLE_FED = 512
113*cfb92d14SAndroid Build Coastguard Worker    ROLE_MED = 1024
114*cfb92d14SAndroid Build Coastguard Worker
115*cfb92d14SAndroid Build Coastguard Worker    role = None
116*cfb92d14SAndroid Build Coastguard Worker    """int: role id.
117*cfb92d14SAndroid Build Coastguard Worker
118*cfb92d14SAndroid Build Coastguard Worker    1
119*cfb92d14SAndroid Build Coastguard Worker        Leader
120*cfb92d14SAndroid Build Coastguard Worker    2
121*cfb92d14SAndroid Build Coastguard Worker        Router
122*cfb92d14SAndroid Build Coastguard Worker    4
123*cfb92d14SAndroid Build Coastguard Worker        Sleepy end device
124*cfb92d14SAndroid Build Coastguard Worker    16
125*cfb92d14SAndroid Build Coastguard Worker        Router eligible end device
126*cfb92d14SAndroid Build Coastguard Worker    32
127*cfb92d14SAndroid Build Coastguard Worker        End device
128*cfb92d14SAndroid Build Coastguard Worker    64
129*cfb92d14SAndroid Build Coastguard Worker        Commissioner
130*cfb92d14SAndroid Build Coastguard Worker    128
131*cfb92d14SAndroid Build Coastguard Worker        Joiner
132*cfb92d14SAndroid Build Coastguard Worker    512
133*cfb92d14SAndroid Build Coastguard Worker        Full end device
134*cfb92d14SAndroid Build Coastguard Worker    1024
135*cfb92d14SAndroid Build Coastguard Worker        Minimal end device
136*cfb92d14SAndroid Build Coastguard Worker    """
137*cfb92d14SAndroid Build Coastguard Worker
138*cfb92d14SAndroid Build Coastguard Worker    case = None
139*cfb92d14SAndroid Build Coastguard Worker    """str: Case id, e.g. '6 5 1'.
140*cfb92d14SAndroid Build Coastguard Worker    """
141*cfb92d14SAndroid Build Coastguard Worker
142*cfb92d14SAndroid Build Coastguard Worker    golden_devices_required = 0
143*cfb92d14SAndroid Build Coastguard Worker    """int: Golden devices needed to finish the test
144*cfb92d14SAndroid Build Coastguard Worker    """
145*cfb92d14SAndroid Build Coastguard Worker
146*cfb92d14SAndroid Build Coastguard Worker    child_timeout = settings.THREAD_CHILD_TIMEOUT
147*cfb92d14SAndroid Build Coastguard Worker    """int: Child timeout in seconds
148*cfb92d14SAndroid Build Coastguard Worker    """
149*cfb92d14SAndroid Build Coastguard Worker
150*cfb92d14SAndroid Build Coastguard Worker    sed_polling_interval = settings.THREAD_SED_POLLING_INTERVAL
151*cfb92d14SAndroid Build Coastguard Worker    """int: SED polling interval in seconds
152*cfb92d14SAndroid Build Coastguard Worker    """
153*cfb92d14SAndroid Build Coastguard Worker
154*cfb92d14SAndroid Build Coastguard Worker    auto_dut = settings.AUTO_DUT
155*cfb92d14SAndroid Build Coastguard Worker    """bool: whether use harness auto dut feature"""
156*cfb92d14SAndroid Build Coastguard Worker
157*cfb92d14SAndroid Build Coastguard Worker    timeout = hasattr(settings, 'TIMEOUT') and settings.TIMEOUT or DEFAULT_TIMEOUT
158*cfb92d14SAndroid Build Coastguard Worker    """number: timeout in seconds to stop running this test case"""
159*cfb92d14SAndroid Build Coastguard Worker
160*cfb92d14SAndroid Build Coastguard Worker    started = 0
161*cfb92d14SAndroid Build Coastguard Worker    """number: test case started timestamp"""
162*cfb92d14SAndroid Build Coastguard Worker
163*cfb92d14SAndroid Build Coastguard Worker    case_need_shield = False
164*cfb92d14SAndroid Build Coastguard Worker    """bool: whether needs RF-box"""
165*cfb92d14SAndroid Build Coastguard Worker
166*cfb92d14SAndroid Build Coastguard Worker    device_order = []
167*cfb92d14SAndroid Build Coastguard Worker    """list: device drag order in TestHarness TestBed page"""
168*cfb92d14SAndroid Build Coastguard Worker
169*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, *args, **kwargs):
170*cfb92d14SAndroid Build Coastguard Worker        self.dut = None
171*cfb92d14SAndroid Build Coastguard Worker        self._browser = None
172*cfb92d14SAndroid Build Coastguard Worker        self._hc = None
173*cfb92d14SAndroid Build Coastguard Worker        self.result_dir = '%s\\%s' % (settings.OUTPUT_PATH, self.__class__.__name__)
174*cfb92d14SAndroid Build Coastguard Worker        self.history = HistoryHelper()
175*cfb92d14SAndroid Build Coastguard Worker        self.add_all_devices = False
176*cfb92d14SAndroid Build Coastguard Worker        self.new_th = False
177*cfb92d14SAndroid Build Coastguard Worker
178*cfb92d14SAndroid Build Coastguard Worker        harness_info = ConfigParser.ConfigParser()
179*cfb92d14SAndroid Build Coastguard Worker        harness_info.read('%s\\info.ini' % settings.HARNESS_HOME)
180*cfb92d14SAndroid Build Coastguard Worker        if harness_info.has_option('Thread_Harness_Info', 'Version') and harness_info.has_option(
181*cfb92d14SAndroid Build Coastguard Worker                'Thread_Harness_Info', 'Mode'):
182*cfb92d14SAndroid Build Coastguard Worker            harness_version = harness_info.get('Thread_Harness_Info', 'Version').rsplit(' ', 1)[1]
183*cfb92d14SAndroid Build Coastguard Worker            harness_mode = harness_info.get('Thread_Harness_Info', 'Mode')
184*cfb92d14SAndroid Build Coastguard Worker
185*cfb92d14SAndroid Build Coastguard Worker            if harness_mode == 'External' and harness_version > '1.4.0':
186*cfb92d14SAndroid Build Coastguard Worker                self.new_th = True
187*cfb92d14SAndroid Build Coastguard Worker
188*cfb92d14SAndroid Build Coastguard Worker            if harness_mode == 'Internal' and harness_version > '49.4':
189*cfb92d14SAndroid Build Coastguard Worker                self.new_th = True
190*cfb92d14SAndroid Build Coastguard Worker
191*cfb92d14SAndroid Build Coastguard Worker        super(HarnessCase, self).__init__(*args, **kwargs)
192*cfb92d14SAndroid Build Coastguard Worker
193*cfb92d14SAndroid Build Coastguard Worker    def _init_devices(self):
194*cfb92d14SAndroid Build Coastguard Worker        """Reboot all usb devices.
195*cfb92d14SAndroid Build Coastguard Worker
196*cfb92d14SAndroid Build Coastguard Worker        Note:
197*cfb92d14SAndroid Build Coastguard Worker            If PDU_CONTROLLER_TYPE is not valid, usb devices is not rebooted.
198*cfb92d14SAndroid Build Coastguard Worker        """
199*cfb92d14SAndroid Build Coastguard Worker        if not settings.PDU_CONTROLLER_TYPE:
200*cfb92d14SAndroid Build Coastguard Worker            if settings.AUTO_DUT:
201*cfb92d14SAndroid Build Coastguard Worker                return
202*cfb92d14SAndroid Build Coastguard Worker
203*cfb92d14SAndroid Build Coastguard Worker            for device in settings.GOLDEN_DEVICES:
204*cfb92d14SAndroid Build Coastguard Worker                port, _ = device
205*cfb92d14SAndroid Build Coastguard Worker                try:
206*cfb92d14SAndroid Build Coastguard Worker                    with OpenThreadController(port) as otc:
207*cfb92d14SAndroid Build Coastguard Worker                        logger.info('Resetting %s', port)
208*cfb92d14SAndroid Build Coastguard Worker                        otc.reset()
209*cfb92d14SAndroid Build Coastguard Worker                except BaseException:
210*cfb92d14SAndroid Build Coastguard Worker                    logger.exception('Failed to reset device %s', port)
211*cfb92d14SAndroid Build Coastguard Worker                    self.history.mark_bad_golden_device(device)
212*cfb92d14SAndroid Build Coastguard Worker
213*cfb92d14SAndroid Build Coastguard Worker            return
214*cfb92d14SAndroid Build Coastguard Worker
215*cfb92d14SAndroid Build Coastguard Worker        tries = 3
216*cfb92d14SAndroid Build Coastguard Worker        pdu_factory = PduControllerFactory()
217*cfb92d14SAndroid Build Coastguard Worker
218*cfb92d14SAndroid Build Coastguard Worker        while True:
219*cfb92d14SAndroid Build Coastguard Worker            try:
220*cfb92d14SAndroid Build Coastguard Worker                pdu = pdu_factory.create_pdu_controller(settings.PDU_CONTROLLER_TYPE)
221*cfb92d14SAndroid Build Coastguard Worker                pdu.open(**settings.PDU_CONTROLLER_OPEN_PARAMS)
222*cfb92d14SAndroid Build Coastguard Worker            except EOFError:
223*cfb92d14SAndroid Build Coastguard Worker                logger.warning('Failed to connect to telnet')
224*cfb92d14SAndroid Build Coastguard Worker                tries = tries - 1
225*cfb92d14SAndroid Build Coastguard Worker                if tries:
226*cfb92d14SAndroid Build Coastguard Worker                    time.sleep(10)
227*cfb92d14SAndroid Build Coastguard Worker                    continue
228*cfb92d14SAndroid Build Coastguard Worker                else:
229*cfb92d14SAndroid Build Coastguard Worker                    logger.error('Fatal error: cannot connect to apc')
230*cfb92d14SAndroid Build Coastguard Worker                    raise
231*cfb92d14SAndroid Build Coastguard Worker            else:
232*cfb92d14SAndroid Build Coastguard Worker                pdu.reboot(**settings.PDU_CONTROLLER_REBOOT_PARAMS)
233*cfb92d14SAndroid Build Coastguard Worker                pdu.close()
234*cfb92d14SAndroid Build Coastguard Worker                break
235*cfb92d14SAndroid Build Coastguard Worker
236*cfb92d14SAndroid Build Coastguard Worker        time.sleep(len(settings.GOLDEN_DEVICES))
237*cfb92d14SAndroid Build Coastguard Worker
238*cfb92d14SAndroid Build Coastguard Worker    def _init_harness(self):
239*cfb92d14SAndroid Build Coastguard Worker        """Restart harness backend service.
240*cfb92d14SAndroid Build Coastguard Worker
241*cfb92d14SAndroid Build Coastguard Worker        Please start the harness controller before running the cases, otherwise, nothing happens
242*cfb92d14SAndroid Build Coastguard Worker        """
243*cfb92d14SAndroid Build Coastguard Worker        self._hc = HarnessController(self.result_dir)
244*cfb92d14SAndroid Build Coastguard Worker        self._hc.stop()
245*cfb92d14SAndroid Build Coastguard Worker        time.sleep(1)
246*cfb92d14SAndroid Build Coastguard Worker        self._hc.start()
247*cfb92d14SAndroid Build Coastguard Worker        time.sleep(2)
248*cfb92d14SAndroid Build Coastguard Worker
249*cfb92d14SAndroid Build Coastguard Worker        harness_config = ConfigParser.ConfigParser()
250*cfb92d14SAndroid Build Coastguard Worker        harness_config.read('%s\\Config\\Configuration.ini' % settings.HARNESS_HOME)
251*cfb92d14SAndroid Build Coastguard Worker        if harness_config.has_option('THREAD_HARNESS_CONFIG', 'BrowserAutoNavigate') and harness_config.getboolean(
252*cfb92d14SAndroid Build Coastguard Worker                'THREAD_HARNESS_CONFIG', 'BrowserAutoNavigate'):
253*cfb92d14SAndroid Build Coastguard Worker            logger.error('BrowserAutoNavigate in Configuration.ini should be False')
254*cfb92d14SAndroid Build Coastguard Worker            raise FailError('BrowserAutoNavigate in Configuration.ini should be False')
255*cfb92d14SAndroid Build Coastguard Worker        if settings.MIXED_DEVICE_TYPE:
256*cfb92d14SAndroid Build Coastguard Worker            if harness_config.has_option('THREAD_HARNESS_CONFIG',
257*cfb92d14SAndroid Build Coastguard Worker                                         'EnableDeviceSelection') and not harness_config.getboolean(
258*cfb92d14SAndroid Build Coastguard Worker                                             'THREAD_HARNESS_CONFIG', 'EnableDeviceSelection'):
259*cfb92d14SAndroid Build Coastguard Worker                logger.error('EnableDeviceSelection in Configuration.ini should be True')
260*cfb92d14SAndroid Build Coastguard Worker                raise FailError('EnableDeviceSelection in Configuration.ini should be True')
261*cfb92d14SAndroid Build Coastguard Worker
262*cfb92d14SAndroid Build Coastguard Worker    def _destroy_harness(self):
263*cfb92d14SAndroid Build Coastguard Worker        """Stop harness backend service
264*cfb92d14SAndroid Build Coastguard Worker
265*cfb92d14SAndroid Build Coastguard Worker        Stop harness service.
266*cfb92d14SAndroid Build Coastguard Worker        """
267*cfb92d14SAndroid Build Coastguard Worker        self._hc.stop()
268*cfb92d14SAndroid Build Coastguard Worker        time.sleep(2)
269*cfb92d14SAndroid Build Coastguard Worker
270*cfb92d14SAndroid Build Coastguard Worker    def _init_dut(self):
271*cfb92d14SAndroid Build Coastguard Worker        """Initialize the DUT.
272*cfb92d14SAndroid Build Coastguard Worker
273*cfb92d14SAndroid Build Coastguard Worker        DUT will be restarted. and openthread will started.
274*cfb92d14SAndroid Build Coastguard Worker        """
275*cfb92d14SAndroid Build Coastguard Worker        if self.auto_dut:
276*cfb92d14SAndroid Build Coastguard Worker            self.dut = None
277*cfb92d14SAndroid Build Coastguard Worker            return
278*cfb92d14SAndroid Build Coastguard Worker
279*cfb92d14SAndroid Build Coastguard Worker        dut_port = settings.DUT_DEVICE[0]
280*cfb92d14SAndroid Build Coastguard Worker        dut = OpenThreadController(dut_port)
281*cfb92d14SAndroid Build Coastguard Worker        self.dut = dut
282*cfb92d14SAndroid Build Coastguard Worker
283*cfb92d14SAndroid Build Coastguard Worker    def _destroy_dut(self):
284*cfb92d14SAndroid Build Coastguard Worker        self.dut = None
285*cfb92d14SAndroid Build Coastguard Worker
286*cfb92d14SAndroid Build Coastguard Worker    def _init_browser(self):
287*cfb92d14SAndroid Build Coastguard Worker        """Open harness web page.
288*cfb92d14SAndroid Build Coastguard Worker
289*cfb92d14SAndroid Build Coastguard Worker        Open a quiet chrome which:
290*cfb92d14SAndroid Build Coastguard Worker        1. disables extensions,
291*cfb92d14SAndroid Build Coastguard Worker        2. ignore certificate errors and
292*cfb92d14SAndroid Build Coastguard Worker        3. always allow notifications.
293*cfb92d14SAndroid Build Coastguard Worker        """
294*cfb92d14SAndroid Build Coastguard Worker        try:
295*cfb92d14SAndroid Build Coastguard Worker            chrome_options = webdriver.ChromeOptions()
296*cfb92d14SAndroid Build Coastguard Worker            chrome_options.add_argument('--disable-extensions')
297*cfb92d14SAndroid Build Coastguard Worker            chrome_options.add_argument('--disable-infobars')
298*cfb92d14SAndroid Build Coastguard Worker            chrome_options.add_argument('--ignore-certificate-errors')
299*cfb92d14SAndroid Build Coastguard Worker            chrome_options.add_experimental_option('prefs',
300*cfb92d14SAndroid Build Coastguard Worker                                                   {'profile.managed_default_content_settings.notifications': 1})
301*cfb92d14SAndroid Build Coastguard Worker
302*cfb92d14SAndroid Build Coastguard Worker            browser = webdriver.Chrome(chrome_options=chrome_options)
303*cfb92d14SAndroid Build Coastguard Worker            browser.set_page_load_timeout(20)
304*cfb92d14SAndroid Build Coastguard Worker            browser.implicitly_wait(1)
305*cfb92d14SAndroid Build Coastguard Worker            browser.get(settings.HARNESS_URL)
306*cfb92d14SAndroid Build Coastguard Worker            browser.maximize_window()
307*cfb92d14SAndroid Build Coastguard Worker            self._browser = browser
308*cfb92d14SAndroid Build Coastguard Worker            if not wait_until(lambda: 'Thread' in browser.title, 30):
309*cfb92d14SAndroid Build Coastguard Worker                self.assertIn('Thread', browser.title)
310*cfb92d14SAndroid Build Coastguard Worker            return True
311*cfb92d14SAndroid Build Coastguard Worker        except Exception as e:
312*cfb92d14SAndroid Build Coastguard Worker            logger.info('Init chrome error: {0}'.format(type(e).__name__))
313*cfb92d14SAndroid Build Coastguard Worker            return False
314*cfb92d14SAndroid Build Coastguard Worker
315*cfb92d14SAndroid Build Coastguard Worker    def _destroy_browser(self):
316*cfb92d14SAndroid Build Coastguard Worker        """Close the browser.
317*cfb92d14SAndroid Build Coastguard Worker        """
318*cfb92d14SAndroid Build Coastguard Worker        if self._browser:
319*cfb92d14SAndroid Build Coastguard Worker            self._browser.close()
320*cfb92d14SAndroid Build Coastguard Worker        self._browser = None
321*cfb92d14SAndroid Build Coastguard Worker
322*cfb92d14SAndroid Build Coastguard Worker    def _init_rf_shield(self):
323*cfb92d14SAndroid Build Coastguard Worker        if getattr(settings, 'SHIELD_CONTROLLER_TYPE', None) and getattr(settings, 'SHIELD_CONTROLLER_PARAMS', None):
324*cfb92d14SAndroid Build Coastguard Worker            self.rf_shield = get_rf_shield_controller(shield_type=settings.SHIELD_CONTROLLER_TYPE,
325*cfb92d14SAndroid Build Coastguard Worker                                                      params=settings.SHIELD_CONTROLLER_PARAMS)
326*cfb92d14SAndroid Build Coastguard Worker        else:
327*cfb92d14SAndroid Build Coastguard Worker            self.rf_shield = None
328*cfb92d14SAndroid Build Coastguard Worker
329*cfb92d14SAndroid Build Coastguard Worker    def _destroy_rf_shield(self):
330*cfb92d14SAndroid Build Coastguard Worker        self.rf_shield = None
331*cfb92d14SAndroid Build Coastguard Worker
332*cfb92d14SAndroid Build Coastguard Worker    def setUp(self):
333*cfb92d14SAndroid Build Coastguard Worker        """Prepare to run test case.
334*cfb92d14SAndroid Build Coastguard Worker
335*cfb92d14SAndroid Build Coastguard Worker        Start harness service, init golden devices, reset DUT and open browser.
336*cfb92d14SAndroid Build Coastguard Worker        """
337*cfb92d14SAndroid Build Coastguard Worker        if self.__class__ is HarnessCase:
338*cfb92d14SAndroid Build Coastguard Worker            return
339*cfb92d14SAndroid Build Coastguard Worker
340*cfb92d14SAndroid Build Coastguard Worker        logger.info('Setting up')
341*cfb92d14SAndroid Build Coastguard Worker        # clear files
342*cfb92d14SAndroid Build Coastguard Worker
343*cfb92d14SAndroid Build Coastguard Worker        logger.info('Deleting all .pcapng')
344*cfb92d14SAndroid Build Coastguard Worker        os.system('del /q "%s\\Captures\\*.pcapng"' % settings.HARNESS_HOME)
345*cfb92d14SAndroid Build Coastguard Worker        logger.info('Empty files in Logs')
346*cfb92d14SAndroid Build Coastguard Worker        os.system('del /q "%s\\Logs\\*.*"' % settings.HARNESS_HOME)
347*cfb92d14SAndroid Build Coastguard Worker
348*cfb92d14SAndroid Build Coastguard Worker        # using temp files to fix excel downloading fail
349*cfb92d14SAndroid Build Coastguard Worker        if self.new_th:
350*cfb92d14SAndroid Build Coastguard Worker            logger.info('Empty files in Reports')
351*cfb92d14SAndroid Build Coastguard Worker            os.system('del /q "%s\\Reports\\*.*"' % settings.HARNESS_HOME)
352*cfb92d14SAndroid Build Coastguard Worker        else:
353*cfb92d14SAndroid Build Coastguard Worker            logger.info('Empty files in temps')
354*cfb92d14SAndroid Build Coastguard Worker            os.system('del /q "%s\\Thread_Harness\\temp\\*.*"' % settings.HARNESS_HOME)
355*cfb92d14SAndroid Build Coastguard Worker
356*cfb92d14SAndroid Build Coastguard Worker        # create directory
357*cfb92d14SAndroid Build Coastguard Worker        os.system('mkdir %s' % self.result_dir)
358*cfb92d14SAndroid Build Coastguard Worker        self._init_harness()
359*cfb92d14SAndroid Build Coastguard Worker        self._init_devices()
360*cfb92d14SAndroid Build Coastguard Worker        self._init_dut()
361*cfb92d14SAndroid Build Coastguard Worker        self._init_rf_shield()
362*cfb92d14SAndroid Build Coastguard Worker
363*cfb92d14SAndroid Build Coastguard Worker    def tearDown(self):
364*cfb92d14SAndroid Build Coastguard Worker        """Clean up after each case.
365*cfb92d14SAndroid Build Coastguard Worker
366*cfb92d14SAndroid Build Coastguard Worker        Stop harness service, close browser and close DUT.
367*cfb92d14SAndroid Build Coastguard Worker        """
368*cfb92d14SAndroid Build Coastguard Worker        if self.__class__ is HarnessCase:
369*cfb92d14SAndroid Build Coastguard Worker            return
370*cfb92d14SAndroid Build Coastguard Worker
371*cfb92d14SAndroid Build Coastguard Worker        logger.info('Tearing down')
372*cfb92d14SAndroid Build Coastguard Worker        self._destroy_harness()
373*cfb92d14SAndroid Build Coastguard Worker        self._destroy_browser()
374*cfb92d14SAndroid Build Coastguard Worker        self._destroy_dut()
375*cfb92d14SAndroid Build Coastguard Worker        self._destroy_rf_shield()
376*cfb92d14SAndroid Build Coastguard Worker
377*cfb92d14SAndroid Build Coastguard Worker    def _setup_page(self):
378*cfb92d14SAndroid Build Coastguard Worker        """Do sniffer settings and general settings
379*cfb92d14SAndroid Build Coastguard Worker        """
380*cfb92d14SAndroid Build Coastguard Worker        if not self.started:
381*cfb92d14SAndroid Build Coastguard Worker            self.started = time.time()
382*cfb92d14SAndroid Build Coastguard Worker
383*cfb92d14SAndroid Build Coastguard Worker        # Detect Sniffer
384*cfb92d14SAndroid Build Coastguard Worker        try:
385*cfb92d14SAndroid Build Coastguard Worker            dialog = self._browser.find_element_by_id('capture-Setup-modal')
386*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
387*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Failed to get dialog.')
388*cfb92d14SAndroid Build Coastguard Worker        else:
389*cfb92d14SAndroid Build Coastguard Worker            if dialog and dialog.get_attribute('aria-hidden') == 'false':
390*cfb92d14SAndroid Build Coastguard Worker                times = 100
391*cfb92d14SAndroid Build Coastguard Worker                while times:
392*cfb92d14SAndroid Build Coastguard Worker                    status = dialog.find_element_by_class_name('status-notify').text
393*cfb92d14SAndroid Build Coastguard Worker                    if 'Searching' in status:
394*cfb92d14SAndroid Build Coastguard Worker                        logger.info('Still detecting..')
395*cfb92d14SAndroid Build Coastguard Worker                    elif 'Not' in status:
396*cfb92d14SAndroid Build Coastguard Worker                        logger.warning('Sniffer device not verified!')
397*cfb92d14SAndroid Build Coastguard Worker                        button = dialog.find_element_by_id('snifferAutoDetectBtn')
398*cfb92d14SAndroid Build Coastguard Worker                        button.click()
399*cfb92d14SAndroid Build Coastguard Worker                    elif 'Verified' in status:
400*cfb92d14SAndroid Build Coastguard Worker                        logger.info('Verified!')
401*cfb92d14SAndroid Build Coastguard Worker                        button = dialog.find_element_by_id('saveCaptureSettings')
402*cfb92d14SAndroid Build Coastguard Worker                        button.click()
403*cfb92d14SAndroid Build Coastguard Worker                        break
404*cfb92d14SAndroid Build Coastguard Worker                    else:
405*cfb92d14SAndroid Build Coastguard Worker                        logger.warning('Unexpected sniffer verification status')
406*cfb92d14SAndroid Build Coastguard Worker
407*cfb92d14SAndroid Build Coastguard Worker                    times = times - 1
408*cfb92d14SAndroid Build Coastguard Worker                    time.sleep(1)
409*cfb92d14SAndroid Build Coastguard Worker
410*cfb92d14SAndroid Build Coastguard Worker                if not times:
411*cfb92d14SAndroid Build Coastguard Worker                    raise Exception('Unable to detect sniffer device')
412*cfb92d14SAndroid Build Coastguard Worker
413*cfb92d14SAndroid Build Coastguard Worker        time.sleep(1)
414*cfb92d14SAndroid Build Coastguard Worker
415*cfb92d14SAndroid Build Coastguard Worker        try:
416*cfb92d14SAndroid Build Coastguard Worker            skip_button = self._browser.find_element_by_id('SkipPrepareDevice')
417*cfb92d14SAndroid Build Coastguard Worker            if skip_button.is_enabled():
418*cfb92d14SAndroid Build Coastguard Worker                skip_button.click()
419*cfb92d14SAndroid Build Coastguard Worker                time.sleep(1)
420*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
421*cfb92d14SAndroid Build Coastguard Worker            logger.info('Still detecting sniffers')
422*cfb92d14SAndroid Build Coastguard Worker
423*cfb92d14SAndroid Build Coastguard Worker        try:
424*cfb92d14SAndroid Build Coastguard Worker            next_button = self._browser.find_element_by_id('nextButton')
425*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
426*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Failed to finish setup')
427*cfb92d14SAndroid Build Coastguard Worker            return
428*cfb92d14SAndroid Build Coastguard Worker
429*cfb92d14SAndroid Build Coastguard Worker        if not next_button.is_enabled():
430*cfb92d14SAndroid Build Coastguard Worker            logger.info('Harness is still not ready')
431*cfb92d14SAndroid Build Coastguard Worker            return
432*cfb92d14SAndroid Build Coastguard Worker
433*cfb92d14SAndroid Build Coastguard Worker        # General Setup
434*cfb92d14SAndroid Build Coastguard Worker        try:
435*cfb92d14SAndroid Build Coastguard Worker            if self.child_timeout or self.sed_polling_interval:
436*cfb92d14SAndroid Build Coastguard Worker                logger.info('finding general Setup button')
437*cfb92d14SAndroid Build Coastguard Worker                button = self._browser.find_element_by_id('general-Setup')
438*cfb92d14SAndroid Build Coastguard Worker                button.click()
439*cfb92d14SAndroid Build Coastguard Worker                time.sleep(2)
440*cfb92d14SAndroid Build Coastguard Worker
441*cfb92d14SAndroid Build Coastguard Worker                dialog = self._browser.find_element_by_id('general-Setup-modal')
442*cfb92d14SAndroid Build Coastguard Worker                if dialog.get_attribute('aria-hidden') != 'false':
443*cfb92d14SAndroid Build Coastguard Worker                    raise Exception('Missing General Setup dialog')
444*cfb92d14SAndroid Build Coastguard Worker
445*cfb92d14SAndroid Build Coastguard Worker                field = dialog.find_element_by_id('inp_general_child_update_wait_time')
446*cfb92d14SAndroid Build Coastguard Worker                field.clear()
447*cfb92d14SAndroid Build Coastguard Worker                if self.child_timeout:
448*cfb92d14SAndroid Build Coastguard Worker                    field.send_keys(str(self.child_timeout))
449*cfb92d14SAndroid Build Coastguard Worker
450*cfb92d14SAndroid Build Coastguard Worker                field = dialog.find_element_by_id('inp_general_sed_polling_rate')
451*cfb92d14SAndroid Build Coastguard Worker                field.clear()
452*cfb92d14SAndroid Build Coastguard Worker                if self.sed_polling_interval:
453*cfb92d14SAndroid Build Coastguard Worker                    field.send_keys(str(self.sed_polling_interval))
454*cfb92d14SAndroid Build Coastguard Worker
455*cfb92d14SAndroid Build Coastguard Worker                button = dialog.find_element_by_id('saveGeneralSettings')
456*cfb92d14SAndroid Build Coastguard Worker                button.click()
457*cfb92d14SAndroid Build Coastguard Worker                time.sleep(1)
458*cfb92d14SAndroid Build Coastguard Worker
459*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
460*cfb92d14SAndroid Build Coastguard Worker            logger.info('general setup exception')
461*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Failed to do general setup')
462*cfb92d14SAndroid Build Coastguard Worker            return
463*cfb92d14SAndroid Build Coastguard Worker
464*cfb92d14SAndroid Build Coastguard Worker        # Finish this page
465*cfb92d14SAndroid Build Coastguard Worker        next_button.click()
466*cfb92d14SAndroid Build Coastguard Worker        time.sleep(1)
467*cfb92d14SAndroid Build Coastguard Worker
468*cfb92d14SAndroid Build Coastguard Worker    def _connect_devices(self):
469*cfb92d14SAndroid Build Coastguard Worker        connect_all = self._browser.find_element_by_link_text('Connect All')
470*cfb92d14SAndroid Build Coastguard Worker        connect_all.click()
471*cfb92d14SAndroid Build Coastguard Worker
472*cfb92d14SAndroid Build Coastguard Worker    def _add_device(self, port, device_type_id):
473*cfb92d14SAndroid Build Coastguard Worker        browser = self._browser
474*cfb92d14SAndroid Build Coastguard Worker        test_bed = browser.find_element_by_id('test-bed')
475*cfb92d14SAndroid Build Coastguard Worker        device = browser.find_element_by_id(device_type_id)
476*cfb92d14SAndroid Build Coastguard Worker        # drag
477*cfb92d14SAndroid Build Coastguard Worker        action_chains = ActionChains(browser)
478*cfb92d14SAndroid Build Coastguard Worker        action_chains.click_and_hold(device)
479*cfb92d14SAndroid Build Coastguard Worker        action_chains.move_to_element(test_bed).perform()
480*cfb92d14SAndroid Build Coastguard Worker        time.sleep(1)
481*cfb92d14SAndroid Build Coastguard Worker
482*cfb92d14SAndroid Build Coastguard Worker        # drop
483*cfb92d14SAndroid Build Coastguard Worker        drop_hw = browser.find_element_by_class_name('drop-hw')
484*cfb92d14SAndroid Build Coastguard Worker        action_chains = ActionChains(browser)
485*cfb92d14SAndroid Build Coastguard Worker        action_chains.move_to_element(drop_hw)
486*cfb92d14SAndroid Build Coastguard Worker        action_chains.release(drop_hw).perform()
487*cfb92d14SAndroid Build Coastguard Worker
488*cfb92d14SAndroid Build Coastguard Worker        time.sleep(0.5)
489*cfb92d14SAndroid Build Coastguard Worker        selected_hw = browser.find_element_by_class_name('selected-hw')
490*cfb92d14SAndroid Build Coastguard Worker        form_inputs = selected_hw.find_elements_by_tag_name('input')
491*cfb92d14SAndroid Build Coastguard Worker        form_port = form_inputs[0]
492*cfb92d14SAndroid Build Coastguard Worker        form_port.clear()
493*cfb92d14SAndroid Build Coastguard Worker        form_port.send_keys(port)
494*cfb92d14SAndroid Build Coastguard Worker
495*cfb92d14SAndroid Build Coastguard Worker    def _test_bed(self):
496*cfb92d14SAndroid Build Coastguard Worker        """Set up the test bed.
497*cfb92d14SAndroid Build Coastguard Worker
498*cfb92d14SAndroid Build Coastguard Worker        Connect number of golden devices required by each case.
499*cfb92d14SAndroid Build Coastguard Worker        """
500*cfb92d14SAndroid Build Coastguard Worker        browser = self._browser
501*cfb92d14SAndroid Build Coastguard Worker        test_bed = browser.find_element_by_id('test-bed')
502*cfb92d14SAndroid Build Coastguard Worker        time.sleep(3)
503*cfb92d14SAndroid Build Coastguard Worker        selected_hw_set = test_bed.find_elements_by_class_name('selected-hw')
504*cfb92d14SAndroid Build Coastguard Worker        selected_hw_num = len(selected_hw_set)
505*cfb92d14SAndroid Build Coastguard Worker
506*cfb92d14SAndroid Build Coastguard Worker        while selected_hw_num:
507*cfb92d14SAndroid Build Coastguard Worker            remove_button = selected_hw_set[selected_hw_num - 1].find_element_by_class_name('removeSelectedDevice')
508*cfb92d14SAndroid Build Coastguard Worker            remove_button.click()
509*cfb92d14SAndroid Build Coastguard Worker            selected_hw_num = selected_hw_num - 1
510*cfb92d14SAndroid Build Coastguard Worker
511*cfb92d14SAndroid Build Coastguard Worker        devices = [
512*cfb92d14SAndroid Build Coastguard Worker            device for device in settings.GOLDEN_DEVICES if not self.history.is_bad_golden_device(device[0]) and
513*cfb92d14SAndroid Build Coastguard Worker            not (settings.DUT_DEVICE and device[0] == settings.DUT_DEVICE[0])
514*cfb92d14SAndroid Build Coastguard Worker        ]
515*cfb92d14SAndroid Build Coastguard Worker        logger.info('Available golden devices: %s', json.dumps(devices, indent=2))
516*cfb92d14SAndroid Build Coastguard Worker
517*cfb92d14SAndroid Build Coastguard Worker        shield_devices = [
518*cfb92d14SAndroid Build Coastguard Worker            shield_device for shield_device in settings.SHIELD_GOLDEN_DEVICES
519*cfb92d14SAndroid Build Coastguard Worker            if not self.history.is_bad_golden_device(shield_device[0]) and
520*cfb92d14SAndroid Build Coastguard Worker            not (settings.DUT2_DEVICE and shield_device[0] == settings.DUT2_DEVICE[0])
521*cfb92d14SAndroid Build Coastguard Worker        ]
522*cfb92d14SAndroid Build Coastguard Worker        logger.info('Available shield golden devices: %s', json.dumps(shield_devices, indent=2))
523*cfb92d14SAndroid Build Coastguard Worker        golden_devices_required = self.golden_devices_required
524*cfb92d14SAndroid Build Coastguard Worker
525*cfb92d14SAndroid Build Coastguard Worker        dut_device = ()
526*cfb92d14SAndroid Build Coastguard Worker        if settings.DUT_DEVICE:
527*cfb92d14SAndroid Build Coastguard Worker            dut_device = settings.DUT_DEVICE
528*cfb92d14SAndroid Build Coastguard Worker        """check if test case needs to use RF-shield box and its device order in Testbed page
529*cfb92d14SAndroid Build Coastguard Worker        Two parameters case_need_shield & device_order should be set in the case script
530*cfb92d14SAndroid Build Coastguard Worker        according to the requires: https://openthread.io/certification/test-cases#rf_shielding
531*cfb92d14SAndroid Build Coastguard Worker        Example:
532*cfb92d14SAndroid Build Coastguard Worker         In case script leader_9_2_9.py:
533*cfb92d14SAndroid Build Coastguard Worker          case_need_shield = True
534*cfb92d14SAndroid Build Coastguard Worker          device_order = [('Router_2', False), ('Commissioner', True), ('Router_1', False), ('DUT', True)]
535*cfb92d14SAndroid Build Coastguard Worker         On the TestBed page of the Test Harness, the device sort order for Leader_9_2_9
536*cfb92d14SAndroid Build Coastguard Worker           should be like:
537*cfb92d14SAndroid Build Coastguard Worker             Router_2
538*cfb92d14SAndroid Build Coastguard Worker             Commissioner
539*cfb92d14SAndroid Build Coastguard Worker             Router_1
540*cfb92d14SAndroid Build Coastguard Worker             DUT
541*cfb92d14SAndroid Build Coastguard Worker           The ('Commissioner', True) and ('DUT', True) indicate Commissioner device and DUT2 device should
542*cfb92d14SAndroid Build Coastguard Worker           be in the RF-box and choose from SHIELD_GOLDEN_DEVICES and DUT2_DEVICE. Otherwise ('DUT', False) means
543*cfb92d14SAndroid Build Coastguard Worker           DUT device is not in RF-box and use DUT_DEVICE. The other roles devices with False should be selected
544*cfb92d14SAndroid Build Coastguard Worker           from GOLDEN_DEVICES.
545*cfb92d14SAndroid Build Coastguard Worker
546*cfb92d14SAndroid Build Coastguard Worker         In case script med_6_3_2.py:
547*cfb92d14SAndroid Build Coastguard Worker         case_need_shield = True
548*cfb92d14SAndroid Build Coastguard Worker         device_order = [] # or not defined
549*cfb92d14SAndroid Build Coastguard Worker         means no device drag order. DUT2_DEVICE should be applied as DUT and the other golden devices
550*cfb92d14SAndroid Build Coastguard Worker         are from GOLDEN_DEVICES.
551*cfb92d14SAndroid Build Coastguard Worker        """
552*cfb92d14SAndroid Build Coastguard Worker        if self.case_need_shield:
553*cfb92d14SAndroid Build Coastguard Worker            if not settings.DUT2_DEVICE:
554*cfb92d14SAndroid Build Coastguard Worker                logger.info('Must set DUT2_DEVICE')
555*cfb92d14SAndroid Build Coastguard Worker                raise FailError('DUT2_DEVICE must be set in settings.py')
556*cfb92d14SAndroid Build Coastguard Worker            if isinstance(self.device_order, list) and self.device_order:
557*cfb92d14SAndroid Build Coastguard Worker                logger.info('case %s devices ordered by %s ', self.case, self.device_order)
558*cfb92d14SAndroid Build Coastguard Worker            else:
559*cfb92d14SAndroid Build Coastguard Worker                logger.info('case %s uses %s as DUT', self.case, settings.DUT2_DEVICE)
560*cfb92d14SAndroid Build Coastguard Worker
561*cfb92d14SAndroid Build Coastguard Worker        # for test bed with multi-vendor devices
562*cfb92d14SAndroid Build Coastguard Worker        if settings.MIXED_DEVICE_TYPE:
563*cfb92d14SAndroid Build Coastguard Worker            topo_file = settings.HARNESS_HOME + "\\Thread_Harness\\TestScripts\\TopologyConfig.txt"
564*cfb92d14SAndroid Build Coastguard Worker            try:
565*cfb92d14SAndroid Build Coastguard Worker                f_topo = open(topo_file, 'r')
566*cfb92d14SAndroid Build Coastguard Worker            except IOError:
567*cfb92d14SAndroid Build Coastguard Worker                logger.info('%s can NOT be found', topo_file)
568*cfb92d14SAndroid Build Coastguard Worker                raise GoldenDeviceNotEnoughError()
569*cfb92d14SAndroid Build Coastguard Worker            topo_mixed_devices = []
570*cfb92d14SAndroid Build Coastguard Worker            try:
571*cfb92d14SAndroid Build Coastguard Worker                while True:
572*cfb92d14SAndroid Build Coastguard Worker                    topo_line = f_topo.readline().strip()
573*cfb92d14SAndroid Build Coastguard Worker                    if re.match(r'#.*', topo_line):
574*cfb92d14SAndroid Build Coastguard Worker                        continue
575*cfb92d14SAndroid Build Coastguard Worker                    match_line = re.match(r'(.*)-(.*)', topo_line, re.M | re.I)
576*cfb92d14SAndroid Build Coastguard Worker                    if not match_line:
577*cfb92d14SAndroid Build Coastguard Worker                        continue
578*cfb92d14SAndroid Build Coastguard Worker                    case_id = match_line.group(1)
579*cfb92d14SAndroid Build Coastguard Worker
580*cfb92d14SAndroid Build Coastguard Worker                    if re.sub(r'\.', ' ', case_id) == self.case:
581*cfb92d14SAndroid Build Coastguard Worker                        logger.info('Get line by case %s: %s', case_id, topo_line)
582*cfb92d14SAndroid Build Coastguard Worker                        topo_device_list = re.split(',', match_line.group(2))
583*cfb92d14SAndroid Build Coastguard Worker                        for i in range(len(topo_device_list)):
584*cfb92d14SAndroid Build Coastguard Worker                            topo_device = re.split(':', topo_device_list[i])
585*cfb92d14SAndroid Build Coastguard Worker                            topo_mixed_devices.append(tuple(topo_device))
586*cfb92d14SAndroid Build Coastguard Worker                        break
587*cfb92d14SAndroid Build Coastguard Worker                    else:
588*cfb92d14SAndroid Build Coastguard Worker                        continue
589*cfb92d14SAndroid Build Coastguard Worker            except Exception as e:
590*cfb92d14SAndroid Build Coastguard Worker                logger.info('Get devices from topology config file error: %s', e)
591*cfb92d14SAndroid Build Coastguard Worker                raise GoldenDeviceNotEnoughError()
592*cfb92d14SAndroid Build Coastguard Worker            logger.info('Golden devices in topology config file for case %s: %s', case_id, topo_mixed_devices)
593*cfb92d14SAndroid Build Coastguard Worker            f_topo.close()
594*cfb92d14SAndroid Build Coastguard Worker            golden_device_candidates = []
595*cfb92d14SAndroid Build Coastguard Worker            missing_golden_devices = topo_mixed_devices[:]
596*cfb92d14SAndroid Build Coastguard Worker
597*cfb92d14SAndroid Build Coastguard Worker            # mapping topology config devices with golden devices by device order
598*cfb92d14SAndroid Build Coastguard Worker            if self.case_need_shield and self.device_order:
599*cfb92d14SAndroid Build Coastguard Worker                matched_dut = False
600*cfb92d14SAndroid Build Coastguard Worker                for device_order_item in self.device_order:
601*cfb92d14SAndroid Build Coastguard Worker                    matched = False
602*cfb92d14SAndroid Build Coastguard Worker                    for mixed_device_item in topo_mixed_devices:
603*cfb92d14SAndroid Build Coastguard Worker                        # mapping device in device_order which needs to be shielded
604*cfb92d14SAndroid Build Coastguard Worker                        if device_order_item[1]:
605*cfb92d14SAndroid Build Coastguard Worker                            if 'DUT' in device_order_item[0]:
606*cfb92d14SAndroid Build Coastguard Worker                                golden_device_candidates.append(settings.DUT2_DEVICE)
607*cfb92d14SAndroid Build Coastguard Worker                                dut_device = settings.DUT2_DEVICE
608*cfb92d14SAndroid Build Coastguard Worker                                matched_dut = True
609*cfb92d14SAndroid Build Coastguard Worker                                matched = True
610*cfb92d14SAndroid Build Coastguard Worker                                break
611*cfb92d14SAndroid Build Coastguard Worker                            for device_item in shield_devices:
612*cfb92d14SAndroid Build Coastguard Worker                                if (device_order_item[0] == mixed_device_item[0] and
613*cfb92d14SAndroid Build Coastguard Worker                                        mixed_device_item[1] == device_item[1]):
614*cfb92d14SAndroid Build Coastguard Worker                                    golden_device_candidates.append(device_item)
615*cfb92d14SAndroid Build Coastguard Worker                                    shield_devices.remove(device_item)
616*cfb92d14SAndroid Build Coastguard Worker                                    matched = True
617*cfb92d14SAndroid Build Coastguard Worker                                    break
618*cfb92d14SAndroid Build Coastguard Worker                        # mapping device in device_order which does not need to be shielded
619*cfb92d14SAndroid Build Coastguard Worker                        else:
620*cfb92d14SAndroid Build Coastguard Worker                            if 'DUT' in device_order_item[0]:
621*cfb92d14SAndroid Build Coastguard Worker                                golden_device_candidates.append(settings.DUT_DEVICE)
622*cfb92d14SAndroid Build Coastguard Worker                                matched_dut = True
623*cfb92d14SAndroid Build Coastguard Worker                                matched = True
624*cfb92d14SAndroid Build Coastguard Worker                                break
625*cfb92d14SAndroid Build Coastguard Worker                            for device_item in devices:
626*cfb92d14SAndroid Build Coastguard Worker                                if (device_order_item[0] == mixed_device_item[0] and
627*cfb92d14SAndroid Build Coastguard Worker                                        mixed_device_item[1] == device_item[1]):
628*cfb92d14SAndroid Build Coastguard Worker                                    golden_device_candidates.append(device_item)
629*cfb92d14SAndroid Build Coastguard Worker                                    devices.remove(device_item)
630*cfb92d14SAndroid Build Coastguard Worker                                    matched = True
631*cfb92d14SAndroid Build Coastguard Worker                                    break
632*cfb92d14SAndroid Build Coastguard Worker                    if not matched:
633*cfb92d14SAndroid Build Coastguard Worker                        logger.info('Golden device not enough in : no %s', device_order_item)
634*cfb92d14SAndroid Build Coastguard Worker                        raise GoldenDeviceNotEnoughError()
635*cfb92d14SAndroid Build Coastguard Worker                if not matched_dut:
636*cfb92d14SAndroid Build Coastguard Worker                    raise FailError('Failed to find DUT in device_order')
637*cfb92d14SAndroid Build Coastguard Worker                devices = golden_device_candidates
638*cfb92d14SAndroid Build Coastguard Worker                self.add_all_devices = True
639*cfb92d14SAndroid Build Coastguard Worker            else:
640*cfb92d14SAndroid Build Coastguard Worker                for mixed_device_item in topo_mixed_devices:
641*cfb92d14SAndroid Build Coastguard Worker                    for device_item in devices:
642*cfb92d14SAndroid Build Coastguard Worker                        if mixed_device_item[1] == device_item[1]:
643*cfb92d14SAndroid Build Coastguard Worker                            golden_device_candidates.append(device_item)
644*cfb92d14SAndroid Build Coastguard Worker                            devices.remove(device_item)
645*cfb92d14SAndroid Build Coastguard Worker                            missing_golden_devices.remove(mixed_device_item)
646*cfb92d14SAndroid Build Coastguard Worker                            break
647*cfb92d14SAndroid Build Coastguard Worker                logger.info('Golden devices in topology config file mapped in settings : %s', golden_device_candidates)
648*cfb92d14SAndroid Build Coastguard Worker                if len(topo_mixed_devices) != len(golden_device_candidates):
649*cfb92d14SAndroid Build Coastguard Worker                    device_dict = dict()
650*cfb92d14SAndroid Build Coastguard Worker                    for missing_device in missing_golden_devices:
651*cfb92d14SAndroid Build Coastguard Worker                        if missing_device[1] in device_dict:
652*cfb92d14SAndroid Build Coastguard Worker                            device_dict[missing_device[1]] += 1
653*cfb92d14SAndroid Build Coastguard Worker                        else:
654*cfb92d14SAndroid Build Coastguard Worker                            device_dict[missing_device[1]] = 1
655*cfb92d14SAndroid Build Coastguard Worker                    logger.info('Missing Devices: %s', device_dict)
656*cfb92d14SAndroid Build Coastguard Worker                    raise GoldenDeviceNotEnoughError()
657*cfb92d14SAndroid Build Coastguard Worker                else:
658*cfb92d14SAndroid Build Coastguard Worker                    devices = golden_device_candidates
659*cfb92d14SAndroid Build Coastguard Worker                    golden_devices_required = len(devices)
660*cfb92d14SAndroid Build Coastguard Worker                    logger.info('All case-needed golden devices: %s', json.dumps(devices, indent=2))
661*cfb92d14SAndroid Build Coastguard Worker        # for test bed with single vendor devices
662*cfb92d14SAndroid Build Coastguard Worker        else:
663*cfb92d14SAndroid Build Coastguard Worker            golden_device_candidates = []
664*cfb92d14SAndroid Build Coastguard Worker            if self.case_need_shield and self.device_order:
665*cfb92d14SAndroid Build Coastguard Worker                matched_dut = False
666*cfb92d14SAndroid Build Coastguard Worker                for device_order_item in self.device_order:
667*cfb92d14SAndroid Build Coastguard Worker                    matched = False
668*cfb92d14SAndroid Build Coastguard Worker                    # choose device which needs to be shielded
669*cfb92d14SAndroid Build Coastguard Worker                    if device_order_item[1]:
670*cfb92d14SAndroid Build Coastguard Worker                        if 'DUT' in device_order_item[0]:
671*cfb92d14SAndroid Build Coastguard Worker                            golden_device_candidates.append(settings.DUT2_DEVICE)
672*cfb92d14SAndroid Build Coastguard Worker                            dut_device = settings.DUT2_DEVICE
673*cfb92d14SAndroid Build Coastguard Worker                            matched_dut = True
674*cfb92d14SAndroid Build Coastguard Worker                            matched = True
675*cfb92d14SAndroid Build Coastguard Worker                        else:
676*cfb92d14SAndroid Build Coastguard Worker                            for device_item in shield_devices:
677*cfb92d14SAndroid Build Coastguard Worker                                golden_device_candidates.append(device_item)
678*cfb92d14SAndroid Build Coastguard Worker                                shield_devices.remove(device_item)
679*cfb92d14SAndroid Build Coastguard Worker                                matched = True
680*cfb92d14SAndroid Build Coastguard Worker                                break
681*cfb92d14SAndroid Build Coastguard Worker                    # choose device which does not need to be shielded
682*cfb92d14SAndroid Build Coastguard Worker                    else:
683*cfb92d14SAndroid Build Coastguard Worker                        if 'DUT' in device_order_item[0]:
684*cfb92d14SAndroid Build Coastguard Worker                            golden_device_candidates.append(settings.DUT_DEVICE)
685*cfb92d14SAndroid Build Coastguard Worker                            matched_dut = True
686*cfb92d14SAndroid Build Coastguard Worker                            matched = True
687*cfb92d14SAndroid Build Coastguard Worker                        else:
688*cfb92d14SAndroid Build Coastguard Worker                            for device_item in devices:
689*cfb92d14SAndroid Build Coastguard Worker                                golden_device_candidates.append(device_item)
690*cfb92d14SAndroid Build Coastguard Worker                                devices.remove(device_item)
691*cfb92d14SAndroid Build Coastguard Worker                                matched = True
692*cfb92d14SAndroid Build Coastguard Worker                                break
693*cfb92d14SAndroid Build Coastguard Worker                    if not matched:
694*cfb92d14SAndroid Build Coastguard Worker                        logger.info('Golden device not enough in : no %s', device_order_item)
695*cfb92d14SAndroid Build Coastguard Worker                        raise GoldenDeviceNotEnoughError()
696*cfb92d14SAndroid Build Coastguard Worker                if not matched_dut:
697*cfb92d14SAndroid Build Coastguard Worker                    raise FailError('Failed to find DUT in device_order')
698*cfb92d14SAndroid Build Coastguard Worker                devices = golden_device_candidates
699*cfb92d14SAndroid Build Coastguard Worker                self.add_all_devices = True
700*cfb92d14SAndroid Build Coastguard Worker
701*cfb92d14SAndroid Build Coastguard Worker        if self.auto_dut and not settings.DUT_DEVICE:
702*cfb92d14SAndroid Build Coastguard Worker            if settings.MIXED_DEVICE_TYPE:
703*cfb92d14SAndroid Build Coastguard Worker                logger.info('Must set DUT_DEVICE')
704*cfb92d14SAndroid Build Coastguard Worker                raise FailError('DUT_DEVICE must be set for mixed testbed')
705*cfb92d14SAndroid Build Coastguard Worker            golden_devices_required += 1
706*cfb92d14SAndroid Build Coastguard Worker
707*cfb92d14SAndroid Build Coastguard Worker        if len(devices) < golden_devices_required:
708*cfb92d14SAndroid Build Coastguard Worker            raise GoldenDeviceNotEnoughError()
709*cfb92d14SAndroid Build Coastguard Worker
710*cfb92d14SAndroid Build Coastguard Worker        # add golden devices
711*cfb92d14SAndroid Build Coastguard Worker        number_of_devices_to_add = len(devices) if self.add_all_devices else golden_devices_required
712*cfb92d14SAndroid Build Coastguard Worker        for i in range(number_of_devices_to_add):
713*cfb92d14SAndroid Build Coastguard Worker            self._add_device(*devices.pop())
714*cfb92d14SAndroid Build Coastguard Worker
715*cfb92d14SAndroid Build Coastguard Worker        # add DUT
716*cfb92d14SAndroid Build Coastguard Worker        if self.case_need_shield:
717*cfb92d14SAndroid Build Coastguard Worker            if not self.device_order:
718*cfb92d14SAndroid Build Coastguard Worker                self._add_device(*settings.DUT2_DEVICE)
719*cfb92d14SAndroid Build Coastguard Worker        else:
720*cfb92d14SAndroid Build Coastguard Worker            if settings.DUT_DEVICE:
721*cfb92d14SAndroid Build Coastguard Worker                self._add_device(*settings.DUT_DEVICE)
722*cfb92d14SAndroid Build Coastguard Worker
723*cfb92d14SAndroid Build Coastguard Worker        # enable AUTO DUT
724*cfb92d14SAndroid Build Coastguard Worker        if self.auto_dut:
725*cfb92d14SAndroid Build Coastguard Worker            checkbox_auto_dut = browser.find_element_by_id('EnableAutoDutSelection')
726*cfb92d14SAndroid Build Coastguard Worker            if not checkbox_auto_dut.is_selected():
727*cfb92d14SAndroid Build Coastguard Worker                checkbox_auto_dut.click()
728*cfb92d14SAndroid Build Coastguard Worker                time.sleep(1)
729*cfb92d14SAndroid Build Coastguard Worker
730*cfb92d14SAndroid Build Coastguard Worker            if settings.DUT_DEVICE:
731*cfb92d14SAndroid Build Coastguard Worker                radio_auto_dut = browser.find_element_by_class_name('AutoDUT_RadBtns')
732*cfb92d14SAndroid Build Coastguard Worker                if not radio_auto_dut.is_selected() and not self.device_order:
733*cfb92d14SAndroid Build Coastguard Worker                    radio_auto_dut.click()
734*cfb92d14SAndroid Build Coastguard Worker
735*cfb92d14SAndroid Build Coastguard Worker                if self.device_order:
736*cfb92d14SAndroid Build Coastguard Worker                    selected_hw_set = test_bed.find_elements_by_class_name('selected-hw')
737*cfb92d14SAndroid Build Coastguard Worker                    for selected_hw in selected_hw_set:
738*cfb92d14SAndroid Build Coastguard Worker                        form_inputs = selected_hw.find_elements_by_tag_name('input')
739*cfb92d14SAndroid Build Coastguard Worker                        form_port = form_inputs[0]
740*cfb92d14SAndroid Build Coastguard Worker                        port = form_port.get_attribute('value').encode('utf8')
741*cfb92d14SAndroid Build Coastguard Worker                        if port == dut_device[0]:
742*cfb92d14SAndroid Build Coastguard Worker                            radio_auto_dut = selected_hw.find_element_by_class_name('AutoDUT_RadBtns')
743*cfb92d14SAndroid Build Coastguard Worker                            if not radio_auto_dut.is_selected():
744*cfb92d14SAndroid Build Coastguard Worker                                radio_auto_dut.click()
745*cfb92d14SAndroid Build Coastguard Worker
746*cfb92d14SAndroid Build Coastguard Worker        while True:
747*cfb92d14SAndroid Build Coastguard Worker            try:
748*cfb92d14SAndroid Build Coastguard Worker                self._connect_devices()
749*cfb92d14SAndroid Build Coastguard Worker                button_next = browser.find_element_by_id('nextBtn')
750*cfb92d14SAndroid Build Coastguard Worker                if not wait_until(
751*cfb92d14SAndroid Build Coastguard Worker                        lambda: 'disabled' not in button_next.get_attribute('class'),
752*cfb92d14SAndroid Build Coastguard Worker                        times=(30 + 4 * number_of_devices_to_add),
753*cfb92d14SAndroid Build Coastguard Worker                ):
754*cfb92d14SAndroid Build Coastguard Worker                    bad_ones = []
755*cfb92d14SAndroid Build Coastguard Worker                    selected_hw_set = test_bed.find_elements_by_class_name('selected-hw')
756*cfb92d14SAndroid Build Coastguard Worker                    for selected_hw in selected_hw_set:
757*cfb92d14SAndroid Build Coastguard Worker                        form_inputs = selected_hw.find_elements_by_tag_name('input')
758*cfb92d14SAndroid Build Coastguard Worker                        form_port = form_inputs[0]
759*cfb92d14SAndroid Build Coastguard Worker                        if form_port.is_enabled():
760*cfb92d14SAndroid Build Coastguard Worker                            bad_ones.append(selected_hw)
761*cfb92d14SAndroid Build Coastguard Worker
762*cfb92d14SAndroid Build Coastguard Worker                    for selected_hw in bad_ones:
763*cfb92d14SAndroid Build Coastguard Worker                        form_inputs = selected_hw.find_elements_by_tag_name('input')
764*cfb92d14SAndroid Build Coastguard Worker                        form_port = form_inputs[0]
765*cfb92d14SAndroid Build Coastguard Worker                        port = form_port.get_attribute('value').encode('utf8')
766*cfb92d14SAndroid Build Coastguard Worker                        if port == dut_device[0]:
767*cfb92d14SAndroid Build Coastguard Worker                            if settings.PDU_CONTROLLER_TYPE is None:
768*cfb92d14SAndroid Build Coastguard Worker                                # connection error cannot recover without power
769*cfb92d14SAndroid Build Coastguard Worker                                # cycling
770*cfb92d14SAndroid Build Coastguard Worker                                raise FatalError('Failed to connect to DUT')
771*cfb92d14SAndroid Build Coastguard Worker                            else:
772*cfb92d14SAndroid Build Coastguard Worker                                raise FailError('Failed to connect to DUT')
773*cfb92d14SAndroid Build Coastguard Worker
774*cfb92d14SAndroid Build Coastguard Worker                        if settings.PDU_CONTROLLER_TYPE is None:
775*cfb92d14SAndroid Build Coastguard Worker                            # port cannot recover without power cycling
776*cfb92d14SAndroid Build Coastguard Worker                            self.history.mark_bad_golden_device(port)
777*cfb92d14SAndroid Build Coastguard Worker
778*cfb92d14SAndroid Build Coastguard Worker                        # remove the bad one
779*cfb92d14SAndroid Build Coastguard Worker                        selected_hw.find_element_by_class_name('removeSelectedDevice').click()
780*cfb92d14SAndroid Build Coastguard Worker                        time.sleep(0.1)
781*cfb92d14SAndroid Build Coastguard Worker
782*cfb92d14SAndroid Build Coastguard Worker                        if len(devices):
783*cfb92d14SAndroid Build Coastguard Worker                            self._add_device(*devices.pop())
784*cfb92d14SAndroid Build Coastguard Worker                        else:
785*cfb92d14SAndroid Build Coastguard Worker                            devices = None
786*cfb92d14SAndroid Build Coastguard Worker
787*cfb92d14SAndroid Build Coastguard Worker                    if devices is None:
788*cfb92d14SAndroid Build Coastguard Worker                        logger.warning('Golden devices not enough')
789*cfb92d14SAndroid Build Coastguard Worker                        raise GoldenDeviceNotEnoughError()
790*cfb92d14SAndroid Build Coastguard Worker                    else:
791*cfb92d14SAndroid Build Coastguard Worker                        logger.info('Try again with new golden devices')
792*cfb92d14SAndroid Build Coastguard Worker                        continue
793*cfb92d14SAndroid Build Coastguard Worker
794*cfb92d14SAndroid Build Coastguard Worker                if self.auto_dut and not settings.DUT_DEVICE:
795*cfb92d14SAndroid Build Coastguard Worker                    radio_auto_dut = browser.find_element_by_class_name('AutoDUT_RadBtns')
796*cfb92d14SAndroid Build Coastguard Worker                    if not radio_auto_dut.is_selected():
797*cfb92d14SAndroid Build Coastguard Worker                        radio_auto_dut.click()
798*cfb92d14SAndroid Build Coastguard Worker
799*cfb92d14SAndroid Build Coastguard Worker                    time.sleep(5)
800*cfb92d14SAndroid Build Coastguard Worker
801*cfb92d14SAndroid Build Coastguard Worker                button_next.click()
802*cfb92d14SAndroid Build Coastguard Worker                if not wait_until(lambda: self._browser.current_url.endswith('TestExecution.html'), 20):
803*cfb92d14SAndroid Build Coastguard Worker                    raise Exception('Failed to load TestExecution page')
804*cfb92d14SAndroid Build Coastguard Worker            except FailError:
805*cfb92d14SAndroid Build Coastguard Worker                raise
806*cfb92d14SAndroid Build Coastguard Worker            except BaseException:
807*cfb92d14SAndroid Build Coastguard Worker                logger.exception('Unexpected error')
808*cfb92d14SAndroid Build Coastguard Worker            else:
809*cfb92d14SAndroid Build Coastguard Worker                break
810*cfb92d14SAndroid Build Coastguard Worker
811*cfb92d14SAndroid Build Coastguard Worker    def _select_case(self, role, case):
812*cfb92d14SAndroid Build Coastguard Worker        """Select the test case.
813*cfb92d14SAndroid Build Coastguard Worker        """
814*cfb92d14SAndroid Build Coastguard Worker        # select the case
815*cfb92d14SAndroid Build Coastguard Worker        elem = Select(self._browser.find_element_by_id('select-dut'))
816*cfb92d14SAndroid Build Coastguard Worker        elem.select_by_value(str(role))
817*cfb92d14SAndroid Build Coastguard Worker        time.sleep(1)
818*cfb92d14SAndroid Build Coastguard Worker
819*cfb92d14SAndroid Build Coastguard Worker        checkbox = None
820*cfb92d14SAndroid Build Coastguard Worker        wait_until(lambda: self._browser.find_elements_by_css_selector('.tree-node .tree-title') and True)
821*cfb92d14SAndroid Build Coastguard Worker        elems = self._browser.find_elements_by_css_selector('.tree-node .tree-title')
822*cfb92d14SAndroid Build Coastguard Worker        finder = re.compile(r'.*\b' + case + r'\b')
823*cfb92d14SAndroid Build Coastguard Worker        finder_dotted = re.compile(r'.*\b' + case.replace(' ', r'\.') + r'\b')
824*cfb92d14SAndroid Build Coastguard Worker        for elem in elems:
825*cfb92d14SAndroid Build Coastguard Worker            # elem.txt might be null when the required reference devices could
826*cfb92d14SAndroid Build Coastguard Worker            # not be met (either due to the quantity or the type) for specific test.
827*cfb92d14SAndroid Build Coastguard Worker            # perform() will throw exceptions if elem.text is null since Chrome
828*cfb92d14SAndroid Build Coastguard Worker            # and chromedriver 80. If elem is not shown in current case list
829*cfb92d14SAndroid Build Coastguard Worker            # window, move_to_element() will not work either.
830*cfb92d14SAndroid Build Coastguard Worker            if not elem.text:
831*cfb92d14SAndroid Build Coastguard Worker                continue
832*cfb92d14SAndroid Build Coastguard Worker            # execute a javascript to scroll the window to the elem
833*cfb92d14SAndroid Build Coastguard Worker            self._browser.execute_script('arguments[0].scrollIntoView();', elem)
834*cfb92d14SAndroid Build Coastguard Worker            action_chains = ActionChains(self._browser)
835*cfb92d14SAndroid Build Coastguard Worker            action_chains.move_to_element(elem)
836*cfb92d14SAndroid Build Coastguard Worker            action_chains.perform()
837*cfb92d14SAndroid Build Coastguard Worker            logger.debug(elem.text)
838*cfb92d14SAndroid Build Coastguard Worker            if finder.match(elem.text) or finder_dotted.match(elem.text):
839*cfb92d14SAndroid Build Coastguard Worker                parent = elem.find_element_by_xpath('..')
840*cfb92d14SAndroid Build Coastguard Worker                checkbox = parent.find_element_by_class_name('tree-checkbox')
841*cfb92d14SAndroid Build Coastguard Worker                break
842*cfb92d14SAndroid Build Coastguard Worker
843*cfb92d14SAndroid Build Coastguard Worker        if not checkbox:
844*cfb92d14SAndroid Build Coastguard Worker            time.sleep(5)
845*cfb92d14SAndroid Build Coastguard Worker            raise Exception('Failed to find the case')
846*cfb92d14SAndroid Build Coastguard Worker
847*cfb92d14SAndroid Build Coastguard Worker        self._browser.execute_script("$('.overview').css('left', '0')")
848*cfb92d14SAndroid Build Coastguard Worker        checkbox.click()
849*cfb92d14SAndroid Build Coastguard Worker        time.sleep(1)
850*cfb92d14SAndroid Build Coastguard Worker
851*cfb92d14SAndroid Build Coastguard Worker        elem = self._browser.find_element_by_id('runTest')
852*cfb92d14SAndroid Build Coastguard Worker        elem.click()
853*cfb92d14SAndroid Build Coastguard Worker        if not wait_until(lambda: self._browser.find_element_by_id('stopTest') and True, 10):
854*cfb92d14SAndroid Build Coastguard Worker            raise Exception('Failed to start test case')
855*cfb92d14SAndroid Build Coastguard Worker
856*cfb92d14SAndroid Build Coastguard Worker    def _collect_result(self):
857*cfb92d14SAndroid Build Coastguard Worker        """Collect test result.
858*cfb92d14SAndroid Build Coastguard Worker
859*cfb92d14SAndroid Build Coastguard Worker        Copy PDF and pcap file to result directory
860*cfb92d14SAndroid Build Coastguard Worker        """
861*cfb92d14SAndroid Build Coastguard Worker
862*cfb92d14SAndroid Build Coastguard Worker        if self.new_th:
863*cfb92d14SAndroid Build Coastguard Worker            os.system('copy "%s\\Reports\\*.*" "%s"' % (settings.HARNESS_HOME, self.result_dir))
864*cfb92d14SAndroid Build Coastguard Worker        else:
865*cfb92d14SAndroid Build Coastguard Worker            os.system('copy "%s\\Thread_Harness\\temp\\*.*" "%s"' % (settings.HARNESS_HOME, self.result_dir))
866*cfb92d14SAndroid Build Coastguard Worker
867*cfb92d14SAndroid Build Coastguard Worker        os.system('copy "%s\\Captures\\*.pcapng" %s\\' % (settings.HARNESS_HOME, self.result_dir))
868*cfb92d14SAndroid Build Coastguard Worker
869*cfb92d14SAndroid Build Coastguard Worker    def _wait_dialog(self):
870*cfb92d14SAndroid Build Coastguard Worker        """Wait for dialogs and handle them until done.
871*cfb92d14SAndroid Build Coastguard Worker        """
872*cfb92d14SAndroid Build Coastguard Worker        logger.debug('waiting for dialog')
873*cfb92d14SAndroid Build Coastguard Worker        done = False
874*cfb92d14SAndroid Build Coastguard Worker        error = False
875*cfb92d14SAndroid Build Coastguard Worker
876*cfb92d14SAndroid Build Coastguard Worker        logger.info('self timeout %d', self.timeout)
877*cfb92d14SAndroid Build Coastguard Worker        while not done and self.timeout:
878*cfb92d14SAndroid Build Coastguard Worker            try:
879*cfb92d14SAndroid Build Coastguard Worker                dialog = self._browser.find_element_by_id('RemoteConfirm')
880*cfb92d14SAndroid Build Coastguard Worker            except BaseException:
881*cfb92d14SAndroid Build Coastguard Worker                logger.exception('Failed to get dialog.')
882*cfb92d14SAndroid Build Coastguard Worker            else:
883*cfb92d14SAndroid Build Coastguard Worker                if dialog and dialog.get_attribute('aria-hidden') == 'false':
884*cfb92d14SAndroid Build Coastguard Worker                    title = dialog.find_element_by_class_name('modal-title').text
885*cfb92d14SAndroid Build Coastguard Worker                    time.sleep(1)
886*cfb92d14SAndroid Build Coastguard Worker                    logger.info('Handling dialog[%s]', title)
887*cfb92d14SAndroid Build Coastguard Worker
888*cfb92d14SAndroid Build Coastguard Worker                    try:
889*cfb92d14SAndroid Build Coastguard Worker                        done = self._handle_dialog(dialog, title)
890*cfb92d14SAndroid Build Coastguard Worker                    except BaseException:
891*cfb92d14SAndroid Build Coastguard Worker                        logger.exception('Error handling dialog: %s', title)
892*cfb92d14SAndroid Build Coastguard Worker                        error = True
893*cfb92d14SAndroid Build Coastguard Worker
894*cfb92d14SAndroid Build Coastguard Worker                    if done is None:
895*cfb92d14SAndroid Build Coastguard Worker                        raise FailError('Unexpected dialog occurred')
896*cfb92d14SAndroid Build Coastguard Worker
897*cfb92d14SAndroid Build Coastguard Worker                    dialog.find_element_by_id('ConfirmOk').click()
898*cfb92d14SAndroid Build Coastguard Worker
899*cfb92d14SAndroid Build Coastguard Worker            time.sleep(1)
900*cfb92d14SAndroid Build Coastguard Worker
901*cfb92d14SAndroid Build Coastguard Worker            try:
902*cfb92d14SAndroid Build Coastguard Worker                stop_button = self._browser.find_element_by_id('stopTest')
903*cfb92d14SAndroid Build Coastguard Worker                if done:
904*cfb92d14SAndroid Build Coastguard Worker                    stop_button.click()
905*cfb92d14SAndroid Build Coastguard Worker                    # wait for stop procedure end
906*cfb92d14SAndroid Build Coastguard Worker                    time.sleep(10)
907*cfb92d14SAndroid Build Coastguard Worker            except NoSuchElementException:
908*cfb92d14SAndroid Build Coastguard Worker                logger.info('Test stopped')
909*cfb92d14SAndroid Build Coastguard Worker                time.sleep(5)
910*cfb92d14SAndroid Build Coastguard Worker                done = True
911*cfb92d14SAndroid Build Coastguard Worker
912*cfb92d14SAndroid Build Coastguard Worker            self.timeout -= 1
913*cfb92d14SAndroid Build Coastguard Worker
914*cfb92d14SAndroid Build Coastguard Worker            # check if already ended capture
915*cfb92d14SAndroid Build Coastguard Worker            if self.timeout % 10 == 0:
916*cfb92d14SAndroid Build Coastguard Worker                lines = self._hc.tail()
917*cfb92d14SAndroid Build Coastguard Worker                if 'SUCCESS: The process "dumpcap.exe" with PID ' in lines:
918*cfb92d14SAndroid Build Coastguard Worker                    logger.info('Tshark should be ended now, lets wait at most 30 seconds.')
919*cfb92d14SAndroid Build Coastguard Worker                    if not wait_until(lambda: 'tshark.exe' not in subprocess.check_output('tasklist'), 30):
920*cfb92d14SAndroid Build Coastguard Worker                        res = subprocess.check_output('taskkill /t /f /im tshark.exe',
921*cfb92d14SAndroid Build Coastguard Worker                                                      stderr=subprocess.STDOUT,
922*cfb92d14SAndroid Build Coastguard Worker                                                      shell=True)
923*cfb92d14SAndroid Build Coastguard Worker                        logger.info(res)
924*cfb92d14SAndroid Build Coastguard Worker
925*cfb92d14SAndroid Build Coastguard Worker        # Wait until case really stopped
926*cfb92d14SAndroid Build Coastguard Worker        wait_until(lambda: self._browser.find_element_by_id('runTest') and True, 30)
927*cfb92d14SAndroid Build Coastguard Worker
928*cfb92d14SAndroid Build Coastguard Worker        if error:
929*cfb92d14SAndroid Build Coastguard Worker            raise FailError('Fail for previous exceptions')
930*cfb92d14SAndroid Build Coastguard Worker
931*cfb92d14SAndroid Build Coastguard Worker    def _handle_dialog(self, dialog, title):
932*cfb92d14SAndroid Build Coastguard Worker        """Handle a dialog.
933*cfb92d14SAndroid Build Coastguard Worker
934*cfb92d14SAndroid Build Coastguard Worker        Returns:
935*cfb92d14SAndroid Build Coastguard Worker            bool True if no more dialogs expected,
936*cfb92d14SAndroid Build Coastguard Worker                 False if more dialogs needed, and
937*cfb92d14SAndroid Build Coastguard Worker                 None if not handled
938*cfb92d14SAndroid Build Coastguard Worker        """
939*cfb92d14SAndroid Build Coastguard Worker        done = self.on_dialog(dialog, title)
940*cfb92d14SAndroid Build Coastguard Worker        if isinstance(done, bool):
941*cfb92d14SAndroid Build Coastguard Worker            return done
942*cfb92d14SAndroid Build Coastguard Worker
943*cfb92d14SAndroid Build Coastguard Worker        if title.startswith('Start DUT'):
944*cfb92d14SAndroid Build Coastguard Worker            body = dialog.find_element_by_id('cnfrmMsg').text
945*cfb92d14SAndroid Build Coastguard Worker            if 'Sleepy End Device' in body:
946*cfb92d14SAndroid Build Coastguard Worker                self.dut.mode = 's'
947*cfb92d14SAndroid Build Coastguard Worker                self.dut.child_timeout = self.child_timeout
948*cfb92d14SAndroid Build Coastguard Worker            elif 'End Device' in body:
949*cfb92d14SAndroid Build Coastguard Worker                self.dut.mode = 'rn'
950*cfb92d14SAndroid Build Coastguard Worker                self.dut.child_timeout = self.child_timeout
951*cfb92d14SAndroid Build Coastguard Worker            else:
952*cfb92d14SAndroid Build Coastguard Worker                self.dut.mode = 'rdn'
953*cfb92d14SAndroid Build Coastguard Worker
954*cfb92d14SAndroid Build Coastguard Worker            if 'at channel' in body:
955*cfb92d14SAndroid Build Coastguard Worker                self.channel = int(body.split(':')[1])
956*cfb92d14SAndroid Build Coastguard Worker
957*cfb92d14SAndroid Build Coastguard Worker            self.dut.channel = self.channel
958*cfb92d14SAndroid Build Coastguard Worker            self.dut.panid = settings.THREAD_PANID
959*cfb92d14SAndroid Build Coastguard Worker            self.dut.networkname = settings.THREAD_NETWORKNAME
960*cfb92d14SAndroid Build Coastguard Worker            self.dut.extpanid = settings.THREAD_EXTPANID
961*cfb92d14SAndroid Build Coastguard Worker            self.dut.start()
962*cfb92d14SAndroid Build Coastguard Worker
963*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('MAC Address Required') or title.startswith('DUT Random Extended MAC Address Required'):
964*cfb92d14SAndroid Build Coastguard Worker            mac = self.dut.mac
965*cfb92d14SAndroid Build Coastguard Worker            inp = dialog.find_element_by_id('cnfrmInpText')
966*cfb92d14SAndroid Build Coastguard Worker            inp.clear()
967*cfb92d14SAndroid Build Coastguard Worker            inp.send_keys('0x%s' % mac)
968*cfb92d14SAndroid Build Coastguard Worker
969*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('LL64 Address'):
970*cfb92d14SAndroid Build Coastguard Worker            ll64 = None
971*cfb92d14SAndroid Build Coastguard Worker            for addr in self.dut.addrs:
972*cfb92d14SAndroid Build Coastguard Worker                addr = addr.lower()
973*cfb92d14SAndroid Build Coastguard Worker                if addr.startswith('fe80') and not re.match('.+ff:fe00:[0-9a-f]{0,4}$', addr):
974*cfb92d14SAndroid Build Coastguard Worker                    ll64 = addr
975*cfb92d14SAndroid Build Coastguard Worker                    break
976*cfb92d14SAndroid Build Coastguard Worker
977*cfb92d14SAndroid Build Coastguard Worker            if not ll64:
978*cfb92d14SAndroid Build Coastguard Worker                raise FailError('No link local address found')
979*cfb92d14SAndroid Build Coastguard Worker
980*cfb92d14SAndroid Build Coastguard Worker            logger.info('Link local address is %s', ll64)
981*cfb92d14SAndroid Build Coastguard Worker            inp = dialog.find_element_by_id('cnfrmInpText')
982*cfb92d14SAndroid Build Coastguard Worker            inp.clear()
983*cfb92d14SAndroid Build Coastguard Worker            inp.send_keys(ll64)
984*cfb92d14SAndroid Build Coastguard Worker
985*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('Enter Channel'):
986*cfb92d14SAndroid Build Coastguard Worker            self.dut.channel = self.channel
987*cfb92d14SAndroid Build Coastguard Worker            inp = dialog.find_element_by_id('cnfrmInpText')
988*cfb92d14SAndroid Build Coastguard Worker            inp.clear()
989*cfb92d14SAndroid Build Coastguard Worker            inp.send_keys(str(self.dut.channel))
990*cfb92d14SAndroid Build Coastguard Worker
991*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('User Action Needed'):
992*cfb92d14SAndroid Build Coastguard Worker            body = dialog.find_element_by_id('cnfrmMsg').text
993*cfb92d14SAndroid Build Coastguard Worker            if body.startswith('Power Down the DUT'):
994*cfb92d14SAndroid Build Coastguard Worker                self.dut.stop()
995*cfb92d14SAndroid Build Coastguard Worker            return True
996*cfb92d14SAndroid Build Coastguard Worker
997*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('Short Address'):
998*cfb92d14SAndroid Build Coastguard Worker            short_addr = '0x%s' % self.dut.short_addr
999*cfb92d14SAndroid Build Coastguard Worker            inp = dialog.find_element_by_id('cnfrmInpText')
1000*cfb92d14SAndroid Build Coastguard Worker            inp.clear()
1001*cfb92d14SAndroid Build Coastguard Worker            inp.send_keys(short_addr)
1002*cfb92d14SAndroid Build Coastguard Worker
1003*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('ML64 Address'):
1004*cfb92d14SAndroid Build Coastguard Worker            ml64 = None
1005*cfb92d14SAndroid Build Coastguard Worker            for addr in self.dut.addrs:
1006*cfb92d14SAndroid Build Coastguard Worker                if addr.startswith('fd') and not re.match('.+ff:fe00:[0-9a-f]{0,4}$', addr):
1007*cfb92d14SAndroid Build Coastguard Worker                    ml64 = addr
1008*cfb92d14SAndroid Build Coastguard Worker                    break
1009*cfb92d14SAndroid Build Coastguard Worker
1010*cfb92d14SAndroid Build Coastguard Worker            if not ml64:
1011*cfb92d14SAndroid Build Coastguard Worker                raise Exception('No mesh local address found')
1012*cfb92d14SAndroid Build Coastguard Worker
1013*cfb92d14SAndroid Build Coastguard Worker            logger.info('Mesh local address is %s', ml64)
1014*cfb92d14SAndroid Build Coastguard Worker            inp = dialog.find_element_by_id('cnfrmInpText')
1015*cfb92d14SAndroid Build Coastguard Worker            inp.clear()
1016*cfb92d14SAndroid Build Coastguard Worker            inp.send_keys(ml64)
1017*cfb92d14SAndroid Build Coastguard Worker
1018*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('Shield Devices') or title.startswith('Shield DUT'):
1019*cfb92d14SAndroid Build Coastguard Worker            time.sleep(2)
1020*cfb92d14SAndroid Build Coastguard Worker            if self.rf_shield:
1021*cfb92d14SAndroid Build Coastguard Worker                logger.info('Shielding devices')
1022*cfb92d14SAndroid Build Coastguard Worker                with self.rf_shield:
1023*cfb92d14SAndroid Build Coastguard Worker                    self.rf_shield.shield()
1024*cfb92d14SAndroid Build Coastguard Worker            elif self.dut and settings.SHIELD_SIMULATION:
1025*cfb92d14SAndroid Build Coastguard Worker                self.dut.channel = (self.channel == THREAD_CHANNEL_MAX and THREAD_CHANNEL_MIN) or (self.channel + 1)
1026*cfb92d14SAndroid Build Coastguard Worker            else:
1027*cfb92d14SAndroid Build Coastguard Worker                input('Shield DUT and press enter to continue..')
1028*cfb92d14SAndroid Build Coastguard Worker
1029*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('Unshield Devices') or title.startswith('Bring DUT back to network'):
1030*cfb92d14SAndroid Build Coastguard Worker            time.sleep(5)
1031*cfb92d14SAndroid Build Coastguard Worker            if self.rf_shield:
1032*cfb92d14SAndroid Build Coastguard Worker                logger.info('Unshielding devices')
1033*cfb92d14SAndroid Build Coastguard Worker                with self.rf_shield:
1034*cfb92d14SAndroid Build Coastguard Worker                    self.rf_shield.unshield()
1035*cfb92d14SAndroid Build Coastguard Worker            elif self.dut and settings.SHIELD_SIMULATION:
1036*cfb92d14SAndroid Build Coastguard Worker                self.dut.channel = self.channel
1037*cfb92d14SAndroid Build Coastguard Worker            else:
1038*cfb92d14SAndroid Build Coastguard Worker                input('Bring DUT and press enter to continue..')
1039*cfb92d14SAndroid Build Coastguard Worker
1040*cfb92d14SAndroid Build Coastguard Worker        elif title.startswith('Configure Prefix on DUT'):
1041*cfb92d14SAndroid Build Coastguard Worker            body = dialog.find_element_by_id('cnfrmMsg').text
1042*cfb92d14SAndroid Build Coastguard Worker            body = body.split(': ')[1]
1043*cfb92d14SAndroid Build Coastguard Worker            params = reduce(
1044*cfb92d14SAndroid Build Coastguard Worker                lambda params, param: params.update(((param[0].strip(' '), param[1]),)) or params,
1045*cfb92d14SAndroid Build Coastguard Worker                [it.split('=') for it in body.split(', ')],
1046*cfb92d14SAndroid Build Coastguard Worker                {},
1047*cfb92d14SAndroid Build Coastguard Worker            )
1048*cfb92d14SAndroid Build Coastguard Worker            prefix = params['P_Prefix'].strip('\0\r\n\t ')
1049*cfb92d14SAndroid Build Coastguard Worker            flags = []
1050*cfb92d14SAndroid Build Coastguard Worker            if params.get('P_slaac_preferred', 0) == '1':
1051*cfb92d14SAndroid Build Coastguard Worker                flags.append('p')
1052*cfb92d14SAndroid Build Coastguard Worker            flags.append('ao')
1053*cfb92d14SAndroid Build Coastguard Worker            if params.get('P_stable', 0) == '1':
1054*cfb92d14SAndroid Build Coastguard Worker                flags.append('s')
1055*cfb92d14SAndroid Build Coastguard Worker            if params.get('P_default', 0) == '1':
1056*cfb92d14SAndroid Build Coastguard Worker                flags.append('r')
1057*cfb92d14SAndroid Build Coastguard Worker            prf = 'high'
1058*cfb92d14SAndroid Build Coastguard Worker            self.dut.add_prefix(prefix, ''.join(flags), prf)
1059*cfb92d14SAndroid Build Coastguard Worker
1060*cfb92d14SAndroid Build Coastguard Worker        return False
1061*cfb92d14SAndroid Build Coastguard Worker
1062*cfb92d14SAndroid Build Coastguard Worker    def test(self):
1063*cfb92d14SAndroid Build Coastguard Worker        """This method will only start test case in child class"""
1064*cfb92d14SAndroid Build Coastguard Worker        if self.__class__ is HarnessCase:
1065*cfb92d14SAndroid Build Coastguard Worker            logger.warning('Skip this harness itself')
1066*cfb92d14SAndroid Build Coastguard Worker            return
1067*cfb92d14SAndroid Build Coastguard Worker
1068*cfb92d14SAndroid Build Coastguard Worker        logger.info('Testing role[%d] case[%s]', self.role, self.case)
1069*cfb92d14SAndroid Build Coastguard Worker
1070*cfb92d14SAndroid Build Coastguard Worker        init_browser_times = 5
1071*cfb92d14SAndroid Build Coastguard Worker        while True:
1072*cfb92d14SAndroid Build Coastguard Worker            if self._init_browser():
1073*cfb92d14SAndroid Build Coastguard Worker                break
1074*cfb92d14SAndroid Build Coastguard Worker            elif init_browser_times > 0:
1075*cfb92d14SAndroid Build Coastguard Worker                init_browser_times -= 1
1076*cfb92d14SAndroid Build Coastguard Worker                self._destroy_browser()
1077*cfb92d14SAndroid Build Coastguard Worker            else:
1078*cfb92d14SAndroid Build Coastguard Worker                raise SystemExit()
1079*cfb92d14SAndroid Build Coastguard Worker
1080*cfb92d14SAndroid Build Coastguard Worker        try:
1081*cfb92d14SAndroid Build Coastguard Worker            # prepare test case
1082*cfb92d14SAndroid Build Coastguard Worker            while True:
1083*cfb92d14SAndroid Build Coastguard Worker                url = self._browser.current_url
1084*cfb92d14SAndroid Build Coastguard Worker                if url.endswith('SetupPage.html'):
1085*cfb92d14SAndroid Build Coastguard Worker                    self._setup_page()
1086*cfb92d14SAndroid Build Coastguard Worker                elif url.endswith('TestBed.html'):
1087*cfb92d14SAndroid Build Coastguard Worker                    self._test_bed()
1088*cfb92d14SAndroid Build Coastguard Worker                elif url.endswith('TestExecution.html'):
1089*cfb92d14SAndroid Build Coastguard Worker                    logger.info('Ready to handle dialogs')
1090*cfb92d14SAndroid Build Coastguard Worker                    break
1091*cfb92d14SAndroid Build Coastguard Worker                time.sleep(2)
1092*cfb92d14SAndroid Build Coastguard Worker        except UnexpectedAlertPresentException:
1093*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Failed to connect to harness server')
1094*cfb92d14SAndroid Build Coastguard Worker            raise SystemExit()
1095*cfb92d14SAndroid Build Coastguard Worker        except FatalError:
1096*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Test stopped for fatal error')
1097*cfb92d14SAndroid Build Coastguard Worker            raise SystemExit()
1098*cfb92d14SAndroid Build Coastguard Worker        except FailError:
1099*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Test failed')
1100*cfb92d14SAndroid Build Coastguard Worker            raise
1101*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
1102*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Something wrong')
1103*cfb92d14SAndroid Build Coastguard Worker
1104*cfb92d14SAndroid Build Coastguard Worker        self._select_case(self.role, self.case)
1105*cfb92d14SAndroid Build Coastguard Worker
1106*cfb92d14SAndroid Build Coastguard Worker        logger.info('start to wait test process end')
1107*cfb92d14SAndroid Build Coastguard Worker        self._wait_dialog()
1108*cfb92d14SAndroid Build Coastguard Worker
1109*cfb92d14SAndroid Build Coastguard Worker        try:
1110*cfb92d14SAndroid Build Coastguard Worker            self._collect_result()
1111*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
1112*cfb92d14SAndroid Build Coastguard Worker            logger.exception('Failed to collect results')
1113*cfb92d14SAndroid Build Coastguard Worker            raise
1114*cfb92d14SAndroid Build Coastguard Worker
1115*cfb92d14SAndroid Build Coastguard Worker        # get case result
1116*cfb92d14SAndroid Build Coastguard Worker        status = self._browser.find_element_by_class_name('title-test').get_attribute('innerText')
1117*cfb92d14SAndroid Build Coastguard Worker        logger.info(status)
1118*cfb92d14SAndroid Build Coastguard Worker        success = 'Pass' in status
1119*cfb92d14SAndroid Build Coastguard Worker        self.assertTrue(success)
1120