File: test_popen_docs.py

package info (click to toggle)
python-testfixtures 9.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,036 kB
  • sloc: python: 10,373; makefile: 76; sh: 9
file content (240 lines) | stat: -rw-r--r-- 7,676 bytes parent folder | download | duplicates (2)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# NB: This file is used in the documentation, if you make changes, ensure
#     you update the line numbers in popen.txt!

from subprocess import Popen, PIPE


def my_func():
    process = Popen(['svn', 'ls', '-R', 'foo'], stdout=PIPE, stderr=PIPE)
    out, err = process.communicate()
    if process.returncode:
        raise RuntimeError('something bad happened')
    return out

dotted_path = 'testfixtures.tests.test_popen_docs.Popen'

from unittest import TestCase

from testfixtures.mock import call
from testfixtures import Replacer, ShouldRaise, compare, SequenceComparison
from testfixtures.popen import MockPopen, PopenBehaviour


class TestMyFunc(TestCase):

    def setUp(self):
        self.Popen = MockPopen()
        self.r = Replacer()
        self.r.replace(dotted_path, self.Popen)
        self.addCleanup(self.r.restore)

    def test_example(self):
        # set up
        self.Popen.set_command('svn ls -R foo', stdout=b'o', stderr=b'e')

        # testing of results
        compare(my_func(), b'o')

        # testing calls were in the right order and with the correct parameters:
        process = call.Popen(['svn', 'ls', '-R', 'foo'], stderr=PIPE, stdout=PIPE)
        compare(Popen.all_calls, expected=[
            process,
            process.communicate()
        ])

    def test_example_bad_returncode(self):
        # set up
        Popen.set_command('svn ls -R foo', stdout=b'o', stderr=b'e',
                          returncode=1)

        # testing of error
        with ShouldRaise(RuntimeError('something bad happened')):
            my_func()

    def test_communicate_with_input(self):
        # setup
        Popen = MockPopen()
        Popen.set_command('a command')
        # usage
        process = Popen('a command', stdout=PIPE, stderr=PIPE, shell=True)
        out, err = process.communicate('foo')
        # test call list
        compare(Popen.all_calls, expected=[
                process.root_call,
                process.root_call.communicate('foo'),
        ])

    def test_read_from_stdout_and_stderr(self):
        # setup
        Popen = MockPopen()
        Popen.set_command('a command', stdout=b'foo', stderr=b'bar')
        # usage
        process = Popen('a command', stdout=PIPE, stderr=PIPE, shell=True)
        compare(process.stdout.read(), expected=b'foo')
        compare(process.stderr.read(), expected=b'bar')

    def test_write_to_stdin(self):
        # setup
        Popen = MockPopen()
        Popen.set_command('a command')
        # usage
        process = Popen('a command', stdin=PIPE, shell=True)
        process.stdin.write('some text')
        process.stdin.close()
        # test call list
        compare(Popen.all_calls, expected=[
            process.root_call,
            process.root_call.stdin.write('some text'),
            process.root_call.stdin.close(),
        ])

    def test_wait_and_return_code(self):
        # setup
        Popen = MockPopen()
        Popen.set_command('a command', returncode=3)
        # usage
        process = Popen('a command')
        compare(process.returncode, expected=None)
        # result checking
        compare(process.wait(), expected=3)
        compare(process.returncode, expected=3)
        # test call list
        compare(Popen.all_calls, expected=[
            call.Popen('a command'),
            call.Popen('a command').wait(),
        ])

    def test_send_signal(self):
        # setup
        Popen = MockPopen()
        Popen.set_command('a command')
        # usage
        process = Popen('a command', stdout=PIPE, stderr=PIPE, shell=True)
        process.send_signal(0)
        # result checking
        compare(Popen.all_calls, expected=[
            process.root_call,
            process.root_call.send_signal(0),
        ])

    def test_poll_until_result(self):
        # setup
        Popen = MockPopen()
        Popen.set_command('a command', returncode=3, poll_count=2)
        # example usage
        process = Popen('a command')
        while process.poll() is None:
            # you'd probably have a sleep here, or go off and
            # do some other work.
            pass
        # result checking
        compare(process.returncode, expected=3)
        compare(Popen.all_calls, expected=[
            process.root_call,
            process.root_call.poll(),
            process.root_call.poll(),
            process.root_call.poll(),
        ])

    def test_default_behaviour(self):
        # set up
        self.Popen.set_default(stdout=b'o', stderr=b'e')

        # testing of results
        compare(my_func(), b'o')

        # testing calls were in the right order and with the correct parameters:
        root_call = call.Popen(['svn', 'ls', '-R', 'foo'],
                               stderr=PIPE, stdout=PIPE)
        compare(Popen.all_calls, expected=[
            root_call,
            root_call.communicate()
        ])

    def test_multiple_responses(self):
        # set up
        behaviours = [
            PopenBehaviour(stderr=b'e', returncode=1),
            PopenBehaviour(stdout=b'o'),
        ]

        def behaviour(command, stdin):
            return behaviours.pop(0)

        self.Popen.set_command('svn ls -R foo', behaviour=behaviour)

        # testing of error:
        with ShouldRaise(RuntimeError('something bad happened')):
            my_func()
        # testing of second call:
        compare(my_func(), b'o')

    def test_count_down(self):
        # set up
        self.Popen.set_command('svn ls -R foo', behaviour=CustomBehaviour())
        # testing of error:
        with ShouldRaise(RuntimeError('something bad happened')):
            my_func()
        # testing of second call:
        compare(my_func(), b'o')

    def test_multiple_processes(self):
        # set up
        self.Popen.set_command('process --batch=0', stdout=b'42')
        self.Popen.set_command('process --batch=1', stdout=b'13')

        # testing of results
        compare(process_in_batches(2), expected=55)

        # testing of process management:
        p1 = call.Popen('process --batch=0', shell=True, stderr=PIPE, stdout=PIPE)
        p2 = call.Popen('process --batch=1', shell=True, stderr=PIPE, stdout=PIPE)
        compare(Popen.all_calls, expected=[
            p1,
            p2,
            p1.communicate(),
            p2.communicate(),
        ])

    def test_multiple_processes_unordered(self):
        # set up
        self.Popen.set_command('process --batch=0', stdout=b'42')
        self.Popen.set_command('process --batch=1', stdout=b'13')

        # testing of results
        compare(process_in_batches(2), expected=55)

        # testing of process management:
        p1 = call.Popen('process --batch=0', shell=True, stderr=PIPE, stdout=PIPE)
        p2 = call.Popen('process --batch=1', shell=True, stderr=PIPE, stdout=PIPE)
        compare(Popen.all_calls, expected=SequenceComparison(
            p2,
            p2.communicate(),
            p1,
            p1.communicate(),
            ordered=False
        ))


class CustomBehaviour:

    def __init__(self, fail_count=1):
        self.fail_count = fail_count

    def __call__(self, command, stdin):
        while self.fail_count > 0:
            self.fail_count -= 1
            return PopenBehaviour(stderr=b'e', returncode=1)
        return PopenBehaviour(stdout=b'o')


def process_in_batches(n):
    processes = []
    for i in range(n):
        processes.append(Popen('process --batch='+str(i),
                               stdout=PIPE, stderr=PIPE, shell=True))
    total = 0
    for process in processes:
        out, err = process.communicate()
        total += int(out)
    return total