Merge lp:~cjohnston/uci-engine/cli-requests into lp:uci-engine

Proposed by Chris Johnston
Status: Merged
Approved by: Chris Johnston
Approved revision: 502
Merged at revision: 518
Proposed branch: lp:~cjohnston/uci-engine/cli-requests
Merge into: lp:uci-engine
Diff against target: 782 lines (+202/-160)
11 files modified
cli/ci_cli/image.py (+5/-4)
cli/ci_cli/status.py (+5/-4)
cli/ci_cli/tests/__init__.py (+43/-0)
cli/ci_cli/tests/test_cli.py (+56/-44)
cli/ci_cli/tests/test_get_ticket_status.py (+31/-31)
cli/ci_cli/tests/test_image.py (+22/-38)
cli/ci_cli/tests/test_utils.py (+13/-12)
cli/ci_cli/utils.py (+9/-14)
cli/setup.py (+1/-0)
cli/ubuntu-ci (+16/-13)
debian/control (+1/-0)
To merge this branch: bzr merge lp:~cjohnston/uci-engine/cli-requests
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Andy Doan (community) Approve
Chris Johnston (community) Needs Resubmitting
Review via email: mp+220960@code.launchpad.net

Commit message

Switch the CLI to use python-requests

Description of the change

Swiftclient is already using python-requests, and I think that using python-requests will make working with the gatekeeper easier so lets switch to using it for the CLI.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:499
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cjohnston/uci-engine/cli-requests/+merge/220960/+edit-commit-message

http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/701/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/701/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:499
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/703/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/703/rebuild

review: Approve (continuous-integration)
Revision history for this message
Andy Doan (doanac) wrote :

nothing major, but 3 comments

500. By Chris Johnston

Remove double code block for exceptions

501. By Chris Johnston

Update test to call ConnectionError on socket.error

502. By Chris Johnston

More cleanup

Revision history for this message
Chris Johnston (cjohnston) :
review: Needs Resubmitting
Revision history for this message
Andy Doan (doanac) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:502
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/706/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/706/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'cli/ci_cli/image.py'
--- cli/ci_cli/image.py 2014-05-07 14:56:11 +0000
+++ cli/ci_cli/image.py 2014-05-27 09:44:30 +0000
@@ -15,7 +15,8 @@
1515
16import os16import os
17import sys17import sys
18import urllib218
19from requests import exceptions
1920
20from ci_cli import utils21from ci_cli import utils
21from ci_utils import (22from ci_utils import (
@@ -41,11 +42,11 @@
41 url = artifact_base + '?type__exact=IMAGE&ticket__exact={}'.format(42 url = artifact_base + '?type__exact=IMAGE&ticket__exact={}'.format(
42 ticket)43 ticket)
43 return utils.get(url)44 return utils.get(url)
44 except urllib2.HTTPError, exc:45 except exceptions.HTTPError, exc:
45 if exc.code == 404 and ticket:46 if exc.response.status_code == 404 and ticket:
46 sys.exit("Ticket number {} not found.".format(ticket))47 sys.exit("Ticket number {} not found.".format(ticket))
47 raise48 raise
48 except urllib2.URLError, exc:49 except exceptions.ConnectionError, exc:
49 raise50 raise
5051
5152
5253
=== modified file 'cli/ci_cli/status.py'
--- cli/ci_cli/status.py 2014-05-07 14:56:11 +0000
+++ cli/ci_cli/status.py 2014-05-27 09:44:30 +0000
@@ -14,7 +14,8 @@
14# with this program. If not, see <http://www.gnu.org/licenses/>.14# with this program. If not, see <http://www.gnu.org/licenses/>.
1515
16import sys16import sys
17import urllib217
18from requests import exceptions
1819
19from ci_cli import utils20from ci_cli import utils
2021
@@ -27,11 +28,11 @@
27 else:28 else:
28 url = utils.CI_URL + utils.TICKET_BASE29 url = utils.CI_URL + utils.TICKET_BASE
29 data = utils.get(url)30 data = utils.get(url)
30 except urllib2.HTTPError, exc:31 except exceptions.HTTPError, exc:
31 if exc.code == 404 and args.ticket:32 if exc.response.status_code == 404 and args.ticket:
32 sys.exit("Ticket number {} not found.".format(args.ticket))33 sys.exit("Ticket number {} not found.".format(args.ticket))
33 raise34 raise
34 except urllib2.URLError, exc:35 except exceptions.ConnectionError, exc:
35 raise36 raise
3637
37 if args.ticket:38 if args.ticket:
3839
=== modified file 'cli/ci_cli/tests/__init__.py'
--- cli/ci_cli/tests/__init__.py 2014-05-07 17:57:12 +0000
+++ cli/ci_cli/tests/__init__.py 2014-05-27 09:44:30 +0000
@@ -17,10 +17,13 @@
17import imp17import imp
18import os18import os
19import sys19import sys
20import json
2021
21from cStringIO import StringIO22from cStringIO import StringIO
22from contextlib import contextmanager23from contextlib import contextmanager
2324
25from requests import exceptions
26
24from ci_cli import utils27from ci_cli import utils
25from ci_utils.testing import TestCaseWithGnupg28from ci_utils.testing import TestCaseWithGnupg
2629
@@ -54,6 +57,46 @@
54 utils.CI_URL = utils.AUTH_CONFIG['ci_url']57 utils.CI_URL = utils.AUTH_CONFIG['ci_url']
5558
5659
60class FakeRequestsReturn:
61 """Object to mock the return of python-requests return."""
62
63 def __init__(self, code, content, reason=None):
64 self.status_code = code
65 self.content = content
66 self.reason = reason
67
68 def raise_for_status(self):
69 if 400 == self.status_code:
70 error = '%s Client Error: %s' % (self.status_code, self.reason)
71 e = exceptions.ConnectionError(error)
72 raise e
73 elif 400 < self.status_code < 500:
74 error = '%s Client Error: %s' % (self.status_code, self.reason)
75 e = exceptions.HTTPError(error, response=self)
76 raise e
77 elif 500 <= self.status_code < 600:
78 error = '%s Server Error: %s' % (self.status_code, self.reason)
79 e = exceptions.HTTPError(error, response=self)
80 raise e
81 else:
82 pass
83
84 def __repr__(self):
85 return self.content
86
87 def __iter__(self):
88 return (line for line in self.content.split("\n"))
89
90 def read(self):
91 return self.content
92
93 def json(self):
94 return json.loads(self.content)
95
96 def _status_code(self):
97 pass
98
99
57class MainScriptTestCase(TestCaseWithGnupg):100class MainScriptTestCase(TestCaseWithGnupg):
58 """Load the 'ubuntu-ci' script module for tests.101 """Load the 'ubuntu-ci' script module for tests.
59102
60103
=== modified file 'cli/ci_cli/tests/test_cli.py'
--- cli/ci_cli/tests/test_cli.py 2014-05-12 15:49:28 +0000
+++ cli/ci_cli/tests/test_cli.py 2014-05-27 09:44:30 +0000
@@ -21,7 +21,6 @@
21import mock21import mock
22import socket22import socket
23from testfixtures import LogCapture23from testfixtures import LogCapture
24import urllib2
2524
26from ci_cli import utils25from ci_cli import utils
27from ci_cli.tests import (26from ci_cli.tests import (
@@ -29,6 +28,7 @@
29 capture_stdout,28 capture_stdout,
30 mock_load_config,29 mock_load_config,
31 MainScriptTestCase,30 MainScriptTestCase,
31 FakeRequestsReturn,
32)32)
33from ci_cli.ticket import new_ticket33from ci_cli.ticket import new_ticket
34from ci_utils.testing import get_test_file_path34from ci_utils.testing import get_test_file_path
@@ -41,9 +41,10 @@
41class CLICommandsTestCase(MainScriptTestCase):41class CLICommandsTestCase(MainScriptTestCase):
42 """Tests cli basic commands."""42 """Tests cli basic commands."""
4343
44 @mock.patch('urllib2.urlopen')44 @mock.patch('requests.get')
45 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())45 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())
46 def test_ticket_status_one_ticket(self, mock_load_config, mock_urlopen):46 def test_ticket_status_one_ticket(self, mock_load_config,
47 mock_requests):
47 """Verify cli status command when providing ticket number."""48 """Verify cli status command when providing ticket number."""
48 data = {49 data = {
49 "current_workflow_step": str(TicketWorkflowStep.IMAGE_BUILDING),50 "current_workflow_step": str(TicketWorkflowStep.IMAGE_BUILDING),
@@ -58,9 +59,9 @@
58 "added_binaries": "mynewpackage",59 "added_binaries": "mynewpackage",
59 "removed_binaries": "myoldpackage",60 "removed_binaries": "myoldpackage",
60 }61 }
61 resp = mock.Mock()62 mock_requests.side_effect = [
62 resp.read.return_value = json.dumps(data)63 FakeRequestsReturn(200, json.dumps(data))
63 mock_urlopen.return_value = resp64 ]
64 args = ['status', '-t', '5']65 args = ['status', '-t', '5']
65 with capture_stdout(self.cli.main, args) as cm:66 with capture_stdout(self.cli.main, args) as cm:
66 self.assertEquals(67 self.assertEquals(
@@ -76,11 +77,11 @@
76 'Removed binaries: myoldpackage\n'.format(77 'Removed binaries: myoldpackage\n'.format(
77 str(TicketWorkflowStep.IMAGE_BUILDING),78 str(TicketWorkflowStep.IMAGE_BUILDING),
78 str(TicketWorkflowStepStatus.INPROGRESS)))79 str(TicketWorkflowStepStatus.INPROGRESS)))
79 mock_urlopen.assert_called_once()80 mock_requests.assert_called_once()
8081
81 @mock.patch('urllib2.urlopen')82 @mock.patch('requests.get')
82 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())83 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())
83 def test_ticket_status_all_tickets(self, mock_load_config, mock_urlopen):84 def test_ticket_status_all_tickets(self, mock_load_config, mock_requests):
84 """Verify cli status command for multiple tickets."""85 """Verify cli status command for multiple tickets."""
85 data = {86 data = {
86 "objects": [87 "objects": [
@@ -98,16 +99,16 @@
98 },99 },
99 ]100 ]
100 }101 }
101 resp = mock.Mock()102 mock_requests.side_effect = [
102 resp.read.return_value = json.dumps(data)103 FakeRequestsReturn(200, json.dumps(data))
103 mock_urlopen.return_value = resp104 ]
104 args = ['status']105 args = ['status']
105 with capture_stdout(self.cli.main, args) as cm:106 with capture_stdout(self.cli.main, args) as cm:
106 self.assertEquals(107 self.assertEquals(
107 cm,108 cm,
108 "Ticket #5, My cool feature is 100 110\n" +109 "Ticket #5, My cool feature is 100 110\n" +
109 "Ticket #6, Ubuntu bug fix is 100 110\n")110 "Ticket #6, Ubuntu bug fix is 100 110\n")
110 mock_urlopen.assert_called_once()111 mock_requests.assert_called_once()
111112
112 @mock.patch('ci_cli.ticket.SubTicket._process')113 @mock.patch('ci_cli.ticket.SubTicket._process')
113 @mock.patch('ci_cli.utils.post',114 @mock.patch('ci_cli.utils.post',
@@ -154,83 +155,94 @@
154 self.assertTrue("foobar" in new_ticket_.subtickets)155 self.assertTrue("foobar" in new_ticket_.subtickets)
155 self.assertTrue("barfoo" in new_ticket_.subtickets)156 self.assertTrue("barfoo" in new_ticket_.subtickets)
156157
157 @mock.patch('urllib2.urlopen')158 @mock.patch('requests.get')
158 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())159 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())
159 def test_ts_server_returns_urlerror(self, mock_load_config, mock_urlopen):160 def test_ts_server_returns_urlerror(self, mock_load_config, mock_requests):
160 """Test cli response to ts server refusing connection (111)."""161 """Test cli response to ts server refusing connection (111)."""
161 mock_urlopen.side_effect = urllib2.URLError(reason=socket.error(111,162 mock_requests.side_effect = [
162 "Connection refused"))163 FakeRequestsReturn(
164 400, '', socket.error(111, "Connection refused"))
165 ]
163 args = ['status']166 args = ['status']
164 with LogCapture() as lc:167 with LogCapture() as lc:
165 logger = logging.getLogger()168 logger = logging.getLogger()
166 self.cli.main(args, log=logger)169 self.cli.main(args, log=logger)
167 mock_urlopen.assert_called_once()170 mock_requests.assert_called_once()
168 self.assertTrue("Cannot reach the server at %s." % utils.CI_URL in171 self.assertTrue("Cannot reach the server at %s." % utils.CI_URL in
172 lc.records[0].msg, lc.records[0].msg)
173 self.assertTrue("Connection refused" in lc.records[0].msg,
169 lc.records[0].msg)174 lc.records[0].msg)
170 self.assertTrue("Connection refused" in lc.records[0].msg)
171175
172 @mock.patch('urllib2.urlopen')176 @mock.patch('requests.get')
173 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())177 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())
174 def test_ts_server_returns_internal_server_error(self, mock_load_config,178 def test_ts_server_returns_internal_server_error(self, mock_load_config,
175 mock_urlopen):179 mock_requests):
176 """Test cli response to ts server returning error 500."""180 """Test cli response to ts server returning error 500."""
177 mock_urlopen.side_effect = urllib2.HTTPError(None, 500,181 mock_requests.side_effect = [
178 "INTERNAL SERVER ERROR",182 FakeRequestsReturn(
179 None, None)183 500, "", "INTERNAL SERVER ERROR"
184 )
185 ]
180 args = ['status']186 args = ['status']
181 with LogCapture() as lc:187 with LogCapture() as lc:
182 logger = logging.getLogger()188 logger = logging.getLogger()
183 self.cli.main(args, log=logger)189 self.cli.main(args, log=logger)
184 mock_urlopen.assert_called_once()190 mock_requests.assert_called_once()
185 self.assertEquals("Server at {} reported internal error. Maybe a "191 self.assertEquals("Server at {} reported internal error. Maybe a "
186 "database hiccup?".format(utils.CI_URL),192 "database hiccup?".format(utils.CI_URL),
187 lc.records[0].msg)193 lc.records[0].msg)
188194
189 @mock.patch('urllib2.urlopen')195 @mock.patch('requests.get')
190 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())196 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())
191 def test_ts_server_returns_url_not_found(self, mock_load_config,197 def test_ts_server_returns_url_not_found(self, mock_load_config,
192 mock_urlopen):198 mock_requests):
193 """Test cli response to ts server returning 404 error."""199 """Test cli response to ts server returning 404 error."""
194 mock_urlopen.side_effect = urllib2.HTTPError(None, 404,200 mock_requests.side_effect = [
195 "Server Not Found",201 FakeRequestsReturn(404, '', 'Not Found')
196 None, None)202 ]
197 args = ['status']203 args = ['status']
198 with LogCapture() as lc:204 with LogCapture() as lc:
199 logger = logging.getLogger()205 logger = logging.getLogger()
200 self.cli.main(args, log=logger)206 self.cli.main(args, log=logger)
201 mock_urlopen.assert_called_once()207 mock_requests.assert_called_once()
202 self.assertEquals("Server at {} not found. Is 'ci_url' correctly "208 self.assertEquals("Server at {} not found. Is 'ci_url' correctly "
203 "set? (HTTP Error 404: Server Not Found)".format(209 "set? (404 Client Error: Not Found)".format(
204 utils.CI_URL), lc.records[0].msg)210 utils.CI_URL), lc.records[0].msg)
205211
206 @mock.patch('urllib2.urlopen')212 @mock.patch('requests.get')
207 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())213 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())
208 def test_ts_server_returns_bad_status_line(self, mock_load_config,214 def test_ts_server_returns_bad_status_line(self, mock_load_config,
209 mock_urlopen):215 mock_requests):
210 """Test cli response to ts server returning BadStatusLine."""216 """Test cli response to ts server returning BadStatusLine."""
211 args = ['status']217 args = ['status']
212 mock_urlopen.side_effect = httplib.BadStatusLine('')218 mock_requests.side_effect = httplib.BadStatusLine('')
213 with LogCapture() as lc:219 with LogCapture() as lc:
214 logger = logging.getLogger()220 logger = logging.getLogger()
215 self.cli.main(args, log=logger)221 self.cli.main(args, log=logger)
216 mock_urlopen.assert_called_once()222 mock_requests.assert_called_once()
217 self.assertEquals("Server at {} replied with an empty response. Is "223 self.assertEquals("Server at {} replied with an empty response. Is "
218 "'ci_url' pointing to the correct service?".format(224 "'ci_url' pointing to the correct service?".format(
219 utils.CI_URL), lc.records[0].msg)225 utils.CI_URL), lc.records[0].msg)
220226
221 @mock.patch('urllib2.urlopen')227 @mock.patch('requests.get')
222 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())228 @mock.patch('ci_cli.utils.load_config', side_effect=mock_load_config())
223 def test_ts_server_returns_other_httperror(self, mock_load_config,229 def test_ts_server_returns_other_httperror(self, mock_load_config,
224 mock_urlopen):230 mock_requests):
225 """Test cli response to ts server returning HTTPError."""231 """Test cli response to ts server returning HTTPError."""
226 mock_urlopen.side_effect = urllib2.HTTPError(None, 403, "Forbidden",232 mock_requests.side_effect = [
227 None, None)233 FakeRequestsReturn(403, '', 'Forbidden')
234 ]
228 args = ['status']235 args = ['status']
229 with LogCapture() as lc:236 with LogCapture() as lc:
230 logger = logging.getLogger()237 logger = logging.getLogger()
231 self.cli.main(args, log=logger)238 self.cli.main(args, log=logger)
232 mock_urlopen.assert_called_once()239 mock_requests.assert_called_once()
233 self.assertEquals("HTTP Error 403: Forbidden", lc.records[0].msg)240 self.assertEquals(
241 "Cannot reach the server at {}. Please, check your "
242 "configuration file ({}): is 'ci_url' correctly set? "
243 "Is the server up and reachable from this machine? "
244 "(403 Client Error: Forbidden).".format(
245 utils.CI_URL, utils.DEF_CFG), lc.records[0].msg)
234246
235247
236class CliArgumentsTestCase(MainScriptTestCase):248class CliArgumentsTestCase(MainScriptTestCase):
237249
=== modified file 'cli/ci_cli/tests/test_get_ticket_status.py'
--- cli/ci_cli/tests/test_get_ticket_status.py 2014-05-12 15:49:28 +0000
+++ cli/ci_cli/tests/test_get_ticket_status.py 2014-05-27 09:44:30 +0000
@@ -17,11 +17,11 @@
1717
18import mock18import mock
19import json19import json
20import urllib2
2120
22from ci_cli.tests import (21from ci_cli.tests import (
23 capture_stdout,22 capture_stdout,
24 MainScriptTestCase,23 MainScriptTestCase,
24 FakeRequestsReturn,
25)25)
26from ci_utils.ticket_states import (26from ci_utils.ticket_states import (
27 TicketWorkflowStep,27 TicketWorkflowStep,
@@ -31,8 +31,8 @@
3131
32class GetTicketStatus(MainScriptTestCase):32class GetTicketStatus(MainScriptTestCase):
3333
34 @mock.patch('urllib2.urlopen')34 @mock.patch('requests.get')
35 def test_get_single_ticket_status(self, mock_urlopen):35 def test_get_single_ticket_status(self, mock_requests):
36 data = {36 data = {
37 "current_workflow_step": str(TicketWorkflowStep.IMAGE_BUILDING),37 "current_workflow_step": str(TicketWorkflowStep.IMAGE_BUILDING),
38 "status": str(TicketWorkflowStepStatus.INPROGRESS),38 "status": str(TicketWorkflowStepStatus.INPROGRESS),
@@ -46,9 +46,9 @@
46 "added_binaries": "mynewpackage",46 "added_binaries": "mynewpackage",
47 "removed_binaries": "myoldpackage",47 "removed_binaries": "myoldpackage",
48 }48 }
49 resp = mock.Mock()49 mock_requests.side_effect = [
50 resp.read.return_value = json.dumps(data)50 FakeRequestsReturn(200, json.dumps(data))
51 mock_urlopen.return_value = resp51 ]
52 args = self.cli.parse_arguments(['status', '-t', '100'])52 args = self.cli.parse_arguments(['status', '-t', '100'])
53 with capture_stdout(args.func, args) as cm:53 with capture_stdout(args.func, args) as cm:
54 self.assertEqual(54 self.assertEqual(
@@ -64,10 +64,10 @@
64 str(TicketWorkflowStep.IMAGE_BUILDING),64 str(TicketWorkflowStep.IMAGE_BUILDING),
65 str(TicketWorkflowStepStatus.INPROGRESS)),65 str(TicketWorkflowStepStatus.INPROGRESS)),
66 cm)66 cm)
67 mock_urlopen.assert_called_once()67 mock_requests.assert_called_once()
6868
69 @mock.patch('urllib2.urlopen')69 @mock.patch('requests.get')
70 def test_get_ticket_status_unicode(self, mock_urlopen):70 def test_get_ticket_status_unicode(self, mock_requests):
71 data = {71 data = {
72 "current_workflow_step": str(TicketWorkflowStep.IMAGE_BUILDING),72 "current_workflow_step": str(TicketWorkflowStep.IMAGE_BUILDING),
73 "status": str(TicketWorkflowStepStatus.INPROGRESS),73 "status": str(TicketWorkflowStepStatus.INPROGRESS),
@@ -81,9 +81,9 @@
81 "added_binaries": "mynewpackage",81 "added_binaries": "mynewpackage",
82 "removed_binaries": "myoldpackage",82 "removed_binaries": "myoldpackage",
83 }83 }
84 resp = mock.Mock()84 mock_requests.side_effect = [
85 resp.read.return_value = json.dumps(data)85 FakeRequestsReturn(200, json.dumps(data))
86 mock_urlopen.return_value = resp86 ]
87 args = self.cli.parse_arguments(['status', '-t', '100'])87 args = self.cli.parse_arguments(['status', '-t', '100'])
88 with capture_stdout(args.func, args) as cm:88 with capture_stdout(args.func, args) as cm:
89 self.assertEqual(89 self.assertEqual(
@@ -99,10 +99,10 @@
99 str(TicketWorkflowStep.IMAGE_BUILDING),99 str(TicketWorkflowStep.IMAGE_BUILDING),
100 str(TicketWorkflowStepStatus.INPROGRESS)),100 str(TicketWorkflowStepStatus.INPROGRESS)),
101 cm)101 cm)
102 mock_urlopen.assert_called_once()102 mock_requests.assert_called_once()
103103
104 @mock.patch('urllib2.urlopen')104 @mock.patch('requests.get')
105 def test_get_single_failed_ticket_status(self, mock_urlopen):105 def test_get_single_failed_ticket_status(self, mock_requests):
106 data = {106 data = {
107 "current_workflow_step": str(TicketWorkflowStep.FAILED),107 "current_workflow_step": str(TicketWorkflowStep.FAILED),
108 "status": str(TicketWorkflowStepStatus.FAILED),108 "status": str(TicketWorkflowStepStatus.FAILED),
@@ -116,9 +116,9 @@
116 "added_binaries": "mynewpackage",116 "added_binaries": "mynewpackage",
117 "removed_binaries": "myoldpackage",117 "removed_binaries": "myoldpackage",
118 }118 }
119 resp = mock.Mock()119 mock_requests.side_effect = [
120 resp.read.return_value = json.dumps(data)120 FakeRequestsReturn(200, json.dumps(data))
121 mock_urlopen.return_value = resp121 ]
122 args = self.cli.parse_arguments(['status', '-t', '100'])122 args = self.cli.parse_arguments(['status', '-t', '100'])
123 with capture_stdout(args.func, args) as cm:123 with capture_stdout(args.func, args) as cm:
124 self.assertEqual(124 self.assertEqual(
@@ -133,10 +133,10 @@
133 'Removed binaries: myoldpackage\n'.format(133 'Removed binaries: myoldpackage\n'.format(
134 str(TicketWorkflowStepStatus.FAILED)),134 str(TicketWorkflowStepStatus.FAILED)),
135 cm)135 cm)
136 mock_urlopen.assert_called_once()136 mock_requests.assert_called_once()
137137
138 @mock.patch('urllib2.urlopen')138 @mock.patch('requests.get')
139 def test_get_all_ticket_status(self, mock_urlopen):139 def test_get_all_ticket_status(self, mock_requests):
140 data = {140 data = {
141 "objects": [141 "objects": [
142 {142 {
@@ -165,9 +165,9 @@
165 },165 },
166 ]166 ]
167 }167 }
168 resp = mock.Mock()168 mock_requests.side_effect = [
169 resp.read.return_value = json.dumps(data)169 FakeRequestsReturn(200, json.dumps(data))
170 mock_urlopen.return_value = resp170 ]
171 args = self.cli.parse_arguments(['status'])171 args = self.cli.parse_arguments(['status'])
172 with capture_stdout(args.func, args) as cm:172 with capture_stdout(args.func, args) as cm:
173 self.assertEqual(173 self.assertEqual(
@@ -176,15 +176,15 @@
176 "Ticket #7, Upstream bug fix is 100 110\n" +176 "Ticket #7, Upstream bug fix is 100 110\n" +
177 "Ticket #9, Other new feature is 100 110\n",177 "Ticket #9, Other new feature is 100 110\n",
178 cm)178 cm)
179 mock_urlopen.assert_called_once()179 mock_requests.assert_called_once()
180180
181 @mock.patch('urllib2.urlopen')181 @mock.patch('requests.get')
182 def test_get_status_404_response(self, mock_urlopen):182 def test_get_status_404_response(self, mock_requests):
183 mock_urlopen.side_effect = urllib2.HTTPError("http://example.com",183 mock_requests.side_effect = [
184 404, "Not Found", "",184 FakeRequestsReturn(404, '', 'Not Found')
185 None)185 ]
186 args = self.cli.parse_arguments(['status', '-t', '99'])186 args = self.cli.parse_arguments(['status', '-t', '99'])
187 with self.assertRaises(SystemExit) as cm:187 with self.assertRaises(SystemExit) as cm:
188 args.func(args)188 args.func(args)
189 mock_urlopen.assert_called_once()189 mock_requests.assert_called_once()
190 self.assertEqual("Ticket number 99 not found.", cm.exception.message)190 self.assertEqual("Ticket number 99 not found.", cm.exception.message)
191191
=== modified file 'cli/ci_cli/tests/test_image.py'
--- cli/ci_cli/tests/test_image.py 2014-05-07 14:56:11 +0000
+++ cli/ci_cli/tests/test_image.py 2014-05-27 09:44:30 +0000
@@ -26,26 +26,10 @@
26from ci_cli.tests import (26from ci_cli.tests import (
27 capture_stdout,27 capture_stdout,
28 MainScriptTestCase,28 MainScriptTestCase,
29 FakeRequestsReturn,
29)30)
3031
3132
32class FakeUrlOpenReturn:
33 """Object to mock the return of urllib2.urlopen."""
34
35 def __init__(self, code, content):
36 self.code = code
37 self.content = content
38
39 def __repr__(self):
40 return self.content
41
42 def __iter__(self):
43 return (line for line in self.content.split("\n"))
44
45 def read(self):
46 return self.content
47
48
49artifact_data = {33artifact_data = {
50 "objects": [34 "objects": [
51 {35 {
@@ -88,11 +72,11 @@
88 if os.path.exists(self.image_path):72 if os.path.exists(self.image_path):
89 os.remove(self.image_path)73 os.remove(self.image_path)
9074
91 @mock.patch('urllib2.urlopen')75 @mock.patch('requests.get')
92 @mock.patch('ci_utils.data_store.create_for_ticket')76 @mock.patch('ci_utils.data_store.create_for_ticket')
93 def test_get_ticket_image(self, mock_create_datastore, mock_urlopen):77 def test_get_ticket_image(self, mock_create_datastore, mock_requests):
94 mock_urlopen.side_effect = [78 mock_requests.side_effect = [
95 FakeUrlOpenReturn(200, json.dumps(artifact_data))]79 FakeRequestsReturn(200, json.dumps(artifact_data))]
96 mock_datastore = mock.Mock()80 mock_datastore = mock.Mock()
97 mock_datastore.get_file.return_value = buffer(" ")81 mock_datastore.get_file.return_value = buffer(" ")
98 mock_create_datastore.return_value = mock_datastore82 mock_create_datastore.return_value = mock_datastore
@@ -106,12 +90,12 @@
106 "Image file can be found at: {}\n".format(self.image_path))90 "Image file can be found at: {}\n".format(self.image_path))
107 mock_datastore.assert_called_once()91 mock_datastore.assert_called_once()
10892
109 @mock.patch('urllib2.urlopen')93 @mock.patch('requests.get')
110 @mock.patch('ci_utils.data_store.create_for_ticket')94 @mock.patch('ci_utils.data_store.create_for_ticket')
111 def test_get_ticket_image_not_found(self, mock_create_datastore,95 def test_get_ticket_image_not_found(self, mock_create_datastore,
112 mock_urlopen):96 mock_requests):
113 mock_urlopen.side_effect = [97 mock_requests.side_effect = [
114 FakeUrlOpenReturn(200, json.dumps(artifact_data))]98 FakeRequestsReturn(200, json.dumps(artifact_data))]
115 mock_datastore = mock.Mock()99 mock_datastore = mock.Mock()
116 mock_datastore.get_file.side_effect = data_store.DataStoreException(100 mock_datastore.get_file.side_effect = data_store.DataStoreException(
117 "Failed to get file: d62d3d9a-ac3d-11e3-847d-fa163eaf5928.img, "101 "Failed to get file: d62d3d9a-ac3d-11e3-847d-fa163eaf5928.img, "
@@ -125,12 +109,12 @@
125 with self.assertRaises(ImageObjectNotFound):109 with self.assertRaises(ImageObjectNotFound):
126 args.func(args)110 args.func(args)
127111
128 @mock.patch('urllib2.urlopen')112 @mock.patch('requests.get')
129 @mock.patch('ci_utils.data_store.DataStore')113 @mock.patch('ci_utils.data_store.DataStore')
130 def test_get_ticket_image_already_exists(self, mock_data_store,114 def test_get_ticket_image_already_exists(self, mock_data_store,
131 mock_urlopen):115 mock_requests):
132 mock_urlopen.side_effect = [116 mock_requests.side_effect = [
133 FakeUrlOpenReturn(200, json.dumps(artifact_data))]117 FakeRequestsReturn(200, json.dumps(artifact_data))]
134 open(self.image_path, 'a').close()118 open(self.image_path, 'a').close()
135 args = self.cli.parse_arguments(['get_image', '-t', '4', '-n',119 args = self.cli.parse_arguments(['get_image', '-t', '4', '-n',
136 self.image_path])120 self.image_path])
@@ -139,13 +123,13 @@
139 "{} already exists.\n".format(self.image_path),123 "{} already exists.\n".format(self.image_path),
140 cm)124 cm)
141125
142 @mock.patch('urllib2.urlopen')126 @mock.patch('requests.get')
143 @mock.patch('ci_utils.data_store.create_for_ticket')127 @mock.patch('ci_utils.data_store.create_for_ticket')
144 def test_get_last_completed_ticket_image(self, mock_create_datastore,128 def test_get_last_completed_ticket_image(self, mock_create_datastore,
145 mock_urlopen):129 mock_requests):
146 mock_urlopen.side_effect = [130 mock_requests.side_effect = [
147 FakeUrlOpenReturn(200, json.dumps(ticket_data)),131 FakeRequestsReturn(200, json.dumps(ticket_data)),
148 FakeUrlOpenReturn(200, json.dumps(artifact_data))132 FakeRequestsReturn(200, json.dumps(artifact_data))
149 ]133 ]
150 mock_datastore = mock.Mock()134 mock_datastore = mock.Mock()
151 mock_datastore.get_file.return_value = buffer(" ")135 mock_datastore.get_file.return_value = buffer(" ")
@@ -159,11 +143,11 @@
159 "Image file can be found at: {}\n".format(self.image_path))143 "Image file can be found at: {}\n".format(self.image_path))
160 mock_datastore.assert_called_once()144 mock_datastore.assert_called_once()
161145
162 @mock.patch('urllib2.urlopen')146 @mock.patch('requests.get')
163 def test_get_last_completed_ticket_none_complete(self, mock_urlopen):147 def test_get_last_completed_ticket_none_complete(self, mock_requests):
164 data = {'objects': []}148 data = {'objects': []}
165 mock_urlopen.side_effect = [149 mock_requests.side_effect = [
166 FakeUrlOpenReturn(200, json.dumps(data))]150 FakeRequestsReturn(200, json.dumps(data))]
167 args = self.cli.parse_arguments(['get_image', '-n', self.image_path])151 args = self.cli.parse_arguments(['get_image', '-n', self.image_path])
168 with self.assertRaises(SystemExit) as cm:152 with self.assertRaises(SystemExit) as cm:
169 args.func(args)153 args.func(args)
170154
=== modified file 'cli/ci_cli/tests/test_utils.py'
--- cli/ci_cli/tests/test_utils.py 2014-05-07 17:57:12 +0000
+++ cli/ci_cli/tests/test_utils.py 2014-05-27 09:44:30 +0000
@@ -21,6 +21,7 @@
21import tempfile21import tempfile
2222
23from ci_cli import utils23from ci_cli import utils
24from ci_cli.tests import FakeRequestsReturn
24from ci_utils.testing import TestCaseWithGnupg25from ci_utils.testing import TestCaseWithGnupg
2526
2627
@@ -47,24 +48,24 @@
47 location = 'http://www.example.com/api/v1/ticket/abc/123/'48 location = 'http://www.example.com/api/v1/ticket/abc/123/'
48 self.assertRaises(ValueError, utils.parse_id, location)49 self.assertRaises(ValueError, utils.parse_id, location)
4950
50 @mock.patch('urllib2.urlopen')51 @mock.patch('requests.get')
51 def test_get_sourcepackage_uri(self, mock_urlopen):52 def test_get_sourcepackage_uri(self, mock_requests):
52 data = {"objects": [{"resource_uri": "/api/v1/sourcepackage/4/"}]}53 data = {"objects": [{"resource_uri": "/api/v1/sourcepackage/4/"}]}
53 resp = mock.Mock()54 mock_requests.side_effect = [
54 resp.read.return_value = json.dumps(data)55 FakeRequestsReturn(200, json.dumps(data))
55 mock_urlopen.return_value = resp56 ]
56 uri = utils.get_sourcepackage_uri('foobar')57 uri = utils.get_sourcepackage_uri('foobar')
57 mock_urlopen.assert_called_once()58 mock_requests.assert_called_once()
58 self.assertEquals(uri, '/api/v1/sourcepackage/4/')59 self.assertEquals(uri, '/api/v1/sourcepackage/4/')
5960
60 @mock.patch('urllib2.urlopen')61 @mock.patch('requests.get')
61 def test_get_sourcepackage_uri_not_found(self, mock_urlopen):62 def test_get_sourcepackage_uri_not_found(self, mock_requests):
62 data = {"objects": []}63 data = {"objects": []}
63 resp = mock.Mock()64 mock_requests.side_effect = [
64 resp.read.return_value = json.dumps(data)65 FakeRequestsReturn(200, json.dumps(data))
65 mock_urlopen.return_value = resp66 ]
66 uri = utils.get_sourcepackage_uri('foobar')67 uri = utils.get_sourcepackage_uri('foobar')
67 mock_urlopen.assert_called_once()68 mock_requests.assert_called_once()
68 self.assertEquals(uri, '')69 self.assertEquals(uri, '')
6970
70 def test_load_config(self):71 def test_load_config(self):
7172
=== modified file 'cli/ci_cli/utils.py'
--- cli/ci_cli/utils.py 2014-04-08 13:27:01 +0000
+++ cli/ci_cli/utils.py 2014-05-27 09:44:30 +0000
@@ -17,8 +17,8 @@
17import json17import json
18import logging18import logging
19import sys19import sys
20import urllib2
21import yaml20import yaml
21import requests
2222
23from ci_utils import data_store23from ci_utils import data_store
2424
@@ -72,22 +72,19 @@
7272
7373
74def post(url, data, headers=HEADERS, patch=False):74def post(url, data, headers=HEADERS, patch=False):
75 req = urllib2.Request(url=url, data=json.dumps(data), headers=HEADERS)75 req = requests.post(url=url, data=json.dumps(data), headers=HEADERS)
76 f = urllib2.urlopen(req)76 resp = req.headers
77 return f.info().dict['location']77 return resp['location']
7878
7979
80def patch(url, data, headers=HEADERS):80def patch(url, data, headers=HEADERS):
81 req = urllib2.Request(url=url, data=json.dumps(data), headers=HEADERS)81 requests.patch(url=url, data=json.dumps(data), headers=HEADERS)
82 req.get_method = lambda: 'PATCH'
83 urllib2.urlopen(req)
8482
8583
86def get(url):84def get(url):
87 f = urllib2.urlopen(url)85 r = requests.get(url)
8886 r.raise_for_status()
89 json_data = f.read()87 return r.json()
90 return json.loads(json_data)
9188
9289
93def parse_id(location):90def parse_id(location):
@@ -101,9 +98,7 @@
10198
102def get_sourcepackage_uri(sourcepackage):99def get_sourcepackage_uri(sourcepackage):
103 url = CI_URL + SOURCEPACKAGE_BASE + '?name__iexact=' + sourcepackage100 url = CI_URL + SOURCEPACKAGE_BASE + '?name__iexact=' + sourcepackage
104 f = urllib2.urlopen(url)101 data = get(url)
105 json_data = f.read()
106 data = json.loads(json_data)
107 try:102 try:
108 sourcepackage_uri = data['objects'][0]['resource_uri']103 sourcepackage_uri = data['objects'][0]['resource_uri']
109 return sourcepackage_uri104 return sourcepackage_uri
110105
=== modified file 'cli/setup.py'
--- cli/setup.py 2014-05-07 17:33:32 +0000
+++ cli/setup.py 2014-05-27 09:44:30 +0000
@@ -27,6 +27,7 @@
27 'dput>=1.6',27 'dput>=1.6',
28 'lazr.enum>=1.1.2',28 'lazr.enum>=1.1.2',
29 'PyYAML==3.10',29 'PyYAML==3.10',
30 'requests==2.2.1',
30 'mock==1.0.1',31 'mock==1.0.1',
31 'testfixtures>=3.0.1',32 'testfixtures>=3.0.1',
32 'python-gnupg>=0.3.6',33 'python-gnupg>=0.3.6',
3334
=== modified file 'cli/ubuntu-ci'
--- cli/ubuntu-ci 2014-05-07 14:56:11 +0000
+++ cli/ubuntu-ci 2014-05-27 09:44:30 +0000
@@ -19,7 +19,8 @@
19import logging19import logging
20import os20import os
21import sys21import sys
22import urllib222
23from requests import exceptions
2324
24from ci_cli import (25from ci_cli import (
25 ticket,26 ticket,
@@ -78,8 +79,8 @@
78 help='Ticket to display status of. Leave off '79 help='Ticket to display status of. Leave off '
79 'for last successful ticket')80 'for last successful ticket')
80 image_parser.add_argument('-n', '--name',81 image_parser.add_argument('-n', '--name',
81 help='Desired file name (and path) for the '82 help='Desired file name (and path) for the '
82 'downloaded image', required=True)83 'downloaded image', required=True)
83 image_parser.set_defaults(func=image.get_image)84 image_parser.set_defaults(func=image.get_image)
84 return parser.parse_args(args)85 return parser.parse_args(args)
8586
@@ -153,10 +154,16 @@
153 except image.ImageObjectNotFound as exc:154 except image.ImageObjectNotFound as exc:
154 log.error("Image cannot be downloaded: {} ({})".format(exc.filename,155 log.error("Image cannot be downloaded: {} ({})".format(exc.filename,
155 str(exc)))156 str(exc)))
156 except urllib2.URLError as exc:157 except exceptions.RequestException as exc:
157 if isinstance(exc, urllib2.HTTPError):158 error = ("Cannot reach the server at {}. Please, check your "
158 reason = exc.reason159 "configuration file ({}): is 'ci_url' correctly set? "
159 code = exc.code160 "Is the server up and reachable from this machine? "
161 "({}).".format(utils.CI_URL, utils.DEF_CFG, str(exc)))
162 if isinstance(exc, exceptions.HTTPError):
163 code = None
164 if exc.response:
165 code = exc.response.status_code
166
160 if code == 500:167 if code == 500:
161 log.error("Server at {} reported internal error. Maybe a "168 log.error("Server at {} reported internal error. Maybe a "
162 "database hiccup?".format(utils.CI_URL))169 "database hiccup?".format(utils.CI_URL))
@@ -164,13 +171,9 @@
164 log.error("Server at {} not found. Is 'ci_url' correctly "171 log.error("Server at {} not found. Is 'ci_url' correctly "
165 "set? ({})".format(utils.CI_URL, str(exc)))172 "set? ({})".format(utils.CI_URL, str(exc)))
166 else:173 else:
167 log.error(str(exc))174 log.error(error)
168 else:175 else:
169 reason = exc.reason176 log.error(error)
170 log.error("Cannot reach the server at {}. Please, check your "
171 "configuration file ({}): is 'ci_url' correctly set? "
172 "Is the server up and reachable from this machine? "
173 "({}).".format(utils.CI_URL, utils.DEF_CFG, reason))
174 except data_store.DataStoreException as exc:177 except data_store.DataStoreException as exc:
175 log.error("Data Store Error: {}".format(exc))178 log.error("Data Store Error: {}".format(exc))
176 except Exception:179 except Exception:
177180
=== modified file 'debian/control'
--- debian/control 2014-05-15 16:12:18 +0000
+++ debian/control 2014-05-27 09:44:30 +0000
@@ -32,6 +32,7 @@
32 python-lazr.enum (>= 1.1.2-0~),32 python-lazr.enum (>= 1.1.2-0~),
33 python-yaml (>= 3.10-2),33 python-yaml (>= 3.10-2),
34 python-swiftclient,34 python-swiftclient,
35 python-requests (>=2.2.1),
35 uci-utils (= ${binary:Version}),36 uci-utils (= ${binary:Version}),
36 ${misc:Depends},37 ${misc:Depends},
37 ${python:Depends}38 ${python:Depends}

Subscribers

People subscribed via source and target branches