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

Side by Side Diff: sitescripts/formmail/test/test_formmail2.py

Issue 29374647: Issue 4814 - Adds csv log to formmail2 (Closed) Base URL: https://hg.adblockplus.org/sitescripts
Patch Set: refactor tests to be parametrized, reducing duplication. Addressed some redundancies Created March 22, 2017, 8:14 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « .sitescripts.example ('k') | sitescripts/formmail/web/formmail2.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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-2017 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 from urllib import urlencode 16 from urllib import urlencode
16 from urllib2 import urlopen, HTTPError 17 from urllib2 import urlopen, HTTPError
18 from csv import DictReader
17 19
18 import pytest 20 import pytest
19 from wsgi_intercept import (urllib_intercept, add_wsgi_intercept, 21 from wsgi_intercept import (urllib_intercept, add_wsgi_intercept,
20 remove_wsgi_intercept) 22 remove_wsgi_intercept)
21 23
22 from sitescripts.formmail.web import formmail2 24 from sitescripts.formmail.web import formmail2
23 25
26 HOST = 'test.local'
27 LOG_PORT = 80
28 NO_LOG_PORT = 81
24 29
25 @pytest.fixture() 30
26 def form_config(): 31 @pytest.fixture
32 def log_path(tmpdir):
33 return str(tmpdir.join('test.csv_log'))
34
35
36 @pytest.fixture
37 def log_form_config():
27 return formmail2.conf_parse(formmail2.get_config_items())['test'] 38 return formmail2.conf_parse(formmail2.get_config_items())['test']
28 39
29 40
30 @pytest.fixture() 41 @pytest.fixture
31 def form_handler(form_config): 42 def form_config():
32 return formmail2.make_handler('test', form_config)[1] 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])
33 54
34 55
35 # 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
36 # test as needed without affecting other tests. 57 # test as needed without affecting other tests.
37 @pytest.fixture 58 @pytest.fixture
38 def form_data(): 59 def form_data():
39 return { 60 return {
40 'email': 'john_doe@gmail.com', 61 'email': 'john_doe@gmail.com',
41 'mandatory': 'john_doe@gmail.com', 62 'mandatory': 'john_doe@gmail.com',
42 'non_mandatory_message': 'Once upon a time\nthere lived a king.', 63 'non_mandatory_message': 'Once upon a time\nthere lived a king.',
43 'non_mandatory_email': 'test@test.com' 64 'non_mandatory_email': 'test@test.com',
44 } 65 }
45 66
46 67
47 @pytest.fixture() 68 @pytest.fixture
48 def response_for(form_handler): 69 def response_for(form_handler):
49 host, port = 'test.local', 80 70 """ Registers two intercepts, returns responses for them based on bool """
50 urllib_intercept.install_opener() 71 urllib_intercept.install_opener()
51 add_wsgi_intercept(host, port, lambda: form_handler) 72 add_wsgi_intercept(HOST, LOG_PORT, lambda: form_handler[0])
52 url = 'http://{}:{}'.format(host, port) 73 add_wsgi_intercept(HOST, NO_LOG_PORT, lambda: form_handler[1])
53 74
54 def response_for(data): 75 def response_for(data, log=False):
76 if log:
77 url = 'http://{}:{}'.format(HOST, LOG_PORT)
78 else:
79 url = 'http://{}:{}'.format(HOST, NO_LOG_PORT)
55 if data is None: 80 if data is None:
56 response = urlopen(url) 81 response = urlopen(url)
57 else: 82 else:
58 response = urlopen(url, urlencode(data)) 83 response = urlopen(url, urlencode(data))
59 return response.code, response.read() 84 return response.code, response.read()
60 85
61 yield response_for 86 yield response_for
62 remove_wsgi_intercept() 87 remove_wsgi_intercept()
63 88
64 89
65 def test_form_handler_email_errors(form_config): 90 @pytest.fixture
66 tmp_config = form_config 91 def sm_mock(mocker):
67 del tmp_config['url'].value 92 return mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
68 with pytest.raises(Exception) as error:
69 formmail2.make_handler('test', tmp_config)[1]
70 assert error.value.message == 'No URL configured for form handler: test'
71 93
72 94
73 def test_form_handler_field_errors(form_config): 95 @pytest.mark.parametrize('key,message', [
74 tmp_config = form_config 96 ('url', 'No URL configured for form handler: test'),
75 tmp_config['fields'] = {} 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]
76 with pytest.raises(Exception) as error: 102 with pytest.raises(Exception) as error:
77 formmail2.make_handler('test', tmp_config)[1] 103 formmail2.make_handler('test', form_config)[1]
78 assert error.value.message == 'No fields configured for form handler: test' 104 assert error.value.message == message
79 105
80 del tmp_config['fields'] 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 assert row != reader.next()
Vasily Kuznetsov 2017/03/23 13:19:16 Are they not equal because of time field? What do
Jon Sonesen 2017/03/23 13:31:01 Done.
147
148
149 def test_config_field_errors(form_config):
150 form_config['fields'] = {}
81 with pytest.raises(Exception) as error: 151 with pytest.raises(Exception) as error:
82 formmail2.make_handler('test', tmp_config)[1] 152 formmail2.make_handler('test', form_config)[1]
83 assert error.value.message == 'No fields configured for form handler: test' 153 assert error.value.message == 'No fields configured for form handler: test'
84 154
85 155
86 def test_form_handler_template_errors(form_config): 156 def test_config_template_errors(form_config):
87 tmp_config = form_config 157 form_config['template'].value = 'no'
88 tmp_config['template'].value = 'no'
89 with pytest.raises(Exception) as error: 158 with pytest.raises(Exception) as error:
90 formmail2.make_handler('test', tmp_config)[1] 159 formmail2.make_handler('test', form_config)[1]
91 assert error.typename == 'TemplateNotFound' 160 assert error.value.message == 'Template not found at: no'
92
93 del tmp_config['template'].value
94 with pytest.raises(Exception) as error:
95 formmail2.make_handler('test', tmp_config)[1]
96 assert error.value.message == ('No template configured for form handler'
97 ': test')
98 del tmp_config['template']
99 with pytest.raises(Exception) as error:
100 formmail2.make_handler('test', tmp_config)[1]
101 assert error.value.message == ('No template configured for form handler'
102 ': test')
103 161
104 162
105 def test_config_parse(form_config): 163 def test_config_parse(form_config):
106 assert form_config['url'].value == 'test/apply/submit' 164 assert form_config['url'].value == 'test/apply/submit'
107 assert form_config['fields']['email'].value == 'mandatory, email' 165 assert form_config['fields']['email'].value == 'mandatory, email'
108 166
109 167
110 def test_success(response_for, form_data, mocker): 168 def test_sendmail_fail(log_path, response_for, form_data, sm_mock):
111 sm_mock = mocker.patch('sitescripts.formmail.web.formmail2.sendMail') 169 sm_mock.side_effect = Exception('Sendmail Fail')
112 assert response_for(form_data) == (200, '') 170 with pytest.raises(HTTPError) as error:
113 assert sm_mock.call_count == 1 171 response_for(form_data, log=True)
114 params = sm_mock.call_args[0][1]['fields'] 172 assert error.typename == 'HTTPError'
Vasily Kuznetsov 2017/03/23 13:19:16 You probably don't need to assert this since you'v
Jon Sonesen 2017/03/23 13:31:01 Acknowledged.
115 assert set(params.keys()) == set(form_data.keys()) 173
116 for key, value in form_data.items(): 174 with open(log_path) as log_file:
117 assert params[key] == value 175 row = DictReader(log_file).next()
176 assert 'time' in row
118 177
119 178
120 def test_non_mandatory_no_msg(response_for, form_data, mocker): 179 def test_append_field_err(form_config, form_data, log_path):
121 mocker.patch('sitescripts.formmail.web.formmail2.sendMail') 180 """ Checks that error logs are correctly written and appended
122 form_data['non_mandatory'] = ''
123 assert response_for(form_data) == (200, '')
124 181
182 Submits three forms, the second two have different fields to the first
183 and should be added to the same log file as each other, and be identical
184 """
185 formmail2.log_formdata(form_data, log_path)
186 del(form_data['email'])
187 try:
188 formmail2.log_formdata(form_data, log_path)
189 except Exception as e:
Vasily Kuznetsov 2017/03/23 13:19:16 Perhaps it's better to use with pytest.raises(...)
Jon Sonesen 2017/03/23 13:31:01 Done. Odd that I chose to use try's in the first p
190 assert e.message == ('Field names have changed, error log '
191 'written to {}_error').format(log_path)
192 try:
Vasily Kuznetsov 2017/03/23 13:19:16 I suppose there's some reason for trying this twic
Jon Sonesen 2017/03/23 13:31:01 Done.
193 formmail2.log_formdata(form_data, log_path)
194 except Exception as e:
195 assert e.message == ('Field names have changed, error log'
Vasily Kuznetsov 2017/03/23 13:19:16 Do we need to assert the whole message here again
Jon Sonesen 2017/03/23 13:31:01 Agreed, I will remove the assertions
196 ' appended to {}_error').format(log_path)
125 197
126 def test_invalid_email_cstm_msg(response_for, form_data, mocker, form_config): 198 with open(log_path + '_error') as error_log:
127 mocker.patch('sitescripts.formmail.web.formmail2.sendMail') 199 reader = DictReader(error_log)
128 form_data['email'] = 'bademail' 200 assert reader.next() == form_data
129 with pytest.raises(HTTPError) as error: 201 assert reader.next() == form_data
130 response_for(form_data)
131 assert error.value.read() == 'You failed the email validation'
132
133
134 def test_valid_nan_mandatory_email(response_for, form_data, mocker):
135 mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
136 form_data['non_mandatory_email'] = 'asfaf'
137 with pytest.raises(HTTPError) as error:
138 response_for(form_data)
139 assert error.value.read() == 'Invalid email'
140
141 del form_data['non_mandatory_email']
142 assert response_for(form_data) == (200, '')
143
144
145 def test_mandatory_fail_dflt_msg(response_for, form_data, mocker):
146 mocker.patch('sitescripts.formmail.web.formmail2.sendMail')
147 del form_data['mandatory']
148 with pytest.raises(HTTPError) as error:
149 response_for(form_data)
150 assert error.value.read() == 'No mandatory entered'
OLDNEW
« no previous file with comments | « .sitescripts.example ('k') | sitescripts/formmail/web/formmail2.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld