1# Copyright 2012-2019, Damian Johnson and The Tor Project 2# See LICENSE for licensing information 3 4""" 5Testing requirements. This provides annotations to skip tests that shouldn't be 6run. 7 8:: 9 10 Test Requirements 11 |- only_run_once - skip test if it has been ran before 12 |- needs - skips the test unless a requirement is met 13 | 14 |- cryptography - skips test unless the cryptography module is present 15 |- ed25519_support - skips test unless cryptography has ed25519 support 16 |- command - requires a command to be on the path 17 |- proc - requires the platform to have recognized /proc contents 18 | 19 |- controller - skips test unless tor provides a controller endpoint 20 |- version - skips test unless we meet a tor version requirement 21 |- ptrace - requires 'DisableDebuggerAttachment' to be set 22 +- online - skips unless targets allow for online tests 23""" 24 25import stem.util.system 26import stem.version 27import test 28import test.runner 29 30RAN_TESTS = [] 31 32 33def only_run_once(func): 34 """ 35 Skips the test if it has ran before. If it hasn't then flags it as being ran. 36 This is useful to prevent lengthy tests that are independent of integ targets 37 from being run repeatedly with ``RUN_ALL``. 38 """ 39 40 def wrapped(self, *args, **kwargs): 41 if self.id() not in RAN_TESTS: 42 RAN_TESTS.append(self.id()) 43 return func(self, *args, **kwargs) 44 else: 45 self.skipTest('(already ran)') 46 47 return wrapped 48 49 50def needs(condition, message): 51 """ 52 Skips the test unless the conditional evaluates to 'true'. 53 """ 54 55 def decorator(func): 56 def wrapped(self, *args, **kwargs): 57 if condition(): 58 return func(self, *args, **kwargs) 59 else: 60 self.skipTest('(%s)' % message) 61 62 return wrapped 63 64 return decorator 65 66 67def _can_access_controller(): 68 return test.runner.get_runner().is_accessible() 69 70 71def _can_ptrace(): 72 # If we're running a tor version where ptrace is disabled and we didn't 73 # set 'DisableDebuggerAttachment=1' then we can infer that it's disabled. 74 75 has_option = test.tor_version() >= stem.version.Requirement.TORRC_DISABLE_DEBUGGER_ATTACHMENT 76 return not has_option or test.runner.Torrc.PTRACE in test.runner.get_runner().get_options() 77 78 79def _is_online(): 80 return test.Target.ONLINE in test.runner.get_runner().attribute_targets 81 82 83def command(cmd): 84 """ 85 Skips the test unless a command is available on the path. 86 """ 87 88 return needs(lambda: stem.util.system.is_available(cmd), '%s unavailable' % cmd) 89 90 91def version(req_version): 92 """ 93 Skips the test unless we meet the required version. 94 95 :param stem.version.Version req_version: required tor version for the test 96 """ 97 98 return needs(lambda: test.tor_version() >= req_version, 'requires %s' % req_version) 99 100 101cryptography = needs(stem.prereq.is_crypto_available, 'requires cryptography') 102ed25519_support = needs(lambda: stem.prereq.is_crypto_available(ed25519 = True), 'requires ed25519 support') 103proc = needs(stem.util.proc.is_available, 'proc unavailable') 104controller = needs(_can_access_controller, 'no connection') 105ptrace = needs(_can_ptrace, 'DisableDebuggerAttachment is set') 106online = needs(_is_online, 'requires online target') 107