/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2009, 2010, 2011 Canonical Ltd
4584.3.21 by Martin Pool
Start adding tests for apport
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
17
"""A collection of commonly used 'Features' to optionally run tests.
18
"""
5241.2.1 by Robert Collins
Merge up from 2.0/2.1:
19
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
20
from __future__ import absolute_import
21
5036.3.8 by Parth Malwankar
closed review comments from vila
22
import os
6060.1.1 by John Arbash Meinel
import subprocess in 'bzrlib.tests.features' so that certain features can properly probe.
23
import subprocess
5036.3.8 by Parth Malwankar
closed review comments from vila
24
import stat
5609.47.1 by Alexander Belchenko
Win32Feature
25
import sys
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
26
import tempfile
4584.3.21 by Martin Pool
Start adding tests for apport
27
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
28
from .. import (
5321.2.1 by Vincent Ladeuil
Fix style issues, including vertical spaces, lines too long and multi lines imports.
29
    osutils,
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
30
    symbol_versioning,
5321.2.1 by Vincent Ladeuil
Fix style issues, including vertical spaces, lines too long and multi lines imports.
31
    )
4913.2.19 by John Arbash Meinel
Compatibly rename ApportFeature to features.apport.
32
33
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
34
class Feature(object):
35
    """An operating system Feature."""
36
37
    def __init__(self):
38
        self._available = None
39
40
    def available(self):
41
        """Is the feature available?
42
43
        :return: True if the feature is available.
44
        """
45
        if self._available is None:
46
            self._available = self._probe()
47
        return self._available
48
49
    def _probe(self):
50
        """Implement this method in concrete features.
51
52
        :return: True if the feature is available.
53
        """
54
        raise NotImplementedError
55
56
    def __str__(self):
57
        if getattr(self, 'feature_name', None):
58
            return self.feature_name()
59
        return self.__class__.__name__
60
61
62
class _SymlinkFeature(Feature):
63
64
    def _probe(self):
65
        return osutils.has_symlinks()
66
67
    def feature_name(self):
68
        return 'symlinks'
69
70
SymlinkFeature = _SymlinkFeature()
71
72
73
class _HardlinkFeature(Feature):
74
75
    def _probe(self):
76
        return osutils.has_hardlinks()
77
78
    def feature_name(self):
79
        return 'hardlinks'
80
81
HardlinkFeature = _HardlinkFeature()
82
83
84
class _OsFifoFeature(Feature):
85
86
    def _probe(self):
87
        return getattr(os, 'mkfifo', None)
88
89
    def feature_name(self):
90
        return 'filesystem fifos'
91
92
OsFifoFeature = _OsFifoFeature()
93
94
95
class _UnicodeFilenameFeature(Feature):
96
    """Does the filesystem support Unicode filenames?"""
97
98
    def _probe(self):
99
        try:
100
            # Check for character combinations unlikely to be covered by any
101
            # single non-unicode encoding. We use the characters
102
            # - greek small letter alpha (U+03B1) and
103
            # - braille pattern dots-123456 (U+283F).
104
            os.stat(u'\u03b1\u283f')
105
        except UnicodeEncodeError:
106
            return False
107
        except (IOError, OSError):
108
            # The filesystem allows the Unicode filename but the file doesn't
109
            # exist.
110
            return True
111
        else:
112
            # The filesystem allows the Unicode filename and the file exists,
113
            # for some reason.
114
            return True
115
116
UnicodeFilenameFeature = _UnicodeFilenameFeature()
117
118
119
class _CompatabilityThunkFeature(Feature):
120
    """This feature is just a thunk to another feature.
121
122
    It issues a deprecation warning if it is accessed, to let you know that you
123
    should really use a different feature.
124
    """
125
126
    def __init__(self, dep_version, module, name,
127
                 replacement_name, replacement_module=None):
128
        super(_CompatabilityThunkFeature, self).__init__()
129
        self._module = module
130
        if replacement_module is None:
131
            replacement_module = module
132
        self._replacement_module = replacement_module
133
        self._name = name
134
        self._replacement_name = replacement_name
135
        self._dep_version = dep_version
136
        self._feature = None
137
138
    def _ensure(self):
139
        if self._feature is None:
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
140
            from breezy import pyutils
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
141
            depr_msg = self._dep_version % ('%s.%s'
142
                                            % (self._module, self._name))
143
            use_msg = ' Use %s.%s instead.' % (self._replacement_module,
144
                                               self._replacement_name)
6325.3.1 by Vincent Ladeuil
Give meaningful deprecation warnings for deprecated test features
145
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning,
146
                                   stacklevel=5)
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
147
            # Import the new feature and use it as a replacement for the
148
            # deprecated one.
149
            self._feature = pyutils.get_named_object(
150
                self._replacement_module, self._replacement_name)
151
152
    def _probe(self):
153
        self._ensure()
154
        return self._feature._probe()
155
156
157
class ModuleAvailableFeature(Feature):
158
    """This is a feature than describes a module we want to be available.
159
160
    Declare the name of the module in __init__(), and then after probing, the
161
    module will be available as 'self.module'.
162
163
    :ivar module: The module if it is available, else None.
164
    """
165
166
    def __init__(self, module_name):
167
        super(ModuleAvailableFeature, self).__init__()
168
        self.module_name = module_name
169
170
    def _probe(self):
5642.4.3 by Vincent Ladeuil
Rework the fix taking mgz remarks into account and rebasing against trunk.
171
        sentinel = object()
172
        module = sys.modules.get(self.module_name, sentinel)
173
        if module is sentinel:
174
            try:
175
                self._module = __import__(self.module_name, {}, {}, [''])
176
                return True
177
            except ImportError:
178
                return False
179
        else:
180
            self._module = module
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
181
            return True
182
183
    @property
184
    def module(self):
185
        if self.available():
186
            return self._module
187
        return None
188
189
    def feature_name(self):
190
        return self.module_name
191
192
6703.1.1 by Jelmer Vernooij
Add a ``PluginLoadedFeature``.
193
class PluginLoadedFeature(Feature):
194
    """Check whether a plugin with specific name is loaded.
195
196
    This is different from ModuleAvailableFeature, because
197
    plugins can be available but explicitly disabled
198
    (e.g. through BRZ_DISABLE_PLUGINS=blah).
199
200
    :ivar plugin_name: The name of the plugin
201
    """
202
203
    def __init__(self, plugin_name):
204
        super(PluginLoadedFeature, self).__init__()
205
        self.plugin_name = plugin_name
206
207
    def _probe(self):
208
        import breezy
209
        return self.plugin_name in breezy.global_state.plugins
210
211
    @property
212
    def plugin(self):
6703.2.1 by Jelmer Vernooij
use breezy.global_state.plugins rather than importing, as mgz suggested.
213
        import breezy
214
        return breezy.global_state.plugins.get(self.plugin_name)
6703.1.1 by Jelmer Vernooij
Add a ``PluginLoadedFeature``.
215
216
    def feature_name(self):
6703.1.2 by Jelmer Vernooij
Change feature name to '... plugin'.
217
        return '%s plugin' % self.plugin_name
6703.1.1 by Jelmer Vernooij
Add a ``PluginLoadedFeature``.
218
219
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
220
class _HTTPSServerFeature(Feature):
221
    """Some tests want an https Server, check if one is available.
222
223
    Right now, the only way this is available is under python2.6 which provides
224
    an ssl module.
225
    """
226
227
    def _probe(self):
228
        try:
229
            import ssl
230
            return True
231
        except ImportError:
232
            return False
233
234
    def feature_name(self):
235
        return 'HTTPSServer'
236
237
238
HTTPSServerFeature = _HTTPSServerFeature()
239
240
241
class _ByteStringNamedFilesystem(Feature):
242
    """Is the filesystem based on bytes?"""
243
244
    def _probe(self):
245
        if os.name == "posix":
246
            return True
247
        return False
248
249
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
250
251
252
class _UTF8Filesystem(Feature):
253
    """Is the filesystem UTF-8?"""
254
255
    def _probe(self):
256
        if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
257
            return True
258
        return False
259
260
UTF8Filesystem = _UTF8Filesystem()
261
262
263
class _BreakinFeature(Feature):
264
    """Does this platform support the breakin feature?"""
265
266
    def _probe(self):
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
267
        from breezy import breakin
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
268
        if breakin.determine_signal() is None:
269
            return False
270
        if sys.platform == 'win32':
271
            # Windows doesn't have os.kill, and we catch the SIGBREAK signal.
272
            # We trigger SIGBREAK via a Console api so we need ctypes to
273
            # access the function
274
            try:
275
                import ctypes
276
            except OSError:
277
                return False
278
        return True
279
280
    def feature_name(self):
281
        return "SIGQUIT or SIGBREAK w/ctypes on win32"
282
283
284
BreakinFeature = _BreakinFeature()
285
286
287
class _CaseInsCasePresFilenameFeature(Feature):
288
    """Is the file-system case insensitive, but case-preserving?"""
289
290
    def _probe(self):
291
        fileno, name = tempfile.mkstemp(prefix='MixedCase')
292
        try:
293
            # first check truly case-preserving for created files, then check
294
            # case insensitive when opening existing files.
295
            name = osutils.normpath(name)
296
            base, rel = osutils.split(name)
297
            found_rel = osutils.canonical_relpath(base, name)
298
            return (found_rel == rel
299
                    and os.path.isfile(name.upper())
300
                    and os.path.isfile(name.lower()))
301
        finally:
302
            os.close(fileno)
303
            os.remove(name)
304
305
    def feature_name(self):
306
        return "case-insensitive case-preserving filesystem"
307
308
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
309
310
311
class _CaseInsensitiveFilesystemFeature(Feature):
312
    """Check if underlying filesystem is case-insensitive but *not* case
313
    preserving.
314
    """
315
    # Note that on Windows, Cygwin, MacOS etc, the file-systems are far
316
    # more likely to be case preserving, so this case is rare.
317
318
    def _probe(self):
319
        if CaseInsCasePresFilenameFeature.available():
320
            return False
321
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
322
        from breezy import tests
6280.1.1 by Martin Pool
Restore old name for bzrlib.tests.feature to unbreak bzr fastimport etc
323
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
324
        if tests.TestCaseWithMemoryTransport.TEST_ROOT is None:
325
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
326
            tests.TestCaseWithMemoryTransport.TEST_ROOT = root
327
        else:
328
            root = tests.TestCaseWithMemoryTransport.TEST_ROOT
329
        tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
330
            dir=root)
331
        name_a = osutils.pathjoin(tdir, 'a')
332
        name_A = osutils.pathjoin(tdir, 'A')
333
        os.mkdir(name_a)
334
        result = osutils.isdir(name_A)
6280.1.2 by Martin Pool
Fix NameError
335
        tests._rmtree_temp_dir(tdir)
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
336
        return result
337
338
    def feature_name(self):
339
        return 'case-insensitive filesystem'
340
341
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
342
343
344
class _CaseSensitiveFilesystemFeature(Feature):
345
346
    def _probe(self):
347
        if CaseInsCasePresFilenameFeature.available():
348
            return False
349
        elif CaseInsensitiveFilesystemFeature.available():
350
            return False
351
        else:
352
            return True
353
354
    def feature_name(self):
355
        return 'case-sensitive filesystem'
356
357
# new coding style is for feature instances to be lowercase
358
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
359
360
361
class _NotRunningAsRoot(Feature):
4797.70.1 by Vincent Ladeuil
Skip chmodbits dependent tests when running as root
362
363
    def _probe(self):
364
        try:
365
            uid = os.getuid()
366
        except AttributeError:
367
            # If there is no uid, chances are there is no root either
368
            return True
369
        return uid != 0
370
371
    def feature_name(self):
372
        return 'Not running as root'
373
374
375
not_running_as_root = _NotRunningAsRoot()
5448.5.9 by Vincent Ladeuil
Make the test depends on a feature so it's skipped if meliae is not installed
376
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
377
apport = ModuleAvailableFeature('apport')
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
378
gpg = ModuleAvailableFeature('gpg')
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
379
lzma = ModuleAvailableFeature('lzma')
6091.2.2 by Max Bowsher
Per jam's review comments, get rid of features.meliae_feature, which is new in
380
meliae = ModuleAvailableFeature('meliae.scanner')
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
381
paramiko = ModuleAvailableFeature('paramiko')
382
pywintypes = ModuleAvailableFeature('pywintypes')
383
subunit = ModuleAvailableFeature('subunit')
5967.12.3 by Martin Pool
Unify duplicated UnicodeFilename and _PosixPermissionsFeature
384
testtools = ModuleAvailableFeature('testtools')
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
385
386
compiled_patiencediff_feature = ModuleAvailableFeature(
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
387
    'breezy._patiencediff_c')
388
lsprof_feature = ModuleAvailableFeature('breezy.lsprof')
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
389
390
391
class _BackslashDirSeparatorFeature(Feature):
5241.2.1 by Robert Collins
Merge up from 2.0/2.1:
392
393
    def _probe(self):
394
        try:
395
            os.lstat(os.getcwd() + '\\')
396
        except OSError:
397
            return False
398
        else:
399
            return True
400
401
    def feature_name(self):
402
        return "Filesystem treats '\\' as a directory separator."
403
404
backslashdir_feature = _BackslashDirSeparatorFeature()
405
406
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
407
class _ChownFeature(Feature):
5051.4.10 by Parth Malwankar
moved ChownFeature to tests/features.py
408
    """os.chown is supported"""
409
410
    def _probe(self):
411
        return os.name == 'posix' and hasattr(os, 'chown')
412
5051.4.11 by Parth Malwankar
closed Martins review comments.
413
chown_feature = _ChownFeature()
5051.4.10 by Parth Malwankar
moved ChownFeature to tests/features.py
414
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
415
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
416
class ExecutableFeature(Feature):
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
417
    """Feature testing whether an executable of a given name is on the PATH."""
418
419
    def __init__(self, name):
420
        super(ExecutableFeature, self).__init__()
421
        self.name = name
5147.5.23 by Martin von Gagern
Have ExecutableFeature implement and use _probe.
422
        self._path = None
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
423
424
    @property
425
    def path(self):
5147.5.23 by Martin von Gagern
Have ExecutableFeature implement and use _probe.
426
        # This is a property, so accessing path ensures _probe was called
427
        self.available()
428
        return self._path
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
429
5147.5.23 by Martin von Gagern
Have ExecutableFeature implement and use _probe.
430
    def _probe(self):
5321.1.82 by Gordon Tyler
Changed ExecutableFeature to use osutils.find_executable_on_path.
431
        self._path = osutils.find_executable_on_path(self.name)
432
        return self._path is not None
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
433
434
    def feature_name(self):
435
        return '%s executable' % self.name
5147.5.24 by Martin von Gagern
Move ExecutableFeature instances to tests.features module.
436
437
438
bash_feature = ExecutableFeature('bash')
6282.3.1 by Vincent Ladeuil
First cut at a working plugin to avoid conflicts in .po files by shelling out to msgmerge.
439
diff_feature = ExecutableFeature('diff')
5147.5.24 by Martin von Gagern
Move ExecutableFeature instances to tests.features module.
440
sed_feature = ExecutableFeature('sed')
6282.3.1 by Vincent Ladeuil
First cut at a working plugin to avoid conflicts in .po files by shelling out to msgmerge.
441
msgmerge_feature = ExecutableFeature('msgmerge')
5609.47.1 by Alexander Belchenko
Win32Feature
442
443
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
444
class _PosixPermissionsFeature(Feature):
445
446
    def _probe(self):
447
        def has_perms():
448
            # Create temporary file and check if specified perms are
449
            # maintained.
450
            write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
451
            f = tempfile.mkstemp(prefix='bzr_perms_chk_')
452
            fd, name = f
453
            os.close(fd)
6344.1.1 by Martin Packman
Merge 2.4 into bzr.dev
454
            osutils.chmod_if_possible(name, write_perms)
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
455
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
456
            read_perms = os.stat(name).st_mode & 0o777
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
457
            os.unlink(name)
458
            return (write_perms == read_perms)
459
460
        return (os.name == 'posix') and has_perms()
461
462
    def feature_name(self):
463
        return 'POSIX permissions support'
464
465
466
posix_permissions_feature = _PosixPermissionsFeature()
467
468
469
class _StraceFeature(Feature):
470
471
    def _probe(self):
472
        try:
473
            proc = subprocess.Popen(['strace'],
474
                stderr=subprocess.PIPE,
475
                stdout=subprocess.PIPE)
476
            proc.communicate()
477
            return True
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
478
        except OSError as e:
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
479
            if e.errno == errno.ENOENT:
480
                # strace is not installed
481
                return False
482
            else:
483
                raise
484
485
    def feature_name(self):
486
        return 'strace'
487
488
489
strace_feature = _StraceFeature()
490
491
492
class _AttribFeature(Feature):
493
494
    def _probe(self):
495
        if (sys.platform not in ('cygwin', 'win32')):
496
            return False
497
        try:
498
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
499
        except OSError as e:
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
500
            return False
501
        return (0 == proc.wait())
502
503
    def feature_name(self):
504
        return 'attrib Windows command-line tool'
505
506
507
AttribFeature = _AttribFeature()
5967.12.2 by Martin Pool
Move all features to bzrlib.tests.features in 2.5
508
509
5967.12.3 by Martin Pool
Unify duplicated UnicodeFilename and _PosixPermissionsFeature
510
class Win32Feature(Feature):
5609.47.1 by Alexander Belchenko
Win32Feature
511
    """Feature testing whether we're running selftest on Windows
5609.47.4 by Alexander Belchenko
fixed typo
512
    or Windows-like platform.
5609.47.1 by Alexander Belchenko
Win32Feature
513
    """
514
515
    def _probe(self):
516
        return sys.platform == 'win32'
517
518
    def feature_name(self):
519
        return "win32 platform"
520
5967.12.4 by Martin Pool
Support (but deprecated) old feature names
521
5609.47.1 by Alexander Belchenko
Win32Feature
522
win32_feature = Win32Feature()
6531.3.8 by Jelmer Vernooij
Move color feature into bzrlib.tests.features.
523
524
525
class _ColorFeature(Feature):
526
527
    def _probe(self):
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
528
        from breezy._termcolor import allow_color
6531.3.8 by Jelmer Vernooij
Move color feature into bzrlib.tests.features.
529
        return allow_color()
530
531
    def feature_name(self):
532
        return "Terminal supports color."
533
534
ColorFeature = _ColorFeature()