Source code for autopilot.platform

# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
#
# Autopilot Functional Test Tool
# Copyright (C) 2012-2013 Canonical
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#


"""
Platform identification utilities for Autopilot.
================================================

This module provides functions that give test authors hints as to which
platform their tests are currently running on. This is useful when a test
needs to test slight different behavior depending on the system it's running
on. For example::

    from autopilot import platform

    ...

    def test_something(self):
        if platform.model() == "Galaxy Nexus":
            # do something
        elif platform.model() == "Desktop":
            # do something else

    def test_something_else(self):
        if platform.is_tablet():
            # run a tablet test
        else:
            # run a non-tablet test

Skipping tests based on Platform
++++++++++++++++++++++++++++++++

Sometimes you want a test to not run on certain platforms, or only run on
certain platforms. This can be easily achieved with a combination of the
functions in this module and the ``skipIf`` and ``skipUnless`` decorators. For
example, to define a test that only runs on the galaxy nexus device, write
this::

    from testtools import skipUnless

    ...

    @skipUnless(
        platform.model() == 'Galaxy Nexus',
        "Test is only for Galaxy Nexus"
    )
    def test_something(self):
        # test things!

The inverse is possible as well. To define a test that will run on every device
except the Galaxy Nexus, write this::

    from testtools import skipIf

    ...

    @skipIf(
        platform.model() == 'Galaxy Nexus',
        "Test not available for Galaxy Nexus"
    )
    def test_something(self):
        # test things!

Tuples of values can be used as well, to select more than one platform. For
example::

    @skipIf(
        platform.model() in ('Model One', 'Model Two'),
        "Test not available for Models One and Two"
    )
        def test_something(self):
            # test things!


"""


[docs]def model(): """Get the model name of the current platform. For desktop / laptop installations, this will return "Desktop". Otherwise, the current hardware model will be returned. For example:: platform.model() ... "Galaxy Nexus" """ return _PlatformDetector.create().model
[docs]def image_codename(): """Get the image codename. For desktop / laptop installations this will return "Desktop". Otherwise, the codename of the image that was installed will be returned. For example: platform.image_codename() ... "maguro" """ return _PlatformDetector.create().image_codename
[docs]def is_tablet(): """Indicate whether system is a tablet. The 'ro.build.characteristics' property is checked for 'tablet'. For example: platform.tablet() ... True :returns: boolean indicating whether this is a tablet """ return _PlatformDetector.create().is_tablet
class _PlatformDetector(object): _cached_detector = None @staticmethod def create(): """Create a platform detector object, or return one we baked earlier.""" if _PlatformDetector._cached_detector is None: _PlatformDetector._cached_detector = _PlatformDetector() return _PlatformDetector._cached_detector def __init__(self): self.model = "Desktop" self.image_codename = "Desktop" self.is_tablet = False property_file = _get_property_file() if property_file is not None: self.update_values_from_build_file(property_file) def update_values_from_build_file(self, property_file): """Read build.prop file and parse it.""" properties = _parse_build_properties_file(property_file) self.model = properties.get('ro.product.model', "Desktop") self.image_codename = properties.get('ro.product.name', "Desktop") self.is_tablet = ('ro.build.characteristics' in properties and 'tablet' in properties['ro.build.characteristics']) def _get_property_file_path(): return '/system/build.prop' def _get_property_file(): """Return a file-like object that contains the contents of the build properties file, if it exists, or None. """ path = _get_property_file_path() try: return open(path) except IOError: return None def _parse_build_properties_file(property_file): """Parse 'property_file', which must be a file-like object containing the system build properties. Returns a dictionary of key,value pairs. """ properties = {} for line in property_file: line = line.strip() if not line or line.startswith('#'): continue split_location = line.find('=') if split_location == -1: continue key = line[:split_location] value = line[split_location + 1:] properties[key] = value return properties