Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: sitescripts/formmail/test/test_formmail2.py

Issue 29374647: Issue 4814 - Adds csv log to formmail2 (Closed) Base URL: https://hg.adblockplus.org/sitescripts
Left Patch Set: Created March 7, 2017, 8:24 p.m.
Right Patch Set: Created March 23, 2017, 6:50 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « .sitescripts.example ('k') | sitescripts/formmail/web/formmail2.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # This file is part of the Adblock Plus web scripts, 1 # This file is part of the Adblock Plus web scripts,
2 # Copyright (C) 2006-2016 Eyeo GmbH 2 # Copyright (C) 2006-2017 eyeo GmbH
3 # 3 #
4 # Adblock Plus is free software: you can redistribute it and/or modify 4 # Adblock Plus is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License version 3 as 5 # it under the terms of the GNU General Public License version 3 as
6 # published by the Free Software Foundation. 6 # published by the Free Software Foundation.
7 # 7 #
8 # Adblock Plus is distributed in the hope that it will be useful, 8 # Adblock Plus is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details. 11 # GNU General Public License for more details.
12 # 12 #
13 # You should have received a copy of the GNU General Public License 13 # You should have received a copy of the GNU General Public License
14 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 14 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
15 15
16 import datetime
17 from csv import DictReader
18 from urllib import urlencode 16 from urllib import urlencode
19 from urllib2 import urlopen, HTTPError 17 from urllib2 import urlopen, HTTPError
18 from csv import DictReader
20 19
21 import pytest 20 import pytest
22 from wsgi_intercept import (urllib_intercept, add_wsgi_intercept, 21 from wsgi_intercept import (urllib_intercept, add_wsgi_intercept,
23 remove_wsgi_intercept) 22 remove_wsgi_intercept)
24 23
25 from sitescripts.formmail.web import formmail2 24 from sitescripts.formmail.web import formmail2
26 25
27 26 HOST = 'test.local'
28 @pytest.fixture 27 LOG_PORT = 80
29 def form_config(): 28 NO_LOG_PORT = 81
30 return formmail2.conf_parse(formmail2.get_config_items())['test']
31
32
33 @pytest.fixture
34 def form_handlers(form_config, log_path):
35 """ Returns two handlers, one with logging configured and one without """
Vasily Kuznetsov 2017/03/09 19:58:09 It would be better to have all the docstrings foll
Jon Sonesen 2017/03/14 19:41:26 Done.
36 # override configured path to log file with tmpdir path
37 form_config['csv_log'].value = log_path
38 log_handler = formmail2.make_handler('log_test', form_config)[1]
39
40 # parse a new config because the make_handler function changes the provided
41 # config object which causes the config parsing to break when creating
42 # the handler which has no log
43 no_log_config = formmail2.conf_parse(formmail2.get_config_items())['test']
44 del no_log_config['csv_log']
Jon Sonesen 2017/03/14 19:41:25 it seems that this is actually not working as expe
45
46 return log_handler, formmail2.make_handler('log_test', no_log_config)[1]
Vasily Kuznetsov 2017/03/09 19:58:09 Maybe we also assign the result of `make_handler`
Jon Sonesen 2017/03/10 09:28:51 I was just thinking about what someone else on the
Vasily Kuznetsov 2017/03/10 09:54:28 Acknowledged.
47 29
48 30
49 @pytest.fixture 31 @pytest.fixture
50 def log_path(tmpdir): 32 def log_path(tmpdir):
51 return str(tmpdir.join('test.csv_log')) 33 return str(tmpdir.join('test.csv_log'))
34
35
36 @pytest.fixture
37 def log_form_config():
38 return formmail2.conf_parse(formmail2.get_config_items())['test']
39
40
41 @pytest.fixture
42 def form_config():
43 config = formmail2.conf_parse(formmail2.get_config_items())['test']
44 del config['csv_log']
45 return config
46
47
48 @pytest.fixture
49 def form_handler(log_path, form_config, log_form_config):
50 """ Create two handlers, one that logs and another that doesn't """
51 log_form_config['csv_log'].value = log_path
52 return (formmail2.make_handler('test', log_form_config)[1],
53 formmail2.make_handler('test', form_config)[1])
52 54
53 55
54 # We make this a fixture instead of a constant so we can modify it in each 56 # We make this a fixture instead of a constant so we can modify it in each
55 # test as needed without affecting other tests. 57 # test as needed without affecting other tests.
56 @pytest.fixture 58 @pytest.fixture
57 def form_data(): 59 def form_data():
58 return { 60 return {
59 'email': 'john_doe@gmail.com', 61 'email': 'john_doe@gmail.com',
60 'mandatory': 'john_doe@gmail.com', 62 'mandatory': 'john_doe@gmail.com',
61 'non_mandatory_message': 'Once upon a time\nthere lived a king.', 63 'non_mandatory_message': 'Once upon a time\nthere lived a king.',
62 'non_mandatory_email': 'test@test.com', 64 'non_mandatory_email': 'test@test.com',
63 } 65 }
64 66
65 67
66 @pytest.fixture 68 @pytest.fixture
67 def responses_for(form_handlers, log_path): 69 def response_for(form_handler):
68 """ 70 """ Registers two intercepts, returns responses for them based on bool """
69 Returns a list of response functions for handlers configured both with and 71 urllib_intercept.install_opener()
70 without logging configured 72 add_wsgi_intercept(HOST, LOG_PORT, lambda: form_handler[0])
71 """ 73 add_wsgi_intercept(HOST, NO_LOG_PORT, lambda: form_handler[1])
72 responses = []
73 for form_handler in form_handlers:
Vasily Kuznetsov 2017/03/09 19:58:09 Nifty!
Jon Sonesen 2017/03/10 09:28:51 Thanks :)
74 host, port = 'test.local', 80
75 urllib_intercept.install_opener()
76 add_wsgi_intercept(host, port, lambda: form_handler)
77 url = 'http://{}:{}'.format(host, port)
78 74
79 def response_for(data): 75 def response_for(data, log=False):
80 if data is None: 76 if log:
81 response = urlopen(url) 77 url = 'http://{}:{}'.format(HOST, LOG_PORT)
82 else: 78 else:
83 response = urlopen(url, urlencode(data)) 79 url = 'http://{}:{}'.format(HOST, NO_LOG_PORT)
84 return response.code, response.read() 80 if data is None:
85 responses.append(response_for) 81 response = urlopen(url)
86 yield responses 82 else:
83 response = urlopen(url, urlencode(data))
84 return response.code, response.read()
85
86 yield response_for
87 remove_wsgi_intercept() 87 remove_wsgi_intercept()
88
89
90 @pytest.fixture
91 def sm_mock(mocker):
92 return mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
93
94
95 @pytest.mark.parametrize('key,message', [
96 ('url', 'No URL configured for form handler: test'),
97 ('fields', 'No fields configured for form handler: test'),
98 ('template', 'No template configured for form handler: test'),
99 ])
100 def test_config_errors(key, message, form_config):
101 del form_config[key]
102 with pytest.raises(Exception) as error:
103 formmail2.make_handler('test', form_config)[1]
104 assert error.value.message == message
105
106
107 @pytest.mark.parametrize('field,message', [
108 (('new_field', 'foo'), 'Unexpected field/fields: new_field'),
109 (('mandatory', ''), 'No mandatory entered'),
110 (('non_mandatory_email', 'asfaf'), 'Invalid email'),
111 (('email', 'asfaf'), 'You failed the email validation'),
112 (('email', ''), 'You failed the email test'),
113 ])
114 def test_http_errs(field, message, response_for, form_data, sm_mock):
115 key, value = field
116 form_data[key] = value
117 with pytest.raises(HTTPError) as error:
118 response_for(form_data)
119 assert error.value.read() == message
120
121
122 @pytest.mark.parametrize('field,expected', [
123 (('non_mandatory_message', '\xc3\xb6'), (200, '')),
124 (('non_mandatory_message', ''), (200, '')),
125 ])
126 def test_success(field, expected, log_path, response_for, form_data, sm_mock):
127 key, value = field
128 form_data[key] = value
129 assert response_for(form_data, log=False) == expected
130 assert sm_mock.call_count == 1
131
132 params = sm_mock.call_args[0][1]['fields']
133 assert set(params.keys()) == set(form_data.keys())
134 for key, value in form_data.items():
135 assert params[key] == value.decode('utf8')
136
137 assert response_for(form_data, log=True) == expected
138 assert sm_mock.call_count == 2
139
140 assert response_for(form_data, log=True) == expected
141 assert sm_mock.call_count == 3
142
143 with open(log_path) as log_file:
144 reader = DictReader(log_file)
145 row = reader.next()
146 # rows should not be equal because the time field
147 # is added by the logging function.
148 assert row != reader.next()
149
150
151 def test_config_field_errors(form_config):
152 form_config['fields'] = {}
153 with pytest.raises(Exception) as error:
154 formmail2.make_handler('test', form_config)[1]
155 assert error.value.message == 'No fields configured for form handler: test'
156
157
158 def test_config_template_errors(form_config):
159 form_config['template'].value = 'no'
160 with pytest.raises(Exception) as error:
161 formmail2.make_handler('test', form_config)[1]
162 assert error.value.message == 'Template not found at: no'
88 163
89 164
90 def test_config_parse(form_config): 165 def test_config_parse(form_config):
91 assert form_config['url'].value == 'test/apply/submit' 166 assert form_config['url'].value == 'test/apply/submit'
92 assert form_config['fields']['email'].value == 'mandatory, email' 167 assert form_config['fields']['email'].value == 'mandatory, email'
93 168
94 169
95 def test_success(responses_for, form_data, mocker): 170 def test_sendmail_fail(log_path, response_for, form_data, sm_mock):
Jon Sonesen 2017/03/14 19:41:26 Should this test check for the existence of the lo
96 for response_for in responses_for: 171 sm_mock.side_effect = Exception('Sendmail Fail')
97 sm_mock = mocker.patch('sitescripts.formmail.web.formmail2.sendMail') 172 with pytest.raises(HTTPError):
98 assert response_for(form_data) == (200, '') 173 response_for(form_data, log=True)
99 assert sm_mock.call_count == 1
100 params = sm_mock.call_args[0][1]['fields']
101 assert set(params.keys()) == set(form_data.keys())
102 for key, value in form_data.items():
103 assert params[key] == value
104 174
105 175 with open(log_path) as log_file:
106 def test_utf8_success(responses_for, form_data, mocker): 176 row = DictReader(log_file).next()
107 form_data['non_mandatory_message'] = '\xc3\xb6' 177 assert row != form_data
108 for response_for in responses_for:
109 sm_mock = mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
110 assert response_for(form_data) == (200, '')
111 assert sm_mock.call_count == 1
112 params = sm_mock.call_args[0][1]['fields']
113 assert set(params.keys()) == set(form_data.keys())
114 for key, value in form_data.items():
115 assert params[key] == value
116
117
118 def test_non_mandatory_no_msg(responses_for, form_data, mocker):
119 mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
120 form_data['non_mandatory'] = ''
121 for response_for in responses_for:
122 assert response_for(form_data) == (200, '')
123
124
125 def test_invalid_email_cstm_msg(responses_for, form_data, mocker, form_config):
126 mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
127 form_data['email'] = 'bademail'
128 for response_for in responses_for:
129 with pytest.raises(HTTPError) as error:
130 response_for(form_data)
131 assert error.value.read() == 'You failed the email validation'
132
133
134 def test_valid_nan_mandatory_email(responses_for, form_data, mocker):
Jon Sonesen 2017/03/14 19:41:25 Yikes! this is actually meant to test 'invalid_non
135 mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
136 form_data['non_mandatory_email'] = 'asfaf'
137 for response_for in responses_for:
138 with pytest.raises(HTTPError) as error:
139 response_for(form_data)
140 assert error.value.read() == 'Invalid email'
141
142 del form_data['non_mandatory_email']
143 for response_for in responses_for:
144 assert response_for(form_data) == (200, '')
145
146
147 def test_mandatory_fail_dflt_msg(responses_for, form_data, mocker):
148 mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
149 del form_data['mandatory']
Jon Sonesen 2017/03/14 19:41:26 it is actually unlikely the request will be sent m
150 for response_for in responses_for:
151 with pytest.raises(HTTPError) as error:
152 response_for(form_data)
153 assert error.value.read() == 'No mandatory entered'
154
155
156 def test_collect_with_tmpl(log_path, form_data):
157 form_data['time'] = 'test'
158 formmail2.log_formdata(form_data, log_path)
159 with open(log_path) as csvfile:
160 assert DictReader(csvfile).next() == form_data
161
162
163 def test_collect_no_tmpl(log_path, form_data, form_config):
164 del(form_config['template'])
165 form_data['time'] = 'test'
166 formmail2.log_formdata(form_data, log_path)
167 with open(log_path) as csvfile:
168 assert DictReader(csvfile).next() == form_data
169
170
171 def test_fieldnames(log_path, form_data):
172 form_data['time'] = str(datetime.datetime.now())
173 formmail2.log_formdata(form_data, log_path)
174 with open(log_path) as csvfile:
175 for field in DictReader(csvfile).fieldnames:
176 assert field in tuple(form_data.keys())
177
178
179 def test_field_err(form_config, form_data, log_path):
180 """
181 Submits a form that does not have the dame fields as previous submissions
182 that have the same form name, asserts that proper message is returned and
183 the row was properly written
184 """
185 formmail2.log_formdata(form_data, log_path)
186 del(form_config['fields']['email'])
187 del(form_data['email'])
188 try:
189 formmail2.log_formdata(form_data, log_path)
190 except Exception as e:
191 assert e.message == ('Field names have changed, error log '
192 'written to {}_error').format(log_path)
193
194 with open(log_path+'_error') as error_log:
195 assert DictReader(error_log).next() == form_data
196 178
197 179
198 def test_append_field_err(form_config, form_data, log_path): 180 def test_append_field_err(form_config, form_data, log_path):
199 """ 181 """ Checks that error logs are correctly written and appended
200 Submits two identical forms that do not match the previous fields 182
201 found in the log file, triggering two rows to be added to the error 183 Submits three forms, the second two have different fields to the first
202 log and asserting the proper message is returned and that the rows 184 and should be added to the same log file as each other, and be identical
203 were written as expected
204 """ 185 """
205 formmail2.log_formdata(form_data, log_path) 186 formmail2.log_formdata(form_data, log_path)
206 del(form_config['fields']['email']) 187 del form_data['email']
207 del(form_data['email']) 188
208 try: 189 # submit two forms with fields that dont match the config
190 # this should append the second form to the error log file
191 with pytest.raises(Exception):
209 formmail2.log_formdata(form_data, log_path) 192 formmail2.log_formdata(form_data, log_path)
210 except Exception: 193 with pytest.raises(Exception):
211 pass
212 try:
213 formmail2.log_formdata(form_data, log_path) 194 formmail2.log_formdata(form_data, log_path)
214 except Exception as e:
215 assert e.message == ('Field names have changed, error log'
216 ' appended to {}_error').format(log_path)
217 195
218 with open(log_path+'_error') as error_log: 196 with open(log_path + '_error') as error_log:
219 reader = DictReader(error_log) 197 reader = DictReader(error_log)
220 # two identical rows should be in the error log
221 assert reader.next() == form_data 198 assert reader.next() == form_data
222 assert reader.next() == form_data 199 assert reader.next() == form_data
223
224
225 def test_append_log(form_data, log_path):
226 """
227 Collect data twice, altering a field in the second call
228 assert that the 2nd row is equal to the resulting form data
229 """
230 form_data['time'] = str(datetime.datetime.now())
231 formmail2.log_formdata(form_data, log_path)
232 form_data['email'] = 'test@foo.com'
233 formmail2.log_formdata(form_data, log_path)
234 with open(log_path) as csvfile:
235 reader = DictReader(csvfile, fieldnames=form_data.keys())
236 # header
237 reader.next()
238 row1 = reader.next()
239 row2 = reader.next()
240
241 assert row2['email'] == form_data['email']
242 assert row2['email'] != row1['email']
LEFTRIGHT

Powered by Google App Engine
This is Rietveld