Logo Search packages:      
Sourcecode: jockey version File versions  Download package

sandbox.py

# -*- coding: UTF-8 -*-

'''Provide a test environment with a fake /sys, modprobe, etc., and
implementations of OSLib, AbstractUI, DriverDB, and various handlers suitable
for self tests.'''

# (c) 2007 Canonical Ltd.
#
# 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 2 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, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import tempfile, atexit, shutil, os, os.path, sys

from jockey.oslib import OSLib
from jockey.detection import HardwareID, DriverID, DriverDB
from jockey.ui import AbstractUI

fake_modinfo = {
    'vanilla': {
        'filename': '/lib/modules/0.8.15/foo/vanilla.ko',
        'license': 'GPL',
        'description': 'free module with available hardware, graphics card',
        'alias': 'pci:v00001001d*sv*sd*bc03sc*i*'
    },
    'chocolate': {
        'filename': '/lib/modules/0.8.15/bar/chocolate.ko',
        'license': 'BSD',
        'description': 'free module with nonavailable hardware',
        'alias': ['pci:v00001002d00000001sv*bc*sc*i*', 'pci:v00001002d00000002sv*sd*bc*sc*i*'],
    },
    'cherry': {
        'filename': '/lib/modules/0.8.15/extra/cherry.ko',
        'license': 'evil',
        'description': 'nonfree module with nonavailable hardware, wifi',
        'alias': 'pci:v0000EEEEd*sv*sd*bc02sc80i*',
    },
    'mint': {
        'filename': '/lib/modules/0.8.15/extra/mint.ko',
        'license': "Palpatine's Revenge",
        'description': 'nonfree module with available hardware, wifi',
        'alias': 'pci:v0000AAAAd000012*sv*sd*bc02sc*i*',
    },
    'vanilla3d': {
        'filename': '/lib/modules/0.8.15/extra/vanilla3d.ko',
        'license': 'PayMe',
        'description': 'nonfree, replacement graphics driver for vanilla',
        'alias': 'pci:v00001001d00003D*sv*sd*bc03sc*i*'
    },
    'spam': {
        'filename': '/lib/modules/0.8.15/extra/spam.ko',
        'license': 'GPL',
        'description': 'free mystical module without modaliases',
    },
    'dullstd': {
        'filename': '/lib/modules/0.8.15/standard/dullstd.ko',
        'license': 'GPL',
        'description': 'standard module which should be ignored for detection',
        'alias': 'pci:v0000DEAFd*sv*sd*bc99sc*i*'
    },
    'firmwifi': {
        'filename': '/lib/modules/0.8.15/standard/firmwifi.ko',
        'license': 'GPL',
        'description': 'standard module which needs firmware',
        'alias': 'fire:1.*',
    },
    'foodmi': {
        'filename': '/lib/modules/0.8.15/dmi/foo.ko',
        'license': 'GPL',
        'description': 'foo DMI driver for [A-1] devices',
        'alias': 'dmi:foo[A-1]*',
    },
}

fake_sys = {
    # graphics card, can use vanilla or vanilla3d, defaulting to free driver
    'pci0000:00/0000:00:11.2': {
        'modalias': 'pci:v00001001d00003D01sv00001234sd00000001bc03sc00i00',
        'driver': '../../../bus/pci/drivers/vanilla',
        'module': 'vanilla',
    },

    # pretend that we have two devices using vanilla, to check for duplication
    # of handlers
    'pci0000:02/0000:00:03.4': {
        'modalias': 'pci:v00001001d00003D01sv00001234sd00000001bc03sc00i00',
        'driver': '../../../bus/pci/drivers/vanilla',
        'module': 'vanilla',
    },

    # something that uses a statically built-in kernel driver
    'pci0000:00/0000:00:22.3': {
        'modalias': 'pci:v00003456d00000001sv00000000sd00000000bc09sc23i00',
        'driver': '../../../bus/pci/drivers/southbridge',
    },

    # wifi which can use mint, but not enabled
    'pci0000:00/0000:01:01.0': {
        'modalias': 'pci:v0000AAAAd000012AAsv00000000sdDEADBEEFbc02sc80i00',
    },

    # another wifi on a funny bus, used for firmware testing
    'fire0/1/2': {
        'modalias': 'fire:1.2'
    },

    # unknown piece of hardware
    'pci0000:01/0000:05:05.0': {
        'modalias': 'pci:v0000FFF0d00000001sv00000000sd00000000bc06sc01i01',
    },

    # uninteresting standard component
    'pci0000:02/0000:01:02.3': {
        'modalias': 'pci:v0000DEAFd00009999sv00000000sd00000000bc99sc00i00',
        'driver': '../../../bus/pci/drivers/dullstd',
        'module': 'dullstd',
    },

    # card on SSB bus which has an uevent, but not a modalias file (like the
    # b43 module)
    'pci0001:00/0001:00:00.1/ssb0:0': {
        'uevent': 'DRIVER=b43\nMODALIAS=ssb:v4243id0812rev05',
    },

    # device with shell glob-like characters in modalias
    'dmi0/1': {
        'modalias': 'dmi:foo[A-1]bar',
    }

}

fake_db = {
    # vanilla3d option for the graphics card
    HardwareID('modalias', 'pci:v00001001d00003D*sv*sd*bc03sc*i*'): {
        ('Foonux', '42'): [DriverID(handler='VanillaGfxHandler')],
        ('Foonux', '41'): [DriverID(handler='IShallNotExist')],
        ('RedSock', '2.0'): [DriverID(handler='Vanilla3DHandler',
            repository='http://nonfree.redsock.com/addons')]
    },

    # driver for the unknown piece of hardware; test multiple handlers here
    HardwareID('modalias', 'pci:v0000FFF0d0000*sv*sd*bc06sc01i*'): {
        ('Foonux', '42'): [
            DriverID(handler='KernelModuleHandler', module='spam'),
            DriverID(handler='KernelModuleHandler', module='mint')
        ],
    },

    # driver for the second wifi, test firmware handler
    HardwareID('modalias', 'fire:1.2'): {
        ('Foonux', '42'): [
            DriverID(handler='FirmwareHandler', module='firmwifi',
                testfile='/lib/firmware/firmwifi.bin', url='http://foo.bar'),
        ],
    },

    # unknown driver
    HardwareID('pci', '9876/FEDC'): {
        ('Foonux', '42'): [DriverID(handler='BogusHandler')],
        ('Oobuntu', 'Eccentric Emu'): [DriverID(handler='BogusHandler')],
    }
}

fake_pkginfo = {
    'mesa-vanilla': {
        'description': ('X.org libraries for the Vanilla 3D driver', 
            'This package provides optimized Mesa libraries for the Vanilla '
            'graphics cards.'),
        'free': False,
    },
    'mesa-std': {
        'description': ('standard system mesa libraries',
            'default mesa libs for free drivers'),
        'free': True,
    },
    'coreutils': {
        'description': ('unrelated system package',
            'This package should always be installed.'),
        'free': True,
    },
    'pretzel': {
        'description': ('yet another test packge',
            'This is yummy, but uninteresting.'),
        'free': False,
    },
}

#-------------------------------------------------------------------#

00200 class TestOSLib(OSLib):
    '''Test suite implementation of OSLib.
    
    This builds a realistic mini-chroot and fake module/package system.
    '''
00205     def __init__(self):
        OSLib.__init__(self)

        # set up a fake environment
        self.workdir = tempfile.mkdtemp()
        atexit.register(shutil.rmtree, self.workdir)
        self._make_modinfo()
        self._make_proc_modules()
        self._make_modprobe()
        self._make_modalias()
        self._make_sys()
        self._make_xorg_conf()

        self.module_blacklist_file = os.path.join(self.workdir, 'module-blacklist')

        self.handler_dir = os.path.join(self.workdir, 'handlers')
        os.mkdir(self.handler_dir)
        self.check_cache = os.path.join(self.workdir, 'check_cache')
        self.backup_dir = os.path.join(self.workdir, 'backup')
        os.mkdir(self.backup_dir)

        self.installed_packages = set(['mesa-std', 'coreutils'])
        self.next_package_install_fails = False

        self.reboot_flag = False

        self.help_available = False
        self.help_called = False

00234     def _make_modinfo(self):
        '''Create a dummy modinfo program which outputs the fake_modinfo data
        and set self.modinfo_path.
        
        Note that this fake modinfo only supports one module argument, not
        several (as the original modinfo), and no options.'''

        os.mkdir(os.path.join(self.workdir, 'bin'))
        self.modinfo_path = os.path.join(self.workdir, 'bin', 'modinfo')
        mi = open(self.modinfo_path, 'w')
        mi.write('''#!/usr/bin/python
import sys

data = %s

if len(sys.argv) != 2:
    print >> sys.stderr, 'Usage: modinfo module'
    sys.exit(0)

m = sys.argv[1]
if m in data:
    attrs = data[m].keys()
    attrs.sort()
    for k in attrs:
        if hasattr(data[m][k], 'isspace'):
            print '%%-16s%%s' %% (k + ':', data[m][k])
        else:
            for i in data[m][k]:
                print '%%-16s%%s' %% (k + ':', i)
else:
    print >> sys.stderr, 'modinfo: could not find module', m
    sys.exit(1)

''' % repr(fake_modinfo))
        mi.close()
        os.chmod(self.modinfo_path, 0755)

00271     def _make_modprobe(self):
        '''Create a dummy modprobe and set self.modprobe_path.'''

        self.modprobe_path = os.path.join(self.workdir, 'bin', 'modprobe')
        mp = open(self.modprobe_path, 'w')
        mp.write('''#!/usr/bin/python
import sys

modinfo = %s
proc_modules = %s

if len(sys.argv) != 2:
    print >> sys.stderr, 'Usage: modprobe module'
    sys.exit(1)

m = sys.argv[1]
if m in modinfo:
    if m not in open(proc_modules).read():
        print >> open(proc_modules, 'a'), '%%s 11111 2 - Live 0xbeefbeef' %% m
else:
    print >> sys.stderr, 'FATAL: Module %%s not found.' %% m
    sys.exit(1)
''' % (repr(fake_modinfo), repr(self.proc_modules)))

        mp.close()
        os.chmod(self.modprobe_path, 0755)
        
00298     def _make_sys(self):
        '''Create a dummy /sys tree from fake_sys and set self.sys_dir.'''

        self.sys_dir = os.path.join(self.workdir, 'sys')

        for pcipath, info in fake_sys.iteritems():
            # create /sys/device entry
            device_dir = os.path.join(self.sys_dir, 'devices', pcipath)
            os.makedirs(device_dir)
            if 'modalias' in info:
                open(os.path.join(device_dir, 'modalias'), 'w').write(info['modalias'])
            if 'uevent' in info:
                open(os.path.join(device_dir, 'uevent'), 'w').write(info['uevent'])

            # create driver dir and symlink to device, if existing
            if 'driver' not in info:
                continue
            driver_dir = os.path.join(device_dir, info['driver'])
            try:
                os.makedirs(driver_dir)
            except OSError:
                pass
            os.symlink(info['driver'], os.path.join(device_dir, 'driver'))
            os.symlink(device_dir, os.path.join(driver_dir,
                os.path.basename(pcipath)))

            # create module dir and symlink to driver, if existing
            if 'module' not in info:
                continue
            module_dir = os.path.join(self.workdir, 'sys', 'module', info['module'])
            try:
                os.makedirs(os.path.join(module_dir, 'drivers'))
            except OSError:
                pass
            if not os.path.islink(os.path.join(driver_dir, 'module')):
                os.symlink(module_dir, os.path.join(driver_dir, 'module'))
            driver_comp = info['driver'].split('/')
            mod_driver_link = os.path.join(module_dir, 'drivers',
                '%s:%s' % (driver_comp[-3], driver_comp[-1]))
            if not os.path.islink(mod_driver_link):
                os.symlink(driver_dir, mod_driver_link)

00340     def _make_proc_modules(self):
        '''Create a dummy /proc/modules and set self.proc_modules.'''

        self.proc_modules = os.path.join(self.workdir, 'proc', 'modules')
        if not os.path.isdir(os.path.dirname(self.proc_modules)):
            os.mkdir(os.path.dirname(self.proc_modules))
        mods = set()
        for info in fake_sys.itervalues():
            try:
                mods.add(info['module'])
            except KeyError:
                pass

        f = open(self.proc_modules, 'w')
        for m in mods:
            print >> f, '%s 12345 0 - Live 0xdeadbeef' % m
        f.close()

00358     def _make_modalias(self):
        '''Create a dummy modules.alias and set self.modaliases
        appropriately.'''

        # prepare one fake kernel modules.alias and an override directory
        self.modaliases = [
            os.path.join(self.workdir, 'kernelmods', 'modules.alias'),
            os.path.join(self.workdir, 'modalias-overrides'),
            '/nonexisting', # should not stumble over those
        ]
        os.mkdir(os.path.dirname(self.modaliases[0]))
        os.mkdir(self.modaliases[1])

        f = open(self.modaliases[0], 'w')
        print >> f, '# Aliases extracted from modules themselves.'
        for mod in sorted(fake_modinfo.keys()):
            aliases = fake_modinfo[mod].get('alias', [])
            if hasattr(aliases, 'isspace'):
                print >> f, 'alias %s %s' % (aliases, mod)
            else:
                for a in aliases:
                    print >> f, 'alias %s %s' % (a, mod)
        f.close()

00382     def _make_xorg_conf(self):
        '''Create a dummy xorg.conf and set self.xorg_conf_path appropriately.'''

        self.xorg_conf_path = os.path.join(self.workdir, 'xorg.conf')
        f = open(self.xorg_conf_path, 'w')
        f.write('''# xorg.conf (xorg X Window System server configuration file)

Section "InputDevice"
      Identifier  "Generic Keyboard"
      Driver            "kbd"
      Option            "CoreKeyboard"
      Option            "XkbRules"  "xorg"
      Option            "XkbModel"  "pc105"
      Option            "XkbLayout" "us"
EndSection

Section "Device"
      Identifier  "Standard ice cream graphics"
      Driver            "vanilla"
EndSection

Section "Monitor"
      Identifier  "My Monitor"
      Option            "DPMS"
      HorizSync   30-70
      VertRefresh 50-160
EndSection

Section "Screen"
      Identifier  "Default Screen"
      Device            "Standard ice cream graphics"
      Monitor           "My Monitor"
      DefaultDepth      24
EndSection

Section "ServerLayout"
      Identifier  "Default Layout"
      Screen            "Default Screen"
      InputDevice "Generic Keyboard"
EndSection
''')
        f.close()

00425     def _get_os_version(self):
        self.os_vendor = 'Foonux'
        self.os_version = '42'

00429     def ignored_modules(self):
        return set(['dullstd'])

00432     def package_description(self, package):
        '''Return a tupe (short_description, long_description) for given
        package.
        
        This should raise a ValueError if the package is not available.'''

        try:
            return fake_pkginfo[package]['description']
        except KeyError:
            raise ValueError, 'no such package'

00443     def is_package_free(self, package):
        '''Return if given package is free software.'''

        return fake_pkginfo[package]['free']

00448     def package_installed(self, package):
        '''Return if the given package is installed.'''

        return package in self.installed_packages

00453     def install_package(self, package, ui):
        '''Install the given package.

        The current UI object is passed as well, in case package installation
        wants to do some callbacks/confirmation dialogs/queries.

        If this succeeds, subsequent package_installed(package) calls must
        return True.'''

        assert package in fake_pkginfo
        if self.next_package_install_fails:
            self.next_package_install_fails = False
        else:
            self.installed_packages.add(package)

00468     def remove_package(self, package, ui):
        '''Uninstall the given package.

        The current UI object is passed as well, in case package installation
        wants to do some callbacks/confirmation dialogs/queries.

        If this succeeds, subsequent package_installed(package) calls must
        return False.'''

        assert package in fake_pkginfo
        self.installed_packages.remove(package)

00480     def ui_notify_reboot(self, ui):
        '''Indicate that the user should do a reboot to activate changes (such
        as changing an X.org video driver).'''

        self.reboot_flag = True

    def pop_reboot_flag(self):
        result = self.reboot_flag
        self.reboot_flag = False
        return result

00491     def ui_help_available(self, ui):
        '''Return if help is available.

        This gets the current UI object passed, which can be used to determine
        whether GTK/KDE is used, etc.
        '''
        return self.help_available

00499     def ui_help(self, ui):
        '''The UI's help button was clicked.

        This should open a help HTML page or website, call yelp with an
        appropriate topic, etc. This gets the current UI object passed, which
        can be used to determine whether GTK/KDE is used, etc.
        '''
        self.help_called = True

00508     def open_app(self, ui, custom_args = None):
        l = open(os.path.join(self.workdir, 'open_app.log'), 'w')
        if custom_args:
            print >> l, ' '.join(custom_args)
        else:
            print >> l, ' '.join(sys.argv)
        l.close()

#-------------------------------------------------------------------#

00518 class AllAvailOSLib(OSLib):
    '''Test suite implementation of OSLib.

    This pretends that any module and packge is always available and gives
    predictable and constant descriptions and states. It is mainly useful for
    testing arbitrary and unknown handlers.
    '''

00526     def __init__(self):
        OSLib.__init__(self)
        self.installed_packages = set()
        self.blacklisted_modules = set()

        self.workdir = tempfile.mkdtemp()
        atexit.register(shutil.rmtree, self.workdir)

        self.reboot_flag = False
        self._make_modinfo()
        self.xorg_conf_path = os.path.join(self.workdir, 'xorg.conf')

00538     def package_description(self, package):
        '''Return a tuple (short_description, long_description) for a package.
        
        This should raise a ValueError if the package is not available.
        '''
        return (package + ' description', package + 'long description')

00545     def is_package_free(self, package):
        '''Return if given package is free software.'''

        return True

00550     def package_installed(self, package):
        '''Return if the given package is installed.'''

        return package in self.installed_packages

00555     def install_package(self, package, ui):
        '''Install the given package.'''

        self.installed_packages.add(package)

00560     def remove_package(self, package, ui):
        '''Uninstall the given package.'''

        self.installed_packages.remove(package)

00565     def module_blacklisted(self, module):
        '''Check if a module is on the modprobe blacklist.'''

        return module in self.blacklisted_modules

00570     def blacklist_module(self, module, blacklist):
        '''Add or remove a kernel module from the modprobe blacklist.
        
        If blacklist is True, the module is blacklisted, otherwise it is
        removed from the blacklist.
        '''

        if blacklist:
            self.blacklisted_modules.add(module)
        else:
            try:
                self.blacklisted_modules.remove(module)
            except KeyError:
                pass

00585     def ui_notify_reboot(self, ui):
        '''Indicate that the user should do a reboot to activate changes (such
        as changing an X.org video driver).'''

        self.reboot_flag = True


00592     def _make_modinfo(self):
        '''Create a dummy modinfo program which outputs dummy data
        and set self.modinfo_path.
        
        Note that this fake modinfo only supports one module argument, not
        several (as the original modinfo), and no options.'''

        os.mkdir(os.path.join(self.workdir, 'bin'))
        self.modinfo_path = os.path.join(self.workdir, 'bin', 'modinfo')
        mi = open(self.modinfo_path, 'w')
        mi.write('''#!/usr/bin/python
import sys

data = %s

if len(sys.argv) != 2:
    print >> sys.stderr, 'Usage: modinfo module'
    sys.exit(0)

m = sys.argv[1]
print '%%-16s%%s' %% ('filename:', '/lib/modules/%%s.ko' %% m)
print '%%-16s%%s' %% ('license:', 'GPL')
print '%%-16s%%s' %% ('description:', '%%s module' %% m)
''' % repr(fake_modinfo))
        mi.close()
        os.chmod(self.modinfo_path, 0755)

#-------------------------------------------------------------------#

00621 class TestDriverDB(DriverDB):
    '''Test suite implementation of DriverDB'''

    def query(self, hwid):
        return fake_db.get(hwid, {}).get(
            (OSLib.inst.os_vendor, OSLib.inst.os_version), [])

#-------------------------------------------------------------------#

class TestUI(AbstractUI):
    def __init__(self):
        AbstractUI.__init__(self)
        self.error_stack = []
        self.confirm_response = None
        self.notification_stack = []
        self.main_loop_active = False
        self.cur_download = [None, None, None] # (url, size, total)
        self.cancel_download = False # whether to cancel the next download at 30%

    def convert_keybindings(self, str):
        return str

    def ui_init(self):
        pass

    def ui_main_loop(self):
        '''Main loop for the user interface.
        
        This should return if the user wants to quit the program, and return
        the exit code.'''

        self.main_loop_active = True

    def ui_idle(self):
        pass

    def error_message(self, title, text):
        '''Show an error message box with given title and text.'''

        self.error_stack.append((title, text))

    def pop_error(self):
        '''Return the last error message (title, text) tuple.'''

        return self.error_stack.pop()

    def confirm_action(self, title, text, subtext = None, action=None):
        assert self.confirm_response is not None, 'must set confirm_response'

        self.last_confirm_title = title
        self.last_confirm_text = text
        self.last_confirm_subtext = subtext
        self.last_confirm_action = action

        r = self.confirm_response
        self.confirm_response = None

        return r

    def ui_notification(self, title, text):
        self.notification_stack.append((title, text))

    def pop_notification(self):
        '''Return the last notification (title, text) tuple.'''

        return self.notification_stack.pop()

    def ui_download_start(self, url, total_size):
        '''Create a progress dialog for a download of given URL.

        total_size specifes the number of bytes to download, or -1 if it cannot
        be determined. In this case the dialog should display an indeterminated
        progress bar (bouncing back and forth).'''

        assert url
        self.cur_download = [url, 0, total_size]

    def ui_download_progress(self, current_size, total_size):
        '''Update download progress of current download.
        
        This should return True to cancel the current download, and False
        otherwise.'''

        assert self.cur_download[0]
        assert self.cur_download[1] is not None
        assert self.cur_download[2] is not None
        assert current_size > self.cur_download[1]
        assert total_size == self.cur_download[2]

        self.cur_download[1] = current_size

        return self.cancel_download and float(current_size)/total_size >= 0.3

    def ui_download_finish(self):
        '''Close the current download progress dialog.'''

        self.cancel_download = False

#-------------------------------------------------------------------#
# TestOSLib consistency tests

import unittest, subprocess

class TestOSLibConsistencyTest(unittest.TestCase):
    def test_modinfo_output(self):
        '''test suite's modinfo output for known modules'''
        
        m = subprocess.Popen([OSLib.inst.modinfo_path, 'vanilla'],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (out, err) = m.communicate()
        self.assertEqual(err, '')
        self.assertEqual(out, '''alias:          pci:v00001001d*sv*sd*bc03sc*i*
description:    free module with available hardware, graphics card
filename:       /lib/modules/0.8.15/foo/vanilla.ko
license:        GPL
''')
        self.assertEqual(m.returncode, 0)

        m = subprocess.Popen([OSLib.inst.modinfo_path, 'chocolate'],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (out, err) = m.communicate()
        self.assertEqual(err, '')
        self.assertEqual(m.returncode, 0)
        self.assert_('chocolate.ko' in out)
        # both modaliases
        self.assert_('alias:          pci:v00001002d00000001sv*' in out)
        self.assert_('alias:          pci:v00001002d00000002sv*' in out)

    def test_modinfo_error(self):
        '''test suite's modinfo output for unknown modules and invalid invocation'''
        
        m = subprocess.Popen([OSLib.inst.modinfo_path, 'nonexisting'],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (out, err) = m.communicate()
        self.assertEqual(out, '')
        self.assert_('could not find module nonexisting' in err)
        self.assertEqual(m.returncode, 1)

        m = subprocess.Popen([OSLib.inst.modinfo_path],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (out, err) = m.communicate()
        self.assertEqual(out, '')
        self.assert_('Usage' in err)
        self.assertEqual(m.returncode, 0)

    def test_modprobe(self):
        '''test suite's modprobe works'''

        # help output
        m = subprocess.Popen([OSLib.inst.modprobe_path],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (out, err) = m.communicate()
        self.assertEqual(out, '')
        self.assert_('Usage' in err)
        self.assertEqual(m.returncode, 1)

        # invalid module
        m = subprocess.Popen([OSLib.inst.modprobe_path, 'nonexisting'],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (out, err) = m.communicate()
        self.assertEqual(out, '')
        self.assert_('FATAL' in err)
        self.assert_('nonexisting' in err)
        self.assertEqual(m.returncode, 1)

        # valid module
        orig_content = open(OSLib.inst.proc_modules).read()
        try:
            self.failIf('cherry' in orig_content)
            m = subprocess.Popen([OSLib.inst.modprobe_path, 'cherry'],
                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            (out, err) = m.communicate()
            self.assertEqual(out, '')
            self.assertEqual(err, '')
            self.assertEqual(m.returncode, 0)
            self.assert_('cherry' in open(OSLib.inst.proc_modules).read())
        finally:
            open(OSLib.inst.proc_modules, 'w').write(orig_content)

    def test_sys_symlinks(self):
        '''all symlinks in fake /sys are valid'''

        for path, dirs, files in os.walk(os.path.join(OSLib.inst.workdir, 'sys')):
            for f in files+dirs:
                p = os.path.join(path, f)
                if os.path.islink(p):
                    rp = os.path.realpath(p)
                    self.assert_(os.path.exists(rp), 
                        'symbolic link %s -> %s is valid' % (p, rp))

    def test_module_aliases_file(self):
        '''module.aliases correctness'''

        self.assertEqual(open(os.path.join(OSLib.inst.workdir, 'kernelmods',
            'modules.alias')).read(), 
            '''# Aliases extracted from modules themselves.
alias pci:v0000EEEEd*sv*sd*bc02sc80i* cherry
alias pci:v00001002d00000001sv*bc*sc*i* chocolate
alias pci:v00001002d00000002sv*sd*bc*sc*i* chocolate
alias pci:v0000DEAFd*sv*sd*bc99sc*i* dullstd
alias fire:1.* firmwifi
alias dmi:foo[A-1]* foodmi
alias pci:v0000AAAAd000012*sv*sd*bc02sc*i* mint
alias pci:v00001001d*sv*sd*bc03sc*i* vanilla
alias pci:v00001001d00003D*sv*sd*bc03sc*i* vanilla3d
''')

    def test_proc_modules(self):
        '''/proc/modules correctness'''

        m = open(OSLib.inst.proc_modules).read()
        self.assertEqual(len(m.splitlines()), 2)
        self.assert_('dullstd' in m)
        self.assert_('vanilla' in m)
        self.failIf('vanilla3d' in m)
        self.failIf('cherry' in m)
        self.failIf('mint' in m)

#-------------------------------------------------------------------#
# test handlers

h_avail_mod = '''
from jockey.handlers import KernelModuleHandler
class AvailMod(KernelModuleHandler):
    def __init__(self, ui):
        KernelModuleHandler.__init__(self, ui, 'vanilla',
            description='Test suite: available kernel module')
    def available(self):
        return True
'''

h_notavail_mod = '''
from jockey.handlers import KernelModuleHandler
class NotAvailMod(KernelModuleHandler):
    def __init__(self, ui):
        KernelModuleHandler.__init__(self, ui, 'chocolate',
            description='Test suite: non-available kernel module')
    def available(self):
        return False
'''

h_nodetectmod = '''
class NoDetectMod(jockey.handlers.KernelModuleHandler):
    def __init__(self, ui):
        jockey.handlers.KernelModuleHandler.__init__(self, ui, 'spam',
            description='Test suite: non-detectable kernel module')
'''

# complete .py file contents with above three handlers
h_availability_py = 'import jockey.handlers\n%s\n%s\n%s\n' % (
    h_avail_mod, h_notavail_mod, h_nodetectmod)

h_nochangemod = '''
class NoChangeMod(jockey.handlers.KernelModuleHandler):
    def __init__(self, ui):
        jockey.handlers.KernelModuleHandler.__init__(self, ui, 'vanilla')
    def available(self):
        return True
    def can_change(self):
        return 'I must live'
'''

# custom handler for ignored kmod
h_ignored_custom_mod = '''
from jockey.handlers import KernelModuleHandler
class LessDullMod(KernelModuleHandler):
    def __init__(self, ui):
        KernelModuleHandler.__init__(self, ui, 'dullstd',
            description='Test suite: custom handler for dullstd (ignored kmod)')
'''

#-------------------------------------------------------------------#
# other globals

log = None

Generated by  Doxygen 1.6.0   Back to index