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