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

Side by Side Diff: tests/test_xtm_translate.py

Issue 29886648: Issue #6942 - Add XTM integration in CMS (Closed)
Patch Set: Addressed comments from Patch Set #4 Created Oct. 5, 2018, 4:23 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
OLDNEW
(Empty)
1 # This file is part of the Adblock Plus web scripts,
2 # Copyright (C) 2006-present eyeo GmbH
3 #
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
6 # published by the Free Software Foundation.
7 #
8 # Adblock Plus is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
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/>.
15
16 from __future__ import unicode_literals
17
18 import os
19 from ConfigParser import SafeConfigParser
20 import io
21 import sys
22 import json
23
24 import pytest
25
26 from cms.translations.xtm import constants as const
27 from cms.translations.xtm.projects_handler import (
28 create_project, upload_files, download_files,
29 )
30 from cms.translations.xtm.cli import (
31 generate_token, handle_projects as main_project_handler,
32 )
33
34 _CMD_START = ['python', '-m', 'cms.bin.xtm_translations']
35
36 _ENV_NO_TOKEN = dict(os.environ)
37 _ENV_NO_TOKEN.pop(const.Token.ENV_VAR, None)
38
39 _ENV_TOKEN_VALID = dict(os.environ)
40 _ENV_TOKEN_VALID[const.Token.ENV_VAR] = 'TheXTM-APIToken-VALID'
41
42 _ENV_TOKEN_INVALID = dict(os.environ)
43 _ENV_TOKEN_INVALID[const.Token.ENV_VAR] = 'TheXTM-APIToken-INVALID'
44
45
46 class _CreationArgsNamespace:
47 def __init__(self):
48 pass
49
50 name = 'bar'
51 desc = 'foo'
52 client_id = 10
53 ref_id = 'faz'
54 workflow_id = 20
55 save_id = False
56 source_dir = None
57 projects_func = staticmethod(create_project)
58 source_lang = 'en_US'
59
60
61 class _UploadArgsNamespace:
62 def __init__(self):
63 pass
64
65 source_dir = None
66 projects_func = staticmethod(upload_files)
67 no_overwrite = False
68
69
70 class _DownloadArgsNamespace:
71 def __init__(self):
72 pass
73
74 source_dir = None
75 projects_func = staticmethod(download_files)
76
77
78 _CREATION_ARGS_DEFAULT = ['--name', 'bar', '--desc', 'foo', '--client-id',
79 '10', '--ref-id', 'faz', '--workflow-id', '20']
80 _CREATION_ARGS_INVALID_TYPE_1 = ['--name', 'bar', '--desc', 'foo',
81 '--client-id', 'foo', '--ref-id', 'faz',
82 '--workflow-id', '3']
83 _CREATION_ARGS_INVALID_TYPE_2 = ['--name', 'bar', '--desc', 'foo',
84 '--client-id', '23', '--ref-id', 'faz',
85 '--workflow-id', 'foo']
86
87
88 @pytest.fixture
89 def env_valid_token():
90 old_env = os.environ
91 os.environ = _ENV_TOKEN_VALID
92 yield True
93 os.environ = old_env
94
95
96 @pytest.mark.script_launch_mode('subprocess')
97 @pytest.mark.parametrize('args,exp_msg', [
98 (['-h'], 'usage: xtm_translations.py [-h] [-v] '
99 '{login,create,upload,download} ...'),
100 (['create', '-h'], 'usage: xtm_translations.py create [-h] --name NAME '
101 '--desc DESC --client-id CLIENT_ID --ref-id REF_ID '
102 '--workflow-id WORKFLOW_ID [--source-lang SOURCE_LANG] '
103 '[--save-id] [source_dir]'),
104 (['upload', '-h'], 'usage: xtm_translations.py upload [-h] '
105 '[--no-overwrite] [source_dir]'),
106 (['download', '-h'], 'usage: xtm_translations.py download [-h] '
107 '[source_dir]'),
108 ])
109 def test_usage_messages(args, exp_msg, script_runner):
110 """Test if appropriate usage messages are displayed."""
111 cmd = list(_CMD_START)
112 cmd.extend(args)
113 ret = script_runner.run(*cmd)
114
115 usg_msg = ret.stdout.replace('\n', '').replace(' ', '')
116
117 assert exp_msg.replace(' ', '') in usg_msg
118
119
120 @pytest.mark.script_launch_mode('subprocess')
121 @pytest.mark.parametrize('args', [
122 ['create', '--name', 'bar', '--desc', 'foo', '--client-id', '1',
123 '--ref-id', 'faz', '--workflow-id', '3'],
124 ['upload'],
125 ['download'],
126 ])
127 def test_default_source_directory(args, script_runner):
128 """Test if the source directory if set to default if not provided."""
129 exp = const.ErrorMessages.NO_TOKEN_PROVIDED.split('\n')[0]
130 cmd = list(_CMD_START)
131 cmd.extend(args)
132
133 ret = script_runner.run(*cmd)
134
135 assert not ret.success
136 assert exp in ret.stderr
137
138
139 @pytest.mark.script_launch_mode('subprocess')
140 @pytest.mark.parametrize('source_dir,args,env,exp_msg', [
141 ('str(temp_site)', _CREATION_ARGS_INVALID_TYPE_1, _ENV_NO_TOKEN,
142 "--client-id: invalid int value: 'foo'"),
143 ('str(temp_site)', _CREATION_ARGS_INVALID_TYPE_2, _ENV_NO_TOKEN,
144 "--workflow-id: invalid int value: 'foo'"),
145 ('str(temp_site)', _CREATION_ARGS_DEFAULT, _ENV_NO_TOKEN,
146 const.ErrorMessages.NO_TOKEN_PROVIDED.split('\n')[0]),
147 ('str(temp_site_valid_project)', _CREATION_ARGS_DEFAULT, _ENV_TOKEN_VALID,
148 const.ErrorMessages.PROJECT_EXISTS.format(1234)),
149 ('str(temp_site)', _CREATION_ARGS_DEFAULT, _ENV_TOKEN_INVALID,
150 'Authentication failed'),
151 ])
152 def test_creation_error_messages(temp_site, intercept, script_runner, args,
153 source_dir, temp_site_valid_project, env,
154 exp_msg):
155 """Test if error cases are treated correctly when creating a project."""
156 cmd = list(_CMD_START)
157 cmd.extend(['create', eval(source_dir)])
158 cmd.extend(args)
159
160 ret = script_runner.run(*cmd, env=env)
161
162 assert not ret.success
163 assert exp_msg in ret.stderr
164
165
166 def test_creation_correct(temp_site, intercept, env_valid_token):
167 """Test if a project is created correctly, given the appropriate args."""
168 namespace = _CreationArgsNamespace()
169 namespace.source_dir = str(temp_site)
170 main_project_handler(namespace)
171
172
173 def test_creation_save_id(temp_site, intercept, env_valid_token):
174 """Test the project id is saved after successfully creating a project."""
175 namespace = _CreationArgsNamespace()
176 namespace.source_dir = str(temp_site)
177 namespace.save_id = True
178 main_project_handler(namespace)
179 cnf = SafeConfigParser()
180 try:
181 with io.open(os.path.join(temp_site, 'settings.ini'),
182 encoding='utf-8') as f:
183 cnf_data = f.read()
184 cnf.readfp(io.StringIO(cnf_data))
185 project_id = cnf.get(const.Config.XTM_SECTION,
186 const.Config.PROJECT_OPTION)
187
188 assert int(project_id) == 1234
189 finally:
190 cnf.remove_option(const.Config.XTM_SECTION,
191 const.Config.PROJECT_OPTION)
192 cnf.write(open(os.path.join(temp_site, 'settings.ini'), 'w'))
193
194
195 def test_login(intercept, monkeypatch, capsys):
196 """Test if the login functionality works as expected."""
197 exp_output = const.Token.SAVE_COMMAND.format(const.Token.ENV_VAR,
198 'TheXTM-APIToken-VALID')
199 monkeypatch.setattr(
200 'cms.translations.xtm.cli.input_fn',
201 lambda inp: 'admin' if 'username' in inp.lower() else '20',
202 )
203 monkeypatch.setattr('getpass.getpass', lambda prompt: 'pass')
204
205 generate_token(None)
206 out, err = capsys.readouterr()
207
208 assert err == ''
209 assert exp_output in out
210
211
212 def test_login_wrong_credentials(intercept, monkeypatch, capsys):
213 """Test exception handling when generating the tokens."""
214 monkeypatch.setattr(
215 'cms.translations.xtm.cli.input_fn',
216 lambda inp: 'foo' if 'username' in inp.lower() else '50',
217 )
218 monkeypatch.setattr('getpass.getpass', lambda prompt: 'pass')
219 monkeypatch.setattr('sys.exit', lambda x: sys.stderr.write(str(x)))
220
221 generate_token(None)
222 out, err = capsys.readouterr()
223
224 assert 'Invalid credentials' in err
225 assert out == ''
226
227
228 @pytest.mark.script_launch_mode('subprocess')
229 @pytest.mark.parametrize('args,env,exp_msg', [
230 (['str(temp_site)'], _ENV_NO_TOKEN,
231 const.ErrorMessages.NO_TOKEN_PROVIDED.split('\n')[0]),
232 (['str(temp_site)'], _ENV_TOKEN_VALID, 'No project configured'),
233 ])
234 def test_upload_error_messages_as_script(temp_site, script_runner, args, env,
235 exp_msg):
236 cmd = list(_CMD_START)
237 cmd.append('upload')
238
239 cmd.extend(list(map(eval, args)))
240
241 ret = script_runner.run(*cmd, env=env)
242
243 assert not ret.success
244 assert exp_msg in ret.stderr
245
246
247 def test_upload_too_many_languages(intercept_too_many_targets,
248 env_valid_token, temp_site_valid_project):
249 namespace = _UploadArgsNamespace()
250 namespace.source_dir = str(temp_site_valid_project)
251
252 with pytest.raises(Exception) as err:
253 main_project_handler(namespace)
254
255 assert 'languages are enabled in the API, but not listed in locales' in \
256 str(err.value)
257
258
259 def test_upload_successful(intercept, env_valid_token,
260 temp_site_valid_project, monkeypatch, capsys):
261 namespace = _UploadArgsNamespace()
262 namespace.source_dir = str(temp_site_valid_project)
263 monkeypatch.setattr('logging.info', lambda x: sys.stderr.write(x))
264
265 main_project_handler(namespace)
266 _, err = capsys.readouterr()
267
268 assert const.InfoMessages.FILES_UPLOADED in err
269 assert 'Created job 1' in err
270
271
272 @pytest.mark.script_launch_mode('subprocess')
273 @pytest.mark.parametrize('env,exp_msg', [
274 (_ENV_NO_TOKEN, const.ErrorMessages.NO_TOKEN_PROVIDED.split('\n')[0]),
275 (_ENV_TOKEN_VALID, 'No project configured'),
276 ])
277 def test_download_error_messages_as_script(temp_site, script_runner, env,
278 exp_msg):
279 cmd = list(_CMD_START)
280 cmd.extend(['download', str(temp_site)])
281
282 ret = script_runner.run(*cmd, env=env)
283
284 assert not ret.success
285 assert exp_msg in ret.stderr
286
287
288 def test_download_no_target_files(temp_site_no_target_files, env_valid_token,
289 intercept, monkeypatch, capsys):
290 namespace = _DownloadArgsNamespace()
291 namespace.source_dir = str(temp_site_no_target_files)
292 monkeypatch.setattr('sys.exit', lambda x: sys.stderr.write(x))
293
294 main_project_handler(namespace)
295 out, err = capsys.readouterr()
296
297 assert const.ErrorMessages.NO_TARGET_FILES_FOUND in err
298
299
300 def test_download_saves_to_disk(temp_site_valid_project, env_valid_token,
301 intercept_populated):
302 namespace = _DownloadArgsNamespace()
303 namespace.source_dir = str(temp_site_valid_project)
304
305 main_project_handler(namespace)
306
307 with open(os.path.join(temp_site_valid_project, 'locales', 'de',
308 'file.json')) as f:
309 assert json.dumps({'foo': 'bar', 'faz': 'baz'}) == f.read()
310
311 with open(os.path.join(temp_site_valid_project, 'locales', 'de', 'foo',
312 'file-utf8.json'), 'rb') as f:
313 assert json.loads(f.read()) == {'foo': '\u1234'}
OLDNEW

Powered by Google App Engine
This is Rietveld