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