• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""
6Test which updates chameleond on the Bluetooth Peer device
7
8This is not a test per se. This 'test' checks if the chameleond version on the
9Bluetooth peer device and updates it if it below the expected value.
10
11"""
12
13
14import logging
15import os
16import sys
17import time
18
19from datetime import datetime
20
21from autotest_lib.client.common_lib import error
22from autotest_lib.server import test
23
24
25# The current chameleond version
26CUR_BT_PKG_VERSION='0.0.1'
27
28
29# The following needs to be kept in sync with values chameleond code
30BUNDLE='chameleond-0.0.2.tar.gz' # Name of the chamleond package
31BUNDLE_DIR = 'chameleond-0.0.2'
32BUNDLE_VERSION = '9999'
33CHAMELEON_BOARD = 'fpga_tio'
34
35def run_cmd(peer, cmd):
36    """A wrapper around host.run()."""
37    try:
38        logging.info("executing command %s on peer",cmd)
39        result = peer.host.run(cmd)
40        logging.info("exit_status is %s", result.exit_status)
41        logging.info("stdout is %s stderr is %s", result.stdout, result.stderr)
42        output = result.stderr if result.stderr else result.stdout
43        if result.exit_status == 0:
44            return True, output
45        else:
46            return False, output
47    except error.AutoservRunError as e:
48        logging.error("Error while running cmd %s %s", cmd, e)
49        return False, None
50
51
52def cmp_version(v1,v2):
53    """ Compare versions.
54
55    Return -1,0,1 depending on whether v1 is less than, equal to or greater
56    than v2
57
58    """
59    p1 = [int(i) for i in v1.split('.')]
60    p2 = [int(i) for i in v2.split('.')]
61    for i1,i2 in zip(p1,p2):
62        if i1 < i2:
63            return -1
64        elif i1 > i2:
65            return 1
66        else:
67            continue
68    return 0
69
70
71def check_version_format(v):
72    """ Check whether version is in proper format"""
73    try:
74        parts = v.split('.')
75        if len(parts) != 3:
76            logging.error('version should be in format x.x.x')
77            return False
78        return all([i.isdigit() for i in parts])
79    except Exception as e:
80        logging.error('exception in check_version_format %s', str(e))
81        return False
82
83
84def is_update_needed(peer):
85    """ Check if update is required
86
87    Get the version of chameleond on the peer and compare to
88    expected version
89
90    @returns: True/False
91    """
92    try:
93        version = peer.get_bt_pkg_version()
94    except:
95        logging.error("Getting the version failed %s",sys.exc_info())
96        raise error.TestFail("Unable to get version")
97
98    logging.info("version on chameleond on the peer device is %s", version)
99    logging.info("current chameleond version is %s", CUR_BT_PKG_VERSION)
100
101    if not check_version_format(version):
102        logging.error("Version not in proper format")
103        raise error.TestFail("Version not in proper format")
104
105    if cmp_version(version, CUR_BT_PKG_VERSION) == -1:
106        logging.debug("Current version is lower. Update required")
107        return True
108    elif cmp_version(version, CUR_BT_PKG_VERSION) == 0:
109        logging.debug("Current version is equal. Update not required")
110        return False
111    else:
112        # A lab peer with a higher version should be highlighted
113        raise error.TestFail("Peer has a higher version")
114
115
116def is_tmp_noexec(peer):
117    """Check if /tmp partition is not excutable."""
118    try:
119        cmd = 'cat /proc/mounts |grep "/tmp"'
120        status, output = run_cmd(peer, cmd)
121        return status and 'noexec' in output
122    except Exception as e:
123        logging.error('Exception %s while checking status of /tmp', str(e))
124        return True
125
126def remount_tmp_exec(peer):
127    """Remount /tmp partition with exec flag."""
128    try:
129        cmd = 'mount -o remount,exec "/tmp"'
130        status, output = run_cmd(peer, cmd)
131        return status
132    except Exception as e:
133        logging.error('Exception %s while remounting /tmp', str(e))
134        return False
135
136
137
138def perform_update(peer, arch):
139    """ Update the chameleond on the peer"""
140
141    if arch == 'CHROMEOS':
142        logging.info("Check if /tmp partition is executable")
143        if is_tmp_noexec(peer):
144            if not remount_tmp_exec(peer):
145                logging.error("unable to remount /tmp as exec")
146                return False
147            if is_tmp_noexec(peer):
148                logging.error("/tmp partition is still noexec")
149                return False
150        logging.info("/tmp partition is executable")
151
152
153    logging.info("copy the file over to the peer")
154    try:
155        current_dir = os.path.dirname(os.path.realpath(__file__))
156        bundle_path = os.path.join(current_dir, BUNDLE)
157        logging.debug("package location is %s", bundle_path)
158        peer.host.send_file(bundle_path, '/tmp/')
159    except:
160        logging.error("copying the file failed %s ", sys.exc_info())
161        return False
162
163    HOST_NOW = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')
164    logging.info("running make on peer")
165    cmd = ('cd /tmp && rm -rf %s && tar zxf %s &&'
166           'cd %s && find -exec touch -c {} \; &&'
167           'make install REMOTE_INSTALL=TRUE '
168           'HOST_NOW="%s" BUNDLE_VERSION=%s '
169           'CHAMELEON_BOARD=%s') % (BUNDLE_DIR, BUNDLE, BUNDLE_DIR,
170                                    HOST_NOW, BUNDLE_VERSION,
171                                    CHAMELEON_BOARD)
172    status, _ = run_cmd(peer, cmd)
173    if not status:
174        logging.info("make failed")
175        return False
176
177    logging.info("chameleond installed on peer")
178    return True
179
180
181
182def restart_check_chameleond(peer, arch):
183    """restart chamleond and make sure it is running."""
184    def _check_output(output, arch):
185        logging.info("checking output '%s' on %s", output, arch)
186        if arch == 'CHROMEOS':
187            expected_output = 'chameleond start/running'
188        else:
189            expected_output = 'chameleond is running'
190        return expected_output in output
191
192    if arch == 'CHROMEOS':
193        restart_cmd = 'restart chameleond'
194        start_cmd = 'start chameleond'
195        status_cmd = 'status chameleond'
196    else:
197        restart_cmd = 'sudo /etc/init.d/chameleond restart'
198        start_cmd = 'sudo /etc/init.d/chameleond start'
199        status_cmd = 'sudo /etc/init.d/chameleond status'
200
201    status, _ = run_cmd(peer, restart_cmd)
202    if not status:
203        status, _ = run_cmd(peer, start_cmd)
204        if not status:
205            logging.error("restarting/starting chamleond failed")
206
207    # Wait till chameleond initialization is complete
208    time.sleep(5)
209
210    status, output = run_cmd(peer, status_cmd)
211    return status and _check_output(output, arch)
212
213
214
215def update_peer(host):
216    """Update the chameleond on peer device if requried"""
217
218    if host.chameleon is None:
219        raise error.TestError('Bluetooth Peer not present')
220
221    peer = host.chameleon
222    arch = host.chameleon.get_platform()
223
224    if arch not in ['CHROMEOS', 'RASPI']:
225        raise error.TestNAError("%s architecture not supported" % arch)
226
227    if not is_update_needed(peer):
228        raise error.TestNAError("Update not needed")
229
230    if not perform_update(peer, arch):
231        raise error.TestFail("Update failed")
232
233    if not restart_check_chameleond(peer, arch):
234        raise error.TestFail("Unable to start chameleond")
235
236    if is_update_needed(peer):
237        raise error.TestFail("Version not updated after upgrade")
238
239    logging.info("updating chameleond succeded")
240
241
242
243class bluetooth_PeerUpdate(test.test):
244    """
245    This test updates chameleond on Bluetooth peer devices
246
247    """
248
249    version = 1
250
251    def run_once(self, host):
252        """ Update Bluetooth peer device
253
254        @param host: the DUT, usually a chromebook
255        """
256
257        self.host = host
258        update_peer(self.host)
259