File: __init__.py

package info (click to toggle)
python-stem 1.8.2-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 7,852 kB
  • sloc: python: 33,748; java: 312; makefile: 124; sh: 14
file content (162 lines) | stat: -rw-r--r-- 4,303 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# Copyright 2011-2019, Damian Johnson and The Tor Project
# See LICENSE for licensing information

"""
Unit and integration tests for the stem library. Helpers include...

::

  get_new_capabilities - missing capabilities found while testing
  register_new_capability - note that tor feature stem lacks

  get_all_combinations - provides all combinations of attributes
  tor_version - provides the version of tor we're testing against
"""

import collections
import itertools
import os

import stem.util.enum
import stem.version

__all__ = [
  'network',
  'output',
  'prompt',
  'runner',
]

# Integration targets fall into two categories:
#
# * Run Targets (like RUN_COOKIE and RUN_PTRACE) which customize our torrc.
#   We do an integration test run for each run target we get.
#
# * Attribute Target (like CHROOT and ONLINE) which indicates
#   non-configuration changes to your test runs. These are applied to all
#   integration runs that we perform.

Target = stem.util.enum.UppercaseEnum(
  'ONLINE',
  'RELATIVE',
  'CHROOT',
  'RUN_NONE',
  'RUN_OPEN',
  'RUN_PASSWORD',
  'RUN_COOKIE',
  'RUN_MULTIPLE',
  'RUN_SOCKET',
  'RUN_SCOOKIE',
  'RUN_PTRACE',
  'RUN_ALL',
)

AsyncTestArgs = collections.namedtuple('AsyncTestArgs', ['test_dir', 'tor_cmd'])
TOR_VERSION = None

# We make some paths relative to stem's base directory (the one above us)
# rather than the process' cwd. This doesn't end with a slash.

STEM_BASE = os.path.sep.join(__file__.split(os.path.sep)[:-2])

# Store new capabilities (events, descriptor entries, etc.)

NEW_CAPABILITIES = set()
NEW_CAPABILITIES_SUPPRESSION_TOKENS = set()

# File extensions of contents that should be ignored.

IGNORED_FILE_TYPES = []
GIT_IGNORE_PATH = os.path.join(STEM_BASE, '.gitignore')

if os.path.exists(GIT_IGNORE_PATH):
  with open(GIT_IGNORE_PATH) as ignore_file:
    for line in ignore_file:
      if line.startswith('*.'):
        IGNORED_FILE_TYPES.append(line[2:].strip())

if os.path.exists(os.path.join(STEM_BASE, '.travis.yml')):
    IGNORED_FILE_TYPES.append('.travis.yml')


def get_new_capabilities():
  """
  Provides a list of capabilities tor supports but stem doesn't, as discovered
  while running our tests.

  :returns: **set** of (type, message) tuples for the capabilities
  """

  return NEW_CAPABILITIES


def register_new_capability(capability_type, msg, suppression_token = None):
  """
  Register new capability found during the tests.

  :param str capability_type: type of capability this is
  :param str msg: description of what we found
  :param str suppression_token: skip registration if this token's already been
    provided
  """

  if suppression_token not in NEW_CAPABILITIES_SUPPRESSION_TOKENS:
    NEW_CAPABILITIES.add((capability_type, msg))

    if suppression_token:
      NEW_CAPABILITIES_SUPPRESSION_TOKENS.add(suppression_token)


def get_all_combinations(attr, include_empty = False):
  """
  Provides an iterator for all combinations of a set of attributes. For
  instance...

  ::

    >>> list(test.get_all_combinations(['a', 'b', 'c']))
    [('a',), ('b',), ('c',), ('a', 'b'), ('a', 'c'), ('b', 'c'), ('a', 'b', 'c')]

  :param list attr: attributes to provide combinations for
  :param bool include_empty: includes an entry with zero items if True
  :returns: iterator for all combinations
  """

  # Makes an itertools.product() call for 'i' copies of attr...
  #
  # * itertools.product(attr) => all one-element combinations
  # * itertools.product(attr, attr) => all two-element combinations
  # * ... etc

  if include_empty:
    yield ()

  seen = set()
  for index in range(1, len(attr) + 1):
    product_arg = [attr for _ in range(index)]

    for item in itertools.product(*product_arg):
      # deduplicate, sort, and only provide if we haven't seen it yet
      item = tuple(sorted(set(item)))

      if item not in seen:
        seen.add(item)
        yield item


def tor_version(tor_path = None):
  """
  Provides the version of tor we're testing against.

  :param str tor_path: location of tor executable to cehck the version of

  :returns: :class:`~stem.version.Version` of tor invoked by our integration
    tests
  """

  global TOR_VERSION

  if TOR_VERSION is None or tor_path:
    TOR_VERSION = stem.version.get_system_tor_version(tor_path)

  return TOR_VERSION