blob: 6180133994f8e583d12a5bdc4497e9cf7b9c632a [file] [log] [blame]
Benjamin Peterson92035012008-12-27 16:00:54 +00001"""Tests for distutils.command.register."""
Benjamin Peterson92035012008-12-27 16:00:54 +00002import os
3import unittest
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +00004import getpass
Tarek Ziadébaf51802009-03-31 21:37:16 +00005import urllib
Tarek Ziadé5af55c62009-05-16 16:52:13 +00006import warnings
7
Éric Araujob344dd02011-02-02 21:38:37 +00008from test.support import check_warnings, run_unittest
Benjamin Peterson92035012008-12-27 16:00:54 +00009
Tarek Ziadébaf51802009-03-31 21:37:16 +000010from distutils.command import register as register_module
Benjamin Peterson92035012008-12-27 16:00:54 +000011from distutils.command.register import register
Tarek Ziadé5af55c62009-05-16 16:52:13 +000012from distutils.errors import DistutilsSetupError
Antoine Pitrou716b7222013-12-21 22:57:56 +010013from distutils.log import INFO
Benjamin Peterson92035012008-12-27 16:00:54 +000014
Éric Araujo8b503c02012-12-08 22:41:11 -050015from distutils.tests.test_config import PyPIRCCommandTestCase
16
17try:
18 import docutils
19except ImportError:
20 docutils = None
Benjamin Peterson92035012008-12-27 16:00:54 +000021
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +000022PYPIRC_NOPASSWORD = """\
23[distutils]
24
25index-servers =
26 server1
27
28[server1]
29username:me
30"""
31
32WANTED_PYPIRC = """\
33[distutils]
34index-servers =
35 pypi
36
37[pypi]
38username:tarek
39password:password
40"""
41
42class Inputs(object):
Benjamin Peterson92035012008-12-27 16:00:54 +000043 """Fakes user inputs."""
44 def __init__(self, *answers):
45 self.answers = answers
46 self.index = 0
47
48 def __call__(self, prompt=''):
49 try:
50 return self.answers[self.index]
51 finally:
52 self.index += 1
53
Tarek Ziadébaf51802009-03-31 21:37:16 +000054class FakeOpener(object):
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +000055 """Fakes a PyPI server"""
56 def __init__(self):
Tarek Ziadébaf51802009-03-31 21:37:16 +000057 self.reqs = []
Benjamin Peterson92035012008-12-27 16:00:54 +000058
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +000059 def __call__(self, *args):
Tarek Ziadébaf51802009-03-31 21:37:16 +000060 return self
61
Antoine Pitrou716b7222013-12-21 22:57:56 +010062 def open(self, req, data=None, timeout=None):
Tarek Ziadébaf51802009-03-31 21:37:16 +000063 self.reqs.append(req)
64 return self
65
66 def read(self):
Antoine Pitrou716b7222013-12-21 22:57:56 +010067 return b'xxx'
68
69 def getheader(self, name, default=None):
70 return {
71 'content-type': 'text/plain; charset=utf-8',
72 }.get(name.lower(), default)
73
Benjamin Peterson92035012008-12-27 16:00:54 +000074
Tarek Ziadé5af55c62009-05-16 16:52:13 +000075class RegisterTestCase(PyPIRCCommandTestCase):
Benjamin Peterson92035012008-12-27 16:00:54 +000076
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +000077 def setUp(self):
Hirokazu Yamamoto2703fd92009-05-29 09:14:04 +000078 super(RegisterTestCase, self).setUp()
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +000079 # patching the password prompt
80 self._old_getpass = getpass.getpass
81 def _getpass(prompt):
82 return 'password'
83 getpass.getpass = _getpass
Antoine Pitrou67834872013-12-22 00:44:01 +010084 urllib.request._opener = None
Tarek Ziadébaf51802009-03-31 21:37:16 +000085 self.old_opener = urllib.request.build_opener
86 self.conn = urllib.request.build_opener = FakeOpener()
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +000087
88 def tearDown(self):
89 getpass.getpass = self._old_getpass
Antoine Pitrou67834872013-12-22 00:44:01 +010090 urllib.request._opener = None
Tarek Ziadébaf51802009-03-31 21:37:16 +000091 urllib.request.build_opener = self.old_opener
Hirokazu Yamamoto2703fd92009-05-29 09:14:04 +000092 super(RegisterTestCase, self).tearDown()
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +000093
Tarek Ziadé5af55c62009-05-16 16:52:13 +000094 def _get_cmd(self, metadata=None):
95 if metadata is None:
96 metadata = {'url': 'xxx', 'author': 'xxx',
97 'author_email': 'xxx',
98 'name': 'xxx', 'version': 'xxx'}
Tarek Ziadébaf51802009-03-31 21:37:16 +000099 pkg_info, dist = self.create_dist(**metadata)
100 return register(dist)
101
Benjamin Peterson92035012008-12-27 16:00:54 +0000102 def test_create_pypirc(self):
103 # this test makes sure a .pypirc file
104 # is created when requested.
105
Tarek Ziadébaf51802009-03-31 21:37:16 +0000106 # let's create a register instance
107 cmd = self._get_cmd()
Benjamin Peterson92035012008-12-27 16:00:54 +0000108
109 # we shouldn't have a .pypirc file yet
Serhiy Storchaka39989152013-11-17 00:17:46 +0200110 self.assertFalse(os.path.exists(self.rc))
Benjamin Peterson92035012008-12-27 16:00:54 +0000111
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +0000112 # patching input and getpass.getpass
Benjamin Peterson92035012008-12-27 16:00:54 +0000113 # so register gets happy
114 #
115 # Here's what we are faking :
116 # use your existing login (choice 1.)
117 # Username : 'tarek'
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +0000118 # Password : 'password'
Benjamin Peterson92035012008-12-27 16:00:54 +0000119 # Save your login (y/N)? : 'y'
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +0000120 inputs = Inputs('1', 'tarek', 'y')
Benjamin Peterson467a7bd2008-12-27 17:00:44 +0000121 register_module.input = inputs.__call__
Benjamin Peterson92035012008-12-27 16:00:54 +0000122 # let's run the command
Tarek Ziadébaf51802009-03-31 21:37:16 +0000123 try:
124 cmd.run()
125 finally:
126 del register_module.input
Benjamin Peterson92035012008-12-27 16:00:54 +0000127
128 # we should have a brand new .pypirc file
Georg Brandlab91fde2009-08-13 08:51:18 +0000129 self.assertTrue(os.path.exists(self.rc))
Benjamin Peterson92035012008-12-27 16:00:54 +0000130
131 # with the content similar to WANTED_PYPIRC
Éric Araujoc6d7ead2010-11-06 02:58:56 +0000132 f = open(self.rc)
133 try:
134 content = f.read()
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000135 self.assertEqual(content, WANTED_PYPIRC)
Éric Araujoc6d7ead2010-11-06 02:58:56 +0000136 finally:
137 f.close()
Benjamin Peterson92035012008-12-27 16:00:54 +0000138
139 # now let's make sure the .pypirc file generated
140 # really works : we shouldn't be asked anything
141 # if we run the command again
142 def _no_way(prompt=''):
143 raise AssertionError(prompt)
Tarek Ziadébaf51802009-03-31 21:37:16 +0000144 register_module.input = _no_way
Benjamin Peterson92035012008-12-27 16:00:54 +0000145
Tarek Ziadébaf51802009-03-31 21:37:16 +0000146 cmd.show_response = 1
Benjamin Peterson92035012008-12-27 16:00:54 +0000147 cmd.run()
148
149 # let's see what the server received : we should
150 # have 2 similar requests
Éric Araujo691840f2011-04-14 03:49:19 +0200151 self.assertEqual(len(self.conn.reqs), 2)
Tarek Ziadébaf51802009-03-31 21:37:16 +0000152 req1 = dict(self.conn.reqs[0].headers)
153 req2 = dict(self.conn.reqs[1].headers)
154
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000155 self.assertEqual(req1['Content-length'], '1374')
156 self.assertEqual(req2['Content-length'], '1374')
Serhiy Storchaka39989152013-11-17 00:17:46 +0200157 self.assertIn(b'xxx', self.conn.reqs[1].data)
Benjamin Peterson92035012008-12-27 16:00:54 +0000158
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +0000159 def test_password_not_in_file(self):
160
Tarek Ziadébaf51802009-03-31 21:37:16 +0000161 self.write_file(self.rc, PYPIRC_NOPASSWORD)
162 cmd = self._get_cmd()
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +0000163 cmd._set_config()
164 cmd.finalize_options()
165 cmd.send_metadata()
166
167 # dist.password should be set
168 # therefore used afterwards by other commands
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000169 self.assertEqual(cmd.distribution.password, 'password')
Tarek Ziadébaf51802009-03-31 21:37:16 +0000170
171 def test_registering(self):
172 # this test runs choice 2
173 cmd = self._get_cmd()
174 inputs = Inputs('2', 'tarek', 'tarek@ziade.org')
175 register_module.input = inputs.__call__
176 try:
177 # let's run the command
178 cmd.run()
179 finally:
180 del register_module.input
181
182 # we should have send a request
Éric Araujo691840f2011-04-14 03:49:19 +0200183 self.assertEqual(len(self.conn.reqs), 1)
Tarek Ziadébaf51802009-03-31 21:37:16 +0000184 req = self.conn.reqs[0]
185 headers = dict(req.headers)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000186 self.assertEqual(headers['Content-length'], '608')
Serhiy Storchaka39989152013-11-17 00:17:46 +0200187 self.assertIn(b'tarek', req.data)
Tarek Ziadébaf51802009-03-31 21:37:16 +0000188
189 def test_password_reset(self):
190 # this test runs choice 3
191 cmd = self._get_cmd()
192 inputs = Inputs('3', 'tarek@ziade.org')
193 register_module.input = inputs.__call__
194 try:
195 # let's run the command
196 cmd.run()
197 finally:
198 del register_module.input
199
200 # we should have send a request
Éric Araujo691840f2011-04-14 03:49:19 +0200201 self.assertEqual(len(self.conn.reqs), 1)
Tarek Ziadébaf51802009-03-31 21:37:16 +0000202 req = self.conn.reqs[0]
203 headers = dict(req.headers)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000204 self.assertEqual(headers['Content-length'], '290')
Serhiy Storchaka39989152013-11-17 00:17:46 +0200205 self.assertIn(b'tarek', req.data)
Tarek Ziadé13f7c3b2009-01-09 00:15:45 +0000206
Éric Araujo8b503c02012-12-08 22:41:11 -0500207 @unittest.skipUnless(docutils is not None, 'needs docutils')
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000208 def test_strict(self):
209 # testing the script option
210 # when on, the register command stops if
211 # the metadata is incomplete or if
212 # long_description is not reSt compliant
213
214 # empty metadata
215 cmd = self._get_cmd({})
216 cmd.ensure_finalized()
217 cmd.strict = 1
218 self.assertRaises(DistutilsSetupError, cmd.run)
219
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000220 # metadata are OK but long_description is broken
221 metadata = {'url': 'xxx', 'author': 'xxx',
Éric Araujo5819dcc2011-10-09 07:25:33 +0200222 'author_email': 'éxéxé',
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000223 'name': 'xxx', 'version': 'xxx',
224 'long_description': 'title\n==\n\ntext'}
225
226 cmd = self._get_cmd(metadata)
227 cmd.ensure_finalized()
228 cmd.strict = 1
229 self.assertRaises(DistutilsSetupError, cmd.run)
230
231 # now something that works
232 metadata['long_description'] = 'title\n=====\n\ntext'
233 cmd = self._get_cmd(metadata)
234 cmd.ensure_finalized()
235 cmd.strict = 1
Tarek Ziadéc9afba82010-10-03 14:30:11 +0000236 inputs = Inputs('1', 'tarek', 'y')
237 register_module.input = inputs.__call__
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000238 # let's run the command
239 try:
240 cmd.run()
241 finally:
Tarek Ziadéc9afba82010-10-03 14:30:11 +0000242 del register_module.input
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000243
244 # strict is not by default
245 cmd = self._get_cmd()
246 cmd.ensure_finalized()
Tarek Ziadéc9afba82010-10-03 14:30:11 +0000247 inputs = Inputs('1', 'tarek', 'y')
248 register_module.input = inputs.__call__
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000249 # let's run the command
250 try:
251 cmd.run()
252 finally:
Tarek Ziadéc9afba82010-10-03 14:30:11 +0000253 del register_module.input
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000254
Éric Araujo5819dcc2011-10-09 07:25:33 +0200255 # and finally a Unicode test (bug #12114)
256 metadata = {'url': 'xxx', 'author': '\u00c9ric',
257 'author_email': 'xxx', 'name': 'xxx',
258 'version': 'xxx',
259 'description': 'Something about esszet \u00df',
260 'long_description': 'More things about esszet \u00df'}
261
262 cmd = self._get_cmd(metadata)
263 cmd.ensure_finalized()
264 cmd.strict = 1
265 inputs = Inputs('1', 'tarek', 'y')
266 register_module.input = inputs.__call__
267 # let's run the command
268 try:
269 cmd.run()
270 finally:
271 del register_module.input
272
Éric Araujo8b503c02012-12-08 22:41:11 -0500273 @unittest.skipUnless(docutils is not None, 'needs docutils')
274 def test_register_invalid_long_description(self):
275 description = ':funkie:`str`' # mimic Sphinx-specific markup
276 metadata = {'url': 'xxx', 'author': 'xxx',
277 'author_email': 'xxx',
278 'name': 'xxx', 'version': 'xxx',
279 'long_description': description}
280 cmd = self._get_cmd(metadata)
281 cmd.ensure_finalized()
282 cmd.strict = True
283 inputs = Inputs('2', 'tarek', 'tarek@ziade.org')
284 register_module.input = inputs
285 self.addCleanup(delattr, register_module, 'input')
286
287 self.assertRaises(DistutilsSetupError, cmd.run)
288
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000289 def test_check_metadata_deprecated(self):
290 # makes sure make_metadata is deprecated
291 cmd = self._get_cmd()
292 with check_warnings() as w:
293 warnings.simplefilter("always")
294 cmd.check_metadata()
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000295 self.assertEqual(len(w.warnings), 1)
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000296
Antoine Pitrou716b7222013-12-21 22:57:56 +0100297 def test_list_classifiers(self):
298 cmd = self._get_cmd()
299 cmd.list_classifiers = 1
300 cmd.run()
301 results = self.get_logs(INFO)
302 self.assertEqual(results, ['running check', 'xxx'])
303
304
Benjamin Peterson92035012008-12-27 16:00:54 +0000305def test_suite():
Tarek Ziadé5af55c62009-05-16 16:52:13 +0000306 return unittest.makeSuite(RegisterTestCase)
Benjamin Peterson92035012008-12-27 16:00:54 +0000307
308if __name__ == "__main__":
Éric Araujob344dd02011-02-02 21:38:37 +0000309 run_unittest(test_suite())