Completed
Pull Request — master (#694)
by Eric
01:14
created

TestRealHooks.teardown_method()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
c 1
b 1
f 0
dl 0
loc 2
rs 10
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
"""
5
test_real_hooks_with_context_serialized
6
---------------------------------------
7
8
Additional tests for `cookiecutter.hooks` module.
9
"""
10
11
import os
12
import errno
13
import mock
14
import json
15
import pytest
16
17
from cookiecutter import hooks, utils
18
from subprocess import Popen
19
from testfixtures import LogCapture
20
21
22
class TestRealHooks(object):
23
    repo_path = os.path.abspath(
24
        'tests/test-real-hooks-with-serialized-context')
25
    hooks_path = repo_path + '/hooks'
26
27
    def teardown_method(self, method):
28
        LogCapture.uninstall_all()
29
30
    def test_run_script_with_context_get_updated_context(self):
31
        """
32
        Execute a hook script, passing a serialized context object and
33
        getting the context updated
34
        """
35
        context = {
36
            "my_key": "my_val"
37
        }
38
        expected = {
39
            "my_key": "my_val_updated"
40
        }
41
        actual = hooks.run_script_with_context(
42
            os.path.join(
43
                self.repo_path,
44
                'update_context',
45
                'hooks',
46
                'pre_gen_project.py'
47
            ),
48
            'tests',
49
            context
50
        )
51
52
        assert actual == expected
53
54
    def test_run_script_with_context_returns_context(self):
55
        """
56
        Execute a hook script, passing a serialized context object
57
        """
58
        context = {
59
            "my_key": "my_val"
60
        }
61
        actual = hooks.run_script_with_context(
62
            os.path.join(
63
                self.repo_path, 'simple', 'hooks', 'pre_gen_project.py'),
64
            'tests',
65
            context
66
        )
67
68
        assert actual == context
69
70
    def test_run_hook_returns_context(self):
71
        """
72
        Execute a hook script, passing a serialized context object
73
        """
74
        context = {
75
            "my_key": "my_val"
76
        }
77
78
        with utils.work_in(os.path.join(self.repo_path, 'simple')):
79
            actual = hooks.run_hook(
80
                'pre_gen_project',
81
                os.path.join(
82
                    self.repo_path,
83
                    'simple',
84
                    'input{{simple_hooks}}'
85
                ),
86
                context
87
            )
88
            assert actual == context
89
90
        with utils.work_in(os.path.join(self.repo_path, 'update_context')):
91
            expected = {
92
                "my_key": "my_val_updated"
93
            }
94
            actual = hooks.run_hook(
95
                'pre_gen_project',
96
                os.path.join(
97
                    self.repo_path,
98
                    'update_context',
99
                    'input{{update_context_hooks}}'
100
                ),
101
                context
102
            )
103
            assert actual == expected
104
105
        with utils.work_in(os.path.join(self.repo_path, 'simple')):
106
            actual = hooks.run_hook(
107
                'not_handled_hook',
108
                os.path.join(
109
                    self.repo_path,
110
                    'simple',
111
                    'input{{simple_hooks}}'
112
                ),
113
                context
114
            )
115
            assert actual == context
116
117
    def test_run_script_with_context_runs_hook_in_place(self):
118
        """
119
        Execute a hook script in place, passing a serialized context object
120
        """
121
        hook = os.path.join(
122
            self.repo_path,
123
            'inplace',
124
            'hooks',
125
            'pre_gen_project.py'
126
        )
127
        context = {
128
            "_run_hook_in_place": True
129
        }
130
        expected = {
131
            "_run_hook_in_place": True,
132
            "inplace": hook
133
        }
134
        actual = hooks.run_script_with_context(hook, 'tests', context)
135
136
        assert actual == expected
137
138
    def test_getting_bad_json_returns_original_context(self):
139
        """
140
        Execute a hook script that returns bad json
141
        """
142
        context = {
143
            "my_key": "my_val",
144
        }
145
146
        actual = hooks.run_script_with_context(
147
            os.path.join(
148
                self.repo_path,
149
                'bad_json',
150
                'hooks',
151
                'pre_gen_project.py'
152
            ),
153
            'tests',
154
            context
155
        )
156
157
        assert actual == context
158
159
    @mock.patch('sys.platform')
160
    @mock.patch('subprocess.Popen', autospec=True)
161
    def test_handle_lost_stdin_during_communication_on_windows_os(
162
        self, mock_popen, mock_platform
163
    ):
164
        """
165
        Ensure that an OSError raised from Popen._stdin_write is correctly
166
        caught and logged, while not blocking the process on windows OS
167
        """
168
        context = {
169
            "my_key": "my_val"
170
        }
171
172
        log = LogCapture()
173
174
        proc = mock_popen.return_value
175
        proc.communicate.side_effect = OSError(
176
            errno.EINVAL, 'Invalid Argument'
177
        )
178
        proc.communicate.return_value = json.dumps(context).encode()
179
        proc.wait.return_value = 0
180
181
        platform = mock_platform.return_value
182
        platform.return_value = "win32"
183
184
        actual = hooks.run_script_with_context(
185
            os.path.join(
186
                self.repo_path, 'simple', 'hooks', 'pre_gen_project.py'),
187
            'tests',
188
            context
189
        )
190
191
        log.check(
192
            ('root', 'WARNING', 'Popen.communicate failed certainly ' +
193
                'because of the issue #19612')
194
        )
195
        assert actual == context
196
197
    def test_handle_oserror_during_communication_on_non_windows_os(self):
198
        """
199
        Ensure that an OSError raised on a non windows os is bubbled up
200
        """
201
        Popen.communicate = mock.Mock(
202
            side_effect=OSError(errno.EINVAL, 'Invalid Argument')
203
        )
204
205
        with pytest.raises(OSError) as excinfo:
206
            hooks.run_script_with_context(
207
                os.path.join(
208
                    self.repo_path, 'simple', 'hooks', 'pre_gen_project.py'),
209
                'tests',
210
                {}
211
            )
212
            assert excinfo.value.errno == errno.EINVAL
213