~alexeftimie/jockey/fix-gobject

« back to all changes in this revision

Viewing changes to tests/sandbox.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2008-01-17 15:02:40 UTC
  • Revision ID: james.westby@ubuntu.com-20080117150240-djmsi8giu255vzzn
Tags: 0.1~r118
* Initial release, result of completely rewriting restricted-manager to be
  maintainable, robust, and suitable for other distributions. Some features
  and the KDE UI still need to be ported.
* See restricted-manager-rewrite specification for details.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: UTF-8 -*-
 
2
 
 
3
'''Provide a test environment with a fake /sys, modprobe, etc., and
 
4
implementations of OSLib, AbstractUI, DriverDB, and various handlers suitable
 
5
for self tests.'''
 
6
 
 
7
# (c) 2007 Canonical Ltd.
 
8
#
 
9
# This program is free software; you can redistribute it and/or modify
 
10
# it under the terms of the GNU General Public License as published by
 
11
# the Free Software Foundation; either version 2 of the License, or
 
12
# (at your option) any later version.
 
13
#
 
14
# This program is distributed in the hope that it will be useful,
 
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
# GNU General Public License for more details.
 
18
#
 
19
# You should have received a copy of the GNU General Public License along
 
20
# with this program; if not, write to the Free Software Foundation, Inc.,
 
21
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
22
 
 
23
import tempfile, atexit, shutil, os, os.path
 
24
 
 
25
from jockey.oslib import OSLib
 
26
from jockey.detection import HardwareID, DriverID, DriverDB
 
27
from jockey.ui import AbstractUI
 
28
 
 
29
fake_modinfo = {
 
30
    'vanilla': {
 
31
        'filename': '/lib/modules/0.8.15/foo/vanilla.ko',
 
32
        'license': 'GPL',
 
33
        'description': 'free module with available hardware, graphics card',
 
34
        'alias': 'pci:v00001001d*sv*sd*bc03sc*i*'
 
35
    },
 
36
    'chocolate': {
 
37
        'filename': '/lib/modules/0.8.15/bar/chocolate.ko',
 
38
        'license': 'BSD',
 
39
        'description': 'free module with nonavailable hardware',
 
40
        'alias': ['pci:v00001002d00000001sv*bc*sc*i*', 'pci:v00001002d00000002sv*sd*bc*sc*i*'],
 
41
    },
 
42
    'cherry': {
 
43
        'filename': '/lib/modules/0.8.15/extra/cherry.ko',
 
44
        'license': 'evil',
 
45
        'description': 'nonfree module with nonavailable hardware, wifi',
 
46
        'alias': 'pci:v0000EEEEd*sv*sd*bc02sc80i*',
 
47
    },
 
48
    'mint': {
 
49
        'filename': '/lib/modules/0.8.15/extra/mint.ko',
 
50
        'license': "Palpatine's Revenge",
 
51
        'description': 'nonfree module with available hardware, wifi',
 
52
        'alias': 'pci:v0000AAAAd000012*sv*sd*bc02sc*i*',
 
53
    },
 
54
    'vanilla3d': {
 
55
        'filename': '/lib/modules/0.8.15/extra/vanilla3d.ko',
 
56
        'license': 'PayMe',
 
57
        'description': 'nonfree, replacement graphics driver for vanilla',
 
58
        'alias': 'pci:v00001001d00003D*sv*sd*bc03sc*i*'
 
59
    },
 
60
    'spam': {
 
61
        'filename': '/lib/modules/0.8.15/extra/spam.ko',
 
62
        'license': 'GPL',
 
63
        'description': 'free mystical module without modaliases',
 
64
    },
 
65
    'dullstd': {
 
66
        'filename': '/lib/modules/0.8.15/standard/dullstd.ko',
 
67
        'license': 'GPL',
 
68
        'description': 'standard module which should be ignored for detection',
 
69
        'alias': 'pci:v0000DEAFd*sv*sd*bc99sc*i*'
 
70
    },
 
71
}
 
72
 
 
73
fake_sys = {
 
74
    # graphics card, can use vanilla or vanilla3d, defaulting to free driver
 
75
    'pci0000:00/0000:00:11.2': {
 
76
        'modalias': 'pci:v00001001d00003D01sv00001234sd00000001bc03sc00i00',
 
77
        'driver': '../../../bus/pci/drivers/vanilla',
 
78
        'module': 'vanilla',
 
79
    },
 
80
 
 
81
    # pretend that we have two devices using vanilla, to check for duplication
 
82
    # of handlers
 
83
    'pci0000:02/0000:00:03.4': {
 
84
        'modalias': 'pci:v00001001d00003D01sv00001234sd00000001bc03sc00i00',
 
85
        'driver': '../../../bus/pci/drivers/vanilla',
 
86
        'module': 'vanilla',
 
87
    },
 
88
 
 
89
    # something that uses a statically built-in kernel driver
 
90
    'pci0000:00/0000:00:22.3': {
 
91
        'modalias': 'pci:v00003456d00000001sv00000000sd00000000bc09sc23i00',
 
92
        'driver': '../../../bus/pci/drivers/southbridge',
 
93
    },
 
94
 
 
95
    # wifi which can use mint, but not enabled
 
96
    'pci0000:00/0000:01:01.0': {
 
97
        'modalias': 'pci:v0000AAAAd000012AAsv00000000sdDEADBEEFbc02sc80i00',
 
98
    },
 
99
 
 
100
    # unknown piece of hardware
 
101
    'pci0000:01/0000:05:05.0': {
 
102
        'modalias': 'pci:v0000FFF0d00000001sv00000000sd00000000bc06sc01i01',
 
103
    },
 
104
 
 
105
    # uninteresting standard component
 
106
    'pci0000:02/0000:01:02.3': {
 
107
        'modalias': 'pci:v0000DEAFd00009999sv00000000sd00000000bc99sc00i00',
 
108
        'driver': '../../../bus/pci/drivers/dullstd',
 
109
        'module': 'dullstd',
 
110
    }
 
111
}
 
112
 
 
113
fake_db = {
 
114
    # vanilla3d option for the graphics card
 
115
    HardwareID('modalias', 'pci:v00001001d00003D*sv*sd*bc03sc*i*'): {
 
116
        ('Foonux', '42'): [DriverID(handler='VanillaGfxHandler')],
 
117
        ('Foonux', '41'): [DriverID(handler='IShallNotExist')],
 
118
        ('RedSock', '2.0'): [DriverID(handler='Vanilla3DHandler',
 
119
            repository='http://nonfree.redsock.com/addons')]
 
120
    },
 
121
 
 
122
    # driver for the unknown piece of hardware; test multiple handlers here
 
123
    HardwareID('modalias', 'pci:v0000FFF0d0000*sv*sd*bc06sc01i*'): {
 
124
        ('Foonux', '42'): [
 
125
            DriverID(handler='KernelModuleHandler', module='spam'),
 
126
            DriverID(handler='KernelModuleHandler', module='mint', xopt1='unbreak')
 
127
        ],
 
128
    },
 
129
 
 
130
    # unknown driver
 
131
    HardwareID('pci', '9876/FEDC'): {
 
132
        ('Foonux', '42'): [DriverID(handler='BogusHandler')],
 
133
        ('Oobuntu', 'Eccentric Emu'): [DriverID(handler='BogusHandler')],
 
134
    }
 
135
}
 
136
 
 
137
fake_pkginfo = {
 
138
    'mesa-vanilla': {
 
139
        'description': ('X.org libraries for the Vanilla 3D driver', 
 
140
            'This package provides optimized Mesa libraries for the Vanilla '
 
141
            'graphics cards.'),
 
142
        'free': False,
 
143
    },
 
144
    'mesa-std': {
 
145
        'description': ('standard system mesa libraries',
 
146
            'default mesa libs for free drivers'),
 
147
        'free': True,
 
148
    },
 
149
    'coreutils': {
 
150
        'description': ('unrelated system package',
 
151
            'This package should always be installed.'),
 
152
        'free': True,
 
153
    }
 
154
}
 
155
 
 
156
#-------------------------------------------------------------------#
 
157
 
 
158
class TestOSLib(OSLib):
 
159
    '''Test suite implementation of OSLib'''
 
160
 
 
161
    def __init__(self):
 
162
        OSLib.__init__(self)
 
163
 
 
164
        # set up a fake environment
 
165
        self.workdir = tempfile.mkdtemp()
 
166
        atexit.register(shutil.rmtree, self.workdir)
 
167
        self._make_modinfo()
 
168
        self._make_proc_modules()
 
169
        self._make_modprobe()
 
170
        self._make_modalias()
 
171
        self._make_sys()
 
172
        self._make_xorg_conf()
 
173
 
 
174
        self.module_blacklist_file = os.path.join(self.workdir, 'module-blacklist')
 
175
 
 
176
        self.handler_dir = os.path.join(self.workdir, 'handlers')
 
177
        os.mkdir(self.handler_dir)
 
178
        self.check_cache = os.path.join(self.workdir, 'check_cache')
 
179
        self.backup_dir = os.path.join(self.workdir, 'backup')
 
180
        os.mkdir(self.backup_dir)
 
181
 
 
182
        self.installed_packages = set(['mesa-std', 'coreutils'])
 
183
 
 
184
        self.reboot_flag = False
 
185
 
 
186
    def _make_modinfo(self):
 
187
        '''Create a dummy modinfo program which outputs the fake_modinfo data
 
188
        and set self.modinfo_path.
 
189
        
 
190
        Note that this fake modinfo only supports one module argument, not
 
191
        several (as the original modinfo), and no options.'''
 
192
 
 
193
        os.mkdir(os.path.join(self.workdir, 'bin'))
 
194
        self.modinfo_path = os.path.join(self.workdir, 'bin', 'modinfo')
 
195
        mi = open(self.modinfo_path, 'w')
 
196
        mi.write('''#!/usr/bin/python
 
197
import sys
 
198
 
 
199
data = %s
 
200
 
 
201
if len(sys.argv) != 2:
 
202
    print >> sys.stderr, 'Usage: modinfo module'
 
203
    sys.exit(0)
 
204
 
 
205
m = sys.argv[1]
 
206
if m in data:
 
207
    attrs = data[m].keys()
 
208
    attrs.sort()
 
209
    for k in attrs:
 
210
        if hasattr(data[m][k], 'isspace'):
 
211
            print '%%-16s%%s' %% (k + ':', data[m][k])
 
212
        else:
 
213
            for i in data[m][k]:
 
214
                print '%%-16s%%s' %% (k + ':', i)
 
215
else:
 
216
    print >> sys.stderr, 'modinfo: could not find module', m
 
217
    sys.exit(1)
 
218
 
 
219
''' % repr(fake_modinfo))
 
220
        mi.close()
 
221
        os.chmod(self.modinfo_path, 0755)
 
222
 
 
223
    def _make_modprobe(self):
 
224
        '''Create a dummy modprobe and set self.modprobe_path.'''
 
225
 
 
226
        self.modprobe_path = os.path.join(self.workdir, 'bin', 'modprobe')
 
227
        mp = open(self.modprobe_path, 'w')
 
228
        mp.write('''#!/usr/bin/python
 
229
import sys
 
230
 
 
231
modinfo = %s
 
232
proc_modules = %s
 
233
 
 
234
if len(sys.argv) != 2:
 
235
    print >> sys.stderr, 'Usage: modprobe module'
 
236
    sys.exit(1)
 
237
 
 
238
m = sys.argv[1]
 
239
if m in modinfo:
 
240
    if m not in open(proc_modules).read():
 
241
        print >> open(proc_modules, 'a'), '%%s 11111 2 - Live 0xbeefbeef' %% m
 
242
else:
 
243
    print >> sys.stderr, 'FATAL: Module %%s not found.' %% m
 
244
    sys.exit(1)
 
245
''' % (repr(fake_modinfo), repr(self.proc_modules)))
 
246
 
 
247
        mp.close()
 
248
        os.chmod(self.modprobe_path, 0755)
 
249
        
 
250
    def _make_sys(self):
 
251
        '''Create a dummy /sys tree from fake_sys and set self.sys_dir.'''
 
252
 
 
253
        self.sys_dir = os.path.join(self.workdir, 'sys')
 
254
 
 
255
        for pcipath, info in fake_sys.iteritems():
 
256
            # create /sys/device entry
 
257
            device_dir = os.path.join(self.sys_dir, 'devices', pcipath)
 
258
            os.makedirs(device_dir)
 
259
            open(os.path.join(device_dir, 'modalias'), 'w').write(info['modalias'])
 
260
 
 
261
            # create driver dir and symlink to device, if existing
 
262
            if 'driver' not in info:
 
263
                continue
 
264
            driver_dir = os.path.join(device_dir, info['driver'])
 
265
            try:
 
266
                os.makedirs(driver_dir)
 
267
            except OSError:
 
268
                pass
 
269
            os.symlink(info['driver'], os.path.join(device_dir, 'driver'))
 
270
            os.symlink(device_dir, os.path.join(driver_dir,
 
271
                os.path.basename(pcipath)))
 
272
 
 
273
            # create module dir and symlink to driver, if existing
 
274
            if 'module' not in info:
 
275
                continue
 
276
            module_dir = os.path.join(self.workdir, 'sys', 'module', info['module'])
 
277
            try:
 
278
                os.makedirs(os.path.join(module_dir, 'drivers'))
 
279
            except OSError:
 
280
                pass
 
281
            if not os.path.islink(os.path.join(driver_dir, 'module')):
 
282
                os.symlink(module_dir, os.path.join(driver_dir, 'module'))
 
283
            driver_comp = info['driver'].split('/')
 
284
            mod_driver_link = os.path.join(module_dir, 'drivers',
 
285
                '%s:%s' % (driver_comp[-3], driver_comp[-1]))
 
286
            if not os.path.islink(mod_driver_link):
 
287
                os.symlink(driver_dir, mod_driver_link)
 
288
 
 
289
    def _make_proc_modules(self):
 
290
        '''Create a dummy /proc/modules and set self.proc_modules.'''
 
291
 
 
292
        self.proc_modules = os.path.join(self.workdir, 'proc', 'modules')
 
293
        if not os.path.isdir(os.path.dirname(self.proc_modules)):
 
294
            os.mkdir(os.path.dirname(self.proc_modules))
 
295
        mods = set()
 
296
        for info in fake_sys.itervalues():
 
297
            try:
 
298
                mods.add(info['module'])
 
299
            except KeyError:
 
300
                pass
 
301
 
 
302
        f = open(self.proc_modules, 'w')
 
303
        for m in mods:
 
304
            print >> f, '%s 12345 0 - Live 0xdeadbeef' % m
 
305
        f.close()
 
306
 
 
307
    def _make_modalias(self):
 
308
        '''Create a dummy modules.alias and set self.modaliases
 
309
        appropriately.'''
 
310
 
 
311
        # prepare one fake kernel modules.alias and an override directory
 
312
        self.modaliases = [
 
313
            os.path.join(self.workdir, 'kernelmods', 'modules.alias'),
 
314
            os.path.join(self.workdir, 'modalias-overrides'),
 
315
            '/nonexisting', # should not stumble over those
 
316
        ]
 
317
        os.mkdir(os.path.dirname(self.modaliases[0]))
 
318
        os.mkdir(self.modaliases[1])
 
319
 
 
320
        f = open(self.modaliases[0], 'w')
 
321
        print >> f, '# Aliases extracted from modules themselves.'
 
322
        for mod in sorted(fake_modinfo.keys()):
 
323
            aliases = fake_modinfo[mod].get('alias', [])
 
324
            if hasattr(aliases, 'isspace'):
 
325
                print >> f, 'alias %s %s' % (aliases, mod)
 
326
            else:
 
327
                for a in aliases:
 
328
                    print >> f, 'alias %s %s' % (a, mod)
 
329
        f.close()
 
330
 
 
331
    def _make_xorg_conf(self):
 
332
        '''Create a dummy xorg.conf and set self.xorg_conf_path appropriately.'''
 
333
 
 
334
        self.xorg_conf_path = os.path.join(self.workdir, 'xorg.conf')
 
335
        f = open(self.xorg_conf_path, 'w')
 
336
        f.write('''# xorg.conf (xorg X Window System server configuration file)
 
337
 
 
338
Section "InputDevice"
 
339
        Identifier      "Generic Keyboard"
 
340
        Driver          "kbd"
 
341
        Option          "CoreKeyboard"
 
342
        Option          "XkbRules"      "xorg"
 
343
        Option          "XkbModel"      "pc105"
 
344
        Option          "XkbLayout"     "us"
 
345
EndSection
 
346
 
 
347
Section "Device"
 
348
        Identifier      "Standard ice cream graphics"
 
349
        Driver          "vanilla"
 
350
EndSection
 
351
 
 
352
Section "Monitor"
 
353
        Identifier      "My Monitor"
 
354
        Option          "DPMS"
 
355
        HorizSync       30-70
 
356
        VertRefresh     50-160
 
357
EndSection
 
358
 
 
359
Section "Screen"
 
360
        Identifier      "Default Screen"
 
361
        Device          "Standard ice cream graphics"
 
362
        Monitor         "My Monitor"
 
363
        DefaultDepth    24
 
364
EndSection
 
365
 
 
366
Section "ServerLayout"
 
367
        Identifier      "Default Layout"
 
368
        Screen          "Default Screen"
 
369
        InputDevice     "Generic Keyboard"
 
370
EndSection
 
371
''')
 
372
        f.close()
 
373
 
 
374
    def _get_os_version(self):
 
375
        self.os_vendor = 'Foonux'
 
376
        self.os_version = '42'
 
377
 
 
378
    def ignored_modules(self):
 
379
        return set(['dullstd'])
 
380
 
 
381
    def package_description(self, package):
 
382
        '''Return a tupe (short_description, long_description) for given
 
383
        package.
 
384
        
 
385
        This should raise a ValueError if the package is not available.'''
 
386
 
 
387
        try:
 
388
            return fake_pkginfo[package]['description']
 
389
        except KeyError:
 
390
            raise ValueError, 'no such package'
 
391
 
 
392
    def is_package_free(self, package):
 
393
        '''Return if given package is free software.'''
 
394
 
 
395
        return fake_pkginfo[package]['free']
 
396
 
 
397
    def package_installed(self, package):
 
398
        '''Return if the given package is installed.'''
 
399
 
 
400
        return package in self.installed_packages
 
401
 
 
402
    def install_package(self, package, ui):
 
403
        '''Install the given package.
 
404
 
 
405
        The current UI object is passed as well, in case package installation
 
406
        wants to do some callbacks/confirmation dialogs/queries.
 
407
 
 
408
        If this succeeds, subsequent package_installed(package) calls must
 
409
        return True.'''
 
410
 
 
411
        assert package in fake_pkginfo
 
412
        self.installed_packages.add(package)
 
413
 
 
414
    def remove_package(self, package, ui):
 
415
        '''Uninstall the given package.
 
416
 
 
417
        The current UI object is passed as well, in case package installation
 
418
        wants to do some callbacks/confirmation dialogs/queries.
 
419
 
 
420
        If this succeeds, subsequent package_installed(package) calls must
 
421
        return False.'''
 
422
 
 
423
        assert package in fake_pkginfo
 
424
        self.installed_packages.remove(package)
 
425
 
 
426
    def ui_notify_reboot(self, ui):
 
427
        '''Indicate that the user should do a reboot to activate changes (such
 
428
        as changing an X.org video driver).'''
 
429
 
 
430
        self.reboot_flag = True
 
431
 
 
432
    def pop_reboot_flag(self):
 
433
        result = self.reboot_flag
 
434
        self.reboot_flag = False
 
435
        return result
 
436
 
 
437
#-------------------------------------------------------------------#
 
438
 
 
439
class TestDriverDB(DriverDB):
 
440
    '''Test suite implementation of DriverDB'''
 
441
 
 
442
    def query(self, hwid):
 
443
        return fake_db.get(hwid, {}).get(
 
444
            (OSLib.inst.os_vendor, OSLib.inst.os_version), [])
 
445
 
 
446
#-------------------------------------------------------------------#
 
447
 
 
448
class TestUI(AbstractUI):
 
449
    def __init__(self):
 
450
        AbstractUI.__init__(self)
 
451
        self.error_stack = []
 
452
        self.confirm_response = None
 
453
        self.notification_stack = []
 
454
        self.main_loop_active = False
 
455
        self.cur_download = [None, None, None] # (url, size, total)
 
456
        self.cancel_download = False # whether to cancel the next download at 30%
 
457
 
 
458
    def convert_keybindings(self, str):
 
459
        return str
 
460
 
 
461
    def ui_init(self):
 
462
        pass
 
463
 
 
464
    def ui_main_loop(self):
 
465
        '''Main loop for the user interface.
 
466
        
 
467
        This should return if the user wants to quit the program, and return
 
468
        the exit code.'''
 
469
 
 
470
        self.main_loop_active = True
 
471
 
 
472
    def error_message(self, title, text):
 
473
        '''Show an error message box with given title and text.'''
 
474
 
 
475
        self.error_stack.append((title, text))
 
476
 
 
477
    def pop_error(self):
 
478
        '''Return the last error message (title, text) tuple.'''
 
479
 
 
480
        return self.error_stack.pop()
 
481
 
 
482
    def confirm_action(self, title, text, subtext = None, action=None):
 
483
        assert self.confirm_response is not None, 'must set confirm_response'
 
484
 
 
485
        self.last_confirm_title = title
 
486
        self.last_confirm_text = text
 
487
        self.last_confirm_subtext = subtext
 
488
        self.last_confirm_action = action
 
489
 
 
490
        r = self.confirm_response
 
491
        self.confirm_response = None
 
492
 
 
493
        return r
 
494
 
 
495
    def ui_notification(self, title, text):
 
496
        self.notification_stack.append((title, text))
 
497
 
 
498
    def pop_notification(self):
 
499
        '''Return the last notification (title, text) tuple.'''
 
500
 
 
501
        return self.notification_stack.pop()
 
502
 
 
503
    def ui_download_start(self, url, total_size):
 
504
        '''Create a progress dialog for a download of given URL.
 
505
 
 
506
        total_size specifes the number of bytes to download, or -1 if it cannot
 
507
        be determined. In this case the dialog should display an indeterminated
 
508
        progress bar (bouncing back and forth).'''
 
509
 
 
510
        assert url
 
511
        self.cur_download = [url, 0, total_size]
 
512
 
 
513
    def ui_download_progress(self, current_size, total_size):
 
514
        '''Update download progress of current download.
 
515
        
 
516
        This should return True to cancel the current download, and False
 
517
        otherwise.'''
 
518
 
 
519
        assert self.cur_download[0]
 
520
        assert self.cur_download[1] is not None
 
521
        assert self.cur_download[2] is not None
 
522
        assert current_size > self.cur_download[1]
 
523
        assert total_size == self.cur_download[2]
 
524
 
 
525
        self.cur_download[1] = current_size
 
526
 
 
527
        return self.cancel_download and float(current_size)/total_size >= 0.3
 
528
 
 
529
    def ui_download_finish(self):
 
530
        '''Close the current download progress dialog.'''
 
531
 
 
532
        self.cancel_download = False
 
533
 
 
534
#-------------------------------------------------------------------#
 
535
# TestOSLib consistency tests
 
536
 
 
537
import unittest, subprocess
 
538
 
 
539
class TestOSLibConsistencyTest(unittest.TestCase):
 
540
    def test_modinfo_output(self):
 
541
        '''test suite's modinfo output for known modules'''
 
542
        
 
543
        m = subprocess.Popen([OSLib.inst.modinfo_path, 'vanilla'],
 
544
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
545
        (out, err) = m.communicate()
 
546
        self.assertEqual(err, '')
 
547
        self.assertEqual(out, '''alias:          pci:v00001001d*sv*sd*bc03sc*i*
 
548
description:    free module with available hardware, graphics card
 
549
filename:       /lib/modules/0.8.15/foo/vanilla.ko
 
550
license:        GPL
 
551
''')
 
552
        self.assertEqual(m.returncode, 0)
 
553
 
 
554
        m = subprocess.Popen([OSLib.inst.modinfo_path, 'chocolate'],
 
555
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
556
        (out, err) = m.communicate()
 
557
        self.assertEqual(err, '')
 
558
        self.assertEqual(m.returncode, 0)
 
559
        self.assert_('chocolate.ko' in out)
 
560
        # both modaliases
 
561
        self.assert_('alias:          pci:v00001002d00000001sv*' in out)
 
562
        self.assert_('alias:          pci:v00001002d00000002sv*' in out)
 
563
 
 
564
    def test_modinfo_error(self):
 
565
        '''test suite's modinfo output for unknown modules and invalid invocation'''
 
566
        
 
567
        m = subprocess.Popen([OSLib.inst.modinfo_path, 'nonexisting'],
 
568
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
569
        (out, err) = m.communicate()
 
570
        self.assertEqual(out, '')
 
571
        self.assert_('could not find module nonexisting' in err)
 
572
        self.assertEqual(m.returncode, 1)
 
573
 
 
574
        m = subprocess.Popen([OSLib.inst.modinfo_path],
 
575
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
576
        (out, err) = m.communicate()
 
577
        self.assertEqual(out, '')
 
578
        self.assert_('Usage' in err)
 
579
        self.assertEqual(m.returncode, 0)
 
580
 
 
581
    def test_modprobe(self):
 
582
        '''test suite's modprobe works'''
 
583
 
 
584
        # help output
 
585
        m = subprocess.Popen([OSLib.inst.modprobe_path],
 
586
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
587
        (out, err) = m.communicate()
 
588
        self.assertEqual(out, '')
 
589
        self.assert_('Usage' in err)
 
590
        self.assertEqual(m.returncode, 1)
 
591
 
 
592
        # invalid module
 
593
        m = subprocess.Popen([OSLib.inst.modprobe_path, 'nonexisting'],
 
594
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
595
        (out, err) = m.communicate()
 
596
        self.assertEqual(out, '')
 
597
        self.assert_('FATAL' in err)
 
598
        self.assert_('nonexisting' in err)
 
599
        self.assertEqual(m.returncode, 1)
 
600
 
 
601
        # valid module
 
602
        orig_content = open(OSLib.inst.proc_modules).read()
 
603
        try:
 
604
            self.failIf('cherry' in orig_content)
 
605
            m = subprocess.Popen([OSLib.inst.modprobe_path, 'cherry'],
 
606
                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
607
            (out, err) = m.communicate()
 
608
            self.assertEqual(out, '')
 
609
            self.assertEqual(err, '')
 
610
            self.assertEqual(m.returncode, 0)
 
611
            self.assert_('cherry' in open(OSLib.inst.proc_modules).read())
 
612
        finally:
 
613
            open(OSLib.inst.proc_modules, 'w').write(orig_content)
 
614
 
 
615
    def test_sys_symlinks(self):
 
616
        '''all symlinks in fake /sys are valid'''
 
617
 
 
618
        for path, dirs, files in os.walk(os.path.join(OSLib.inst.workdir, 'sys')):
 
619
            for f in files+dirs:
 
620
                p = os.path.join(path, f)
 
621
                if os.path.islink(p):
 
622
                    rp = os.path.realpath(p)
 
623
                    self.assert_(os.path.exists(rp), 
 
624
                        'symbolic link %s -> %s is valid' % (p, rp))
 
625
 
 
626
    def test_module_aliases_file(self):
 
627
        '''module.aliases correctness'''
 
628
 
 
629
        self.assertEqual(open(os.path.join(OSLib.inst.workdir, 'kernelmods',
 
630
            'modules.alias')).read(), 
 
631
            '''# Aliases extracted from modules themselves.
 
632
alias pci:v0000EEEEd*sv*sd*bc02sc80i* cherry
 
633
alias pci:v00001002d00000001sv*bc*sc*i* chocolate
 
634
alias pci:v00001002d00000002sv*sd*bc*sc*i* chocolate
 
635
alias pci:v0000DEAFd*sv*sd*bc99sc*i* dullstd
 
636
alias pci:v0000AAAAd000012*sv*sd*bc02sc*i* mint
 
637
alias pci:v00001001d*sv*sd*bc03sc*i* vanilla
 
638
alias pci:v00001001d00003D*sv*sd*bc03sc*i* vanilla3d
 
639
''')
 
640
 
 
641
    def test_proc_modules(self):
 
642
        '''/proc/modules correctness'''
 
643
 
 
644
        m = open(OSLib.inst.proc_modules).read()
 
645
        self.assertEqual(len(m.splitlines()), 2)
 
646
        self.assert_('dullstd' in m)
 
647
        self.assert_('vanilla' in m)
 
648
        self.failIf('vanilla3d' in m)
 
649
        self.failIf('cherry' in m)
 
650
        self.failIf('mint' in m)
 
651
 
 
652
#-------------------------------------------------------------------#
 
653
# test handlers
 
654
 
 
655
h_avail_mod = '''
 
656
from jockey.handlers import KernelModuleHandler
 
657
class AvailMod(KernelModuleHandler):
 
658
    def __init__(self, ui):
 
659
        KernelModuleHandler.__init__(self, ui, 'vanilla',
 
660
            description='Test suite: available kernel module')
 
661
    def available(self):
 
662
        return True
 
663
'''
 
664
 
 
665
h_notavail_mod = '''
 
666
from jockey.handlers import KernelModuleHandler
 
667
class NotAvailMod(KernelModuleHandler):
 
668
    def __init__(self, ui):
 
669
        KernelModuleHandler.__init__(self, ui, 'chocolate',
 
670
            description='Test suite: non-available kernel module')
 
671
    def available(self):
 
672
        return False
 
673
'''
 
674
 
 
675
h_nodetectmod = '''
 
676
class NoDetectMod(jockey.handlers.KernelModuleHandler):
 
677
    def __init__(self, ui):
 
678
        jockey.handlers.KernelModuleHandler.__init__(self, ui, 'spam',
 
679
            description='Test suite: non-detectable kernel module')
 
680
'''
 
681
 
 
682
# complete .py file contents with above three handlers
 
683
h_availability_py = 'import jockey.handlers\n%s\n%s\n%s\n' % (
 
684
    h_avail_mod, h_notavail_mod, h_nodetectmod)
 
685
 
 
686
h_nochangemod = '''
 
687
class NoChangeMod(jockey.handlers.KernelModuleHandler):
 
688
    def __init__(self, ui):
 
689
        jockey.handlers.KernelModuleHandler.__init__(self, ui, 'vanilla')
 
690
    def available(self):
 
691
        return True
 
692
    def can_change(self):
 
693
        return 'I must live'
 
694
'''
 
695
 
 
696
#-------------------------------------------------------------------#
 
697
# other globals
 
698
 
 
699
log = None