1# Copyright (c) 2018 gevent community
2#
3# Permission is hereby granted, free of charge, to any person obtaining a copy
4# of this software and associated documentation files (the "Software"), to deal
5# in the Software without restriction, including without limitation the rights
6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7# copies of the Software, and to permit persons to whom the Software is
8# furnished to do so, subject to the following conditions:
9#
10# The above copyright notice and this permission notice shall be included in
11# all copies or substantial portions of the Software.
12#
13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19# THE SOFTWARE.
20from __future__ import absolute_import, print_function, division
21
22import functools
23import unittest
24
25from . import sysinfo
26
27def _identity(f):
28    return f
29
30def _do_not_skip(reason):
31    assert reason
32    return _identity
33
34
35skipOnMac = _do_not_skip
36skipOnMacOnCI = _do_not_skip
37skipOnWindows = _do_not_skip
38skipOnAppVeyor = _do_not_skip
39skipOnCI = _do_not_skip
40skipOnManylinux = _do_not_skip
41
42skipOnPyPy = _do_not_skip
43skipOnPyPyOnCI = _do_not_skip
44skipOnPyPy3OnCI = _do_not_skip
45skipOnPyPy3 = _do_not_skip
46skipOnPyPyOnWindows = _do_not_skip
47
48skipOnPy2 = unittest.skip if sysinfo.PY2 else _do_not_skip
49skipOnPy3 = unittest.skip if sysinfo.PY3 else _do_not_skip
50skipOnPy37 = unittest.skip if sysinfo.PY37 else _do_not_skip
51skipOnPy310 = unittest.skip if sysinfo.PY310 else _do_not_skip
52
53skipOnPurePython = unittest.skip if sysinfo.PURE_PYTHON else _do_not_skip
54skipWithCExtensions = unittest.skip if not sysinfo.PURE_PYTHON else _do_not_skip
55
56skipOnLibuv = _do_not_skip
57skipOnLibuvOnWin = _do_not_skip
58skipOnLibuvOnCI = _do_not_skip
59skipOnLibuvOnCIOnPyPy = _do_not_skip
60skipOnLibuvOnPyPyOnWin = _do_not_skip
61skipOnLibuvOnTravisOnCPython27 = _do_not_skip
62
63skipOnLibev = _do_not_skip
64
65if sysinfo.WIN:
66    skipOnWindows = unittest.skip
67
68if sysinfo.OSX:
69    skipOnMac = unittest.skip
70
71if sysinfo.RUNNING_ON_APPVEYOR:
72    # See comments scattered around about timeouts and the timer
73    # resolution available on appveyor (lots of jitter). this
74    # seems worse with the 62-bit builds.
75    # Note that we skip/adjust these tests only on AppVeyor, not
76    # win32---we don't think there's gevent related problems but
77    # environment related problems. These can be tested and debugged
78    # separately on windows in a more stable environment.
79    skipOnAppVeyor = unittest.skip
80
81
82if sysinfo.RUNNING_ON_CI:
83    skipOnCI = unittest.skip
84    if sysinfo.OSX:
85        skipOnMacOnCI = unittest.skip
86
87if sysinfo.RUNNING_ON_MANYLINUX:
88    skipOnManylinux = unittest.skip
89
90if sysinfo.PYPY:
91    skipOnPyPy = unittest.skip
92    if sysinfo.RUNNING_ON_CI:
93        skipOnPyPyOnCI = unittest.skip
94
95    if sysinfo.WIN:
96        skipOnPyPyOnWindows = unittest.skip
97
98    if sysinfo.PYPY3:
99        skipOnPyPy3 = unittest.skip
100        if sysinfo.RUNNING_ON_CI:
101            # Same as above, for PyPy3.3-5.5-alpha and 3.5-5.7.1-beta and 3.5-5.8
102            skipOnPyPy3OnCI = unittest.skip
103
104
105skipUnderCoverage = unittest.skip if sysinfo.RUN_COVERAGE else _do_not_skip
106
107skipIf = unittest.skipIf
108skipUnless = unittest.skipUnless
109
110_has_psutil_process = None
111def _check_psutil():
112    global _has_psutil_process
113    if _has_psutil_process is None:
114        _has_psutil_process = sysinfo.get_this_psutil_process() is not None
115    return _has_psutil_process
116
117
118def _make_runtime_skip_decorator(reason, predicate):
119    def decorator(test_item):
120        if not isinstance(test_item, type):
121            f = test_item
122            @functools.wraps(test_item)
123            def skip_wrapper(*args, **kwargs):
124                if not predicate():
125                    raise unittest.SkipTest(reason)
126                return f(*args, **kwargs)
127            test_item = skip_wrapper
128        else:
129            # given a class, override setUp() to skip it.
130            #
131            # Internally, unittest uses two flags on the class to do this:
132            # __unittest_skip__ and __unittest_skip_why__. It *appears*
133            # these are evaluated for each method in the test, so we can safely
134            # change them at runtime. **This isn't documented.**
135            #
136            # If they are set before execution begins, then the class setUpClass
137            # and tearDownClass are skipped. So changing them at runtime could result
138            # in something being set up but not torn down. It is substantially
139            # faster, though, to set them.
140            base = test_item
141            base_setUp = base.setUp
142            @functools.wraps(test_item)
143            def setUp(self):
144                if not predicate():
145                    base.__unittest_skip__ = True
146                    base.__unittest_skip_why__ = reason
147                    raise unittest.SkipTest(reason)
148                base_setUp(self)
149            base.setUp = setUp
150
151        return test_item
152
153    return decorator
154
155def skipWithoutPSUtil(reason):
156    reason = "psutil not available: " + reason
157    # Defer the check until runtime to avoid imports
158    return _make_runtime_skip_decorator(reason, _check_psutil)
159
160if sysinfo.LIBUV:
161    skipOnLibuv = unittest.skip
162
163    if sysinfo.RUNNING_ON_CI:
164        skipOnLibuvOnCI = unittest.skip
165        if sysinfo.PYPY:
166            skipOnLibuvOnCIOnPyPy = unittest.skip
167    if sysinfo.RUNNING_ON_TRAVIS:
168        if sysinfo.CPYTHON:
169            if sysinfo.PY27_ONLY:
170                skipOnLibuvOnTravisOnCPython27 = unittest.skip
171
172    if sysinfo.WIN:
173        skipOnLibuvOnWin = unittest.skip
174        if sysinfo.PYPY:
175            skipOnLibuvOnPyPyOnWin = unittest.skip
176else:
177    skipOnLibev = unittest.skip
178
179
180def skipWithoutResource(resource, reason=''):
181    requires = 'Requires resource %r' % (resource,)
182    if not reason:
183        reason = requires
184    else:
185        reason = reason + ' (' + requires + ')'
186
187    # Defer until runtime; resources are established as part
188    # of test startup.
189    def predicate(): # This is easily cached if needed
190        from . import resources
191        return resources.ensure_setup_resources().is_resource_enabled(resource)
192
193    return _make_runtime_skip_decorator(reason, predicate)
194
195def skipWithoutExternalNetwork(reason=''):
196    # Use to decorate test functions or classes that
197    # need access to external network resources (e.g., DNS, HTTP servers, etc)
198    #
199    # Important: If you use this on classes, you must not use the
200    # two-argument form of super()
201
202    return skipWithoutResource('network', reason)
203