Merge lp:~nataliabidart/ubuntu-sso-client/stable-3-0-update-2.99.92 into lp:ubuntu-sso-client/stable-3-0

Proposed by Natalia Bidart on 2012-04-03
Status: Merged
Approved by: Natalia Bidart on 2012-04-03
Approved revision: 834
Merged at revision: 833
Proposed branch: lp:~nataliabidart/ubuntu-sso-client/stable-3-0-update-2.99.92
Merge into: lp:ubuntu-sso-client/stable-3-0
Diff against target: 548 lines (+341/-13)
12 files modified
data/qt/stylesheet.qss (+4/-1)
ubuntu_sso/keyring/windows.py (+1/-1)
ubuntu_sso/networkstate/tests/test_windows.py (+4/-7)
ubuntu_sso/networkstate/windows.py (+2/-2)
ubuntu_sso/utils/runner/qt.py (+7/-0)
ubuntu_sso/utils/runner/tests/test_qt.py (+19/-0)
ubuntu_sso/utils/tests/test_windows.py (+65/-0)
ubuntu_sso/utils/webclient/gsettings.py (+8/-1)
ubuntu_sso/utils/webclient/qtnetwork.py (+8/-1)
ubuntu_sso/utils/webclient/tests/test_gsettings.py (+23/-0)
ubuntu_sso/utils/webclient/tests/test_qtnetwork.py (+157/-0)
ubuntu_sso/utils/windows.py (+43/-0)
To merge this branch: bzr merge lp:~nataliabidart/ubuntu-sso-client/stable-3-0-update-2.99.92
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) 2012-04-03 Approve on 2012-04-03
Review via email: mp+100588@code.launchpad.net

Commit Message

- Updating from trunk up to revno 940:

[ Alejandro J. Cura <email address hidden> ]
  - Make windows Keyring no longer depend on twisted (LP: #969159).
  - Daemonize the network state thread under windows (LP: #963404).

[ Diego Sarmentero <email address hidden> ]
  - Setting the style directly to the widget to remove the one
    from the application (LP: #969455).

[ Manuel de la Pena <email address hidden> ]
  - Fixed the issue where we use an empty proxy url when the proxy
    was not set in gsettings (LP: #969280).
  - Changed the way in which the proxy settings are retrieved on
    windows to ensure that proxy() returns the correct one and not a
    null initialized one. This fixes the creds retrieval issue
    because the hostName is not longer '' (LP: #958938).

To post a comment you must log in.
Alejandro J. Cura (alecu) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/qt/stylesheet.qss'
2--- data/qt/stylesheet.qss 2012-03-21 17:57:49 +0000
3+++ data/qt/stylesheet.qss 2012-04-03 12:14:21 +0000
4@@ -81,7 +81,6 @@
5 }
6
7 QFrame#frm_box {
8- background: #ffffff;
9 border-radius: 5px;
10 border-style: solid;
11 border-color: #939389;
12@@ -90,6 +89,10 @@
13 min-height: 100px;
14 }
15
16+LoadingOverlay {
17+ background: transparent;
18+}
19+
20 WizardHeader {
21 padding-top: 1px;
22 padding-bottom: 1px;
23
24=== modified file 'ubuntu_sso/keyring/windows.py'
25--- ubuntu_sso/keyring/windows.py 2011-03-30 22:57:37 +0000
26+++ ubuntu_sso/keyring/windows.py 2012-04-03 12:14:21 +0000
27@@ -18,7 +18,7 @@
28
29 from json import loads, dumps
30
31-from twisted.internet.threads import deferToThread
32+from ubuntu_sso.utils.windows import qtDeferToThread as deferToThread
33
34 USERNAME = 'ubuntu_sso'
35
36
37=== modified file 'ubuntu_sso/networkstate/tests/test_windows.py'
38--- ubuntu_sso/networkstate/tests/test_windows.py 2011-11-11 19:20:59 +0000
39+++ ubuntu_sso/networkstate/tests/test_windows.py 2012-04-03 12:14:21 +0000
40@@ -1,8 +1,6 @@
41 # -*- coding: utf-8 -*-
42 #
43-# Author: Manuel de la Pena<manuel@canonical.com>
44-#
45-# Copyright 2011 Canonical Ltd.
46+# Copyright 2011-2012 Canonical Ltd.
47 #
48 # This program is free software: you can redistribute it and/or modify it
49 # under the terms of the GNU General Public License version 3, as published
50@@ -80,7 +78,7 @@
51
52
53 class TestNetworkManagerState(MockerTestCase):
54- """Test he Network Manager State."""
55+ """Test the Network Manager State."""
56
57 def setUp(self):
58 super(TestNetworkManagerState, self).setUp()
59@@ -109,6 +107,7 @@
60 self.mocker.result(False)
61 self.cb(OFFLINE)
62 self.mocker.result(self.thread)
63+ self.thread.daemon = True
64 self.thread.start()
65 self.mocker.replay()
66 self.state.find_online_state(listener=self.network_manager,
67@@ -120,6 +119,7 @@
68 self.mocker.result(ONLINE)
69 self.cb(ONLINE)
70 self.mocker.result(self.thread)
71+ self.thread.daemon = True
72 self.thread.start()
73 self.mocker.replay()
74 self.state.find_online_state(listener=self.network_manager,
75@@ -127,7 +127,6 @@
76
77
78 class FakeWininet(object):
79-
80 """Fake wininet for windll."""
81
82 connection_state = -1
83@@ -140,7 +139,6 @@
84
85
86 class FakeWininetException(object):
87-
88 """Fake wininet for windll."""
89
90 connection_state = -1
91@@ -153,7 +151,6 @@
92
93
94 class TestConnection(TestCase):
95-
96 """Test the state of the connection."""
97
98 @inlineCallbacks
99
100=== modified file 'ubuntu_sso/networkstate/windows.py'
101--- ubuntu_sso/networkstate/windows.py 2012-01-04 16:49:43 +0000
102+++ ubuntu_sso/networkstate/windows.py 2012-04-03 12:14:21 +0000
103@@ -1,7 +1,6 @@
104 # -*- coding: utf-8 -*-
105-# Author: Manuel de la Pena <manuel@canonical.com>
106 #
107-# Copyright 2011 Canonical Ltd.
108+# Copyright 2011-2012 Canonical Ltd.
109 #
110 # This program is free software: you can redistribute it and/or modify it
111 # under the terms of the GNU General Public License version 3, as published
112@@ -207,4 +206,5 @@
113 if listener_thread is None:
114 listener_thread = Thread(target=listener.register,
115 name='Ubuntu SSO NetworkManager')
116+ listener_thread.daemon = True
117 listener_thread.start()
118
119=== modified file 'ubuntu_sso/utils/runner/qt.py'
120--- ubuntu_sso/utils/runner/qt.py 2012-02-10 15:44:28 +0000
121+++ ubuntu_sso/utils/runner/qt.py 2012-04-03 12:14:21 +0000
122@@ -16,7 +16,10 @@
123
124 """Utility to spawn another program from a plain Qt mainloop."""
125
126+import sys
127+
128 from PyQt4 import QtCore
129+from twisted.python import procutils
130
131 from ubuntu_sso.logger import setup_logging
132
133@@ -66,6 +69,10 @@
134 process.error.connect(handle_error)
135
136 args = list(args)
137+ if sys.platform.startswith("win") and not args[0].endswith("exe"):
138+ python_exe = procutils.which("python.exe")
139+ if python_exe:
140+ args.insert(0, python_exe[0])
141 program = args[0]
142 argv = args[1:]
143 process.start(program, argv)
144
145=== modified file 'ubuntu_sso/utils/runner/tests/test_qt.py'
146--- ubuntu_sso/utils/runner/tests/test_qt.py 2012-02-23 13:17:46 +0000
147+++ ubuntu_sso/utils/runner/tests/test_qt.py 2012-04-03 12:14:21 +0000
148@@ -141,3 +141,22 @@
149 yield d
150
151 self.assertNotIn(self.process, qt._processes)
152+
153+ @defer.inlineCallbacks
154+ def test_start_process_win_devel(self):
155+ """Test the windows devel case."""
156+ calls = []
157+ fake_python = r"c:\python99\python.exe"
158+ self.patch(runner.qt.sys, "platform", "win98")
159+ self.patch(runner.qt.procutils, "which", lambda _: [fake_python])
160+ self.patch(subprocess, "call", calls.append)
161+ self.patch(self, "args", ["bin/program", "arg1", "arg2"])
162+
163+ d = defer.Deferred()
164+ runner.qt.spawn_program(self.args,
165+ reply_handler=d.callback, error_handler=lambda **kw: d.errback(kw))
166+ yield d
167+
168+ cmdline = calls[0]
169+ self.assertEqual(cmdline[0], fake_python,
170+ "python.exe is added to the command line.")
171
172=== added file 'ubuntu_sso/utils/tests/test_windows.py'
173--- ubuntu_sso/utils/tests/test_windows.py 1970-01-01 00:00:00 +0000
174+++ ubuntu_sso/utils/tests/test_windows.py 2012-04-03 12:14:21 +0000
175@@ -0,0 +1,65 @@
176+# -*- coding: utf-8 -*-
177+#
178+# Copyright 2012 Canonical Ltd.
179+#
180+# This program is free software: you can redistribute it and/or modify it
181+# under the terms of the GNU General Public License version 3, as published
182+# by the Free Software Foundation.
183+#
184+# This program is distributed in the hope that it will be useful, but
185+# WITHOUT ANY WARRANTY; without even the implied warranties of
186+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
187+# PURPOSE. See the GNU General Public License for more details.
188+#
189+# You should have received a copy of the GNU General Public License along
190+# with this program. If not, see <http://www.gnu.org/licenses/>.
191+
192+"""Tests for the platform specific functions (for Windows)."""
193+
194+import thread
195+
196+from twisted.internet import defer
197+from twisted.trial.unittest import TestCase
198+
199+from ubuntu_sso.utils.windows import qtDeferToThread
200+
201+
202+class FakeException(Exception):
203+ """A Fake exception."""
204+
205+
206+class QtDeferToThreadTestCase(TestCase):
207+ """A Qt-based implementation of deferToThread."""
208+
209+ @defer.inlineCallbacks
210+ def test_executes_function_returns_result(self):
211+ """The passed function is executed and returns the result."""
212+
213+ def fake_operation(first, second="world!"):
214+ """Testing positional and keyword arguments."""
215+ return first + " " + second
216+
217+ result = yield qtDeferToThread(fake_operation, "hola", second="mundo!")
218+ self.assertEqual(result, "hola mundo!")
219+
220+ @defer.inlineCallbacks
221+ def test_exceptions_become_failures(self):
222+ """Any exception while running the function becomes a failure."""
223+
224+ def fake_raise():
225+ """Throw the fake exception."""
226+ raise FakeException
227+
228+ yield self.assertFailure(qtDeferToThread(fake_raise), FakeException)
229+
230+ @defer.inlineCallbacks
231+ def test_function_runs_in_new_thread(self):
232+ """The concerned function is run in a different thread."""
233+
234+ def inner_function():
235+ """This should be run in a different thread."""
236+ return thread.get_ident()
237+
238+ other_thread_id = yield qtDeferToThread(inner_function)
239+ this_thread_id = thread.get_ident()
240+ self.assertNotEqual(this_thread_id, other_thread_id)
241
242=== modified file 'ubuntu_sso/utils/webclient/gsettings.py'
243--- ubuntu_sso/utils/webclient/gsettings.py 2012-03-07 15:12:39 +0000
244+++ ubuntu_sso/utils/webclient/gsettings.py 2012-04-03 12:14:21 +0000
245@@ -34,6 +34,11 @@
246 def parse_manual_proxy_settings(scheme, gsettings):
247 """Parse the settings for a given scheme."""
248 host, username, pwd = parse_proxy_host(gsettings[scheme + ".host"])
249+ # if the user did not set a proxy for a type (http/https/ftp) we should
250+ # return None to ensure that it is not used
251+ if host == '':
252+ return None
253+
254 settings = {
255 "host": host,
256 "port": gsettings[scheme + ".port"],
257@@ -76,7 +81,9 @@
258 elif mode == "manual":
259 settings = {}
260 for scheme in ["http", "https"]:
261- settings[scheme] = parse_manual_proxy_settings(scheme, gsettings)
262+ scheme_settings = parse_manual_proxy_settings(scheme, gsettings)
263+ if scheme_settings is not None:
264+ settings[scheme] = scheme_settings
265 else:
266 # If mode is automatic the PAC javascript should be interpreted
267 # on each request. That is out of scope so it's ignored for now
268
269=== modified file 'ubuntu_sso/utils/webclient/qtnetwork.py'
270--- ubuntu_sso/utils/webclient/qtnetwork.py 2012-03-23 20:15:44 +0000
271+++ ubuntu_sso/utils/webclient/qtnetwork.py 2012-04-03 12:14:21 +0000
272@@ -28,6 +28,7 @@
273 QNetworkAccessManager,
274 QNetworkProxy,
275 QNetworkProxyFactory,
276+ QNetworkProxyQuery,
277 QNetworkReply,
278 QNetworkRequest,
279 QSslCertificate,
280@@ -46,6 +47,7 @@
281 from ubuntu_sso.utils.webclient import gsettings
282
283 logger = setup_logging("ubuntu_sso.utils.webclient.qtnetwork")
284+PROXY_REQUEST = 'https://one.ubuntu.com'
285
286
287 def build_proxy(settings_groups):
288@@ -102,7 +104,12 @@
289 else:
290 logger.info("Proxy is disabled.")
291 else:
292- QNetworkProxyFactory.setUseSystemConfiguration(True)
293+ if WebClient.proxy_instance is None:
294+ logger.info("Querying OS for proxy.")
295+ query = QNetworkProxyQuery(QUrl(PROXY_REQUEST))
296+ proxies = QNetworkProxyFactory.systemProxyForQuery(query)
297+ QNetworkProxy.setApplicationProxy(proxies[0])
298+ WebClient.proxy_instance = proxies[0]
299
300 def handle_proxy_auth(self, proxy, authenticator):
301 """Proxy authentication is required."""
302
303=== modified file 'ubuntu_sso/utils/webclient/tests/test_gsettings.py'
304--- ubuntu_sso/utils/webclient/tests/test_gsettings.py 2012-03-09 12:04:31 +0000
305+++ ubuntu_sso/utils/webclient/tests/test_gsettings.py 2012-04-03 12:14:21 +0000
306@@ -169,6 +169,29 @@
307 ps = gsettings.get_proxy_settings()
308 self.assertEqual(ps["http"], http_expected)
309
310+ def _assert_parser_empty_url(self, scheme):
311+ """Assert the parsing of an empty url."""
312+ template_values = dict(BASE_GSETTINGS_VALUES)
313+ template_values.update({
314+ "mode": "manual",
315+ scheme + "_host": '',
316+ scheme + "_port": 0,
317+ "http_use_auth": "false",
318+ })
319+ fake_output = TEMPLATE_GSETTINGS_OUTPUT.format(**template_values)
320+ self.patch(gsettings.subprocess, "check_output",
321+ lambda _: fake_output)
322+ ps = gsettings.get_proxy_settings()
323+ self.assertNotIn(scheme, ps)
324+
325+ def test_gsettings_parser_empty_http_url(self):
326+ """Test when there is no http proxy set."""
327+ self._assert_parser_empty_url('http')
328+
329+ def test_gsettings_parser_empty_https_url(self):
330+ """Test when there is no https proxy set."""
331+ self._assert_parser_empty_url('https')
332+
333
334 class ParseProxyHostTestCase(TestCase):
335 """Test the parsing of the domain."""
336
337=== added file 'ubuntu_sso/utils/webclient/tests/test_qtnetwork.py'
338--- ubuntu_sso/utils/webclient/tests/test_qtnetwork.py 1970-01-01 00:00:00 +0000
339+++ ubuntu_sso/utils/webclient/tests/test_qtnetwork.py 2012-04-03 12:14:21 +0000
340@@ -0,0 +1,157 @@
341+# -*- coding: utf-8 -*-
342+#
343+# Copyright 2011 Canonical Ltd.
344+#
345+# This program is free software: you can redistribute it and/or modify it
346+# under the terms of the GNU General Public License version 3, as published
347+# by the Free Software Foundation.
348+#
349+# This program is distributed in the hope that it will be useful, but
350+# WITHOUT AN WARRANTY; without even the implied warranties of
351+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
352+# PURPOSE. See the GNU General Public License for more details.
353+#
354+# You should have received a copy of the GNU General Public License along
355+# with this program. If not, see <http://www.gnu.org/licenses/>.
356+"""Specific tests for the qt implementation."""
357+
358+from twisted.internet import defer
359+from ubuntuone.devtools.testcases import TestCase
360+
361+from ubuntu_sso.utils.webclient import qtnetwork
362+
363+
364+class FakeQNetworkProxy(object):
365+ """A fake network proxy class."""
366+
367+ def __init__(self, called):
368+ """Create a new instance."""
369+ self.called = called
370+
371+ def __call__(self, *args, **kwargs):
372+ """Fake construnctor."""
373+ return self
374+
375+ # pylint: disable=C0103
376+ def setApplicationProxy(self, proxy):
377+ """Set the application proxy."""
378+ self.called.append(('setApplicationProxy', proxy))
379+ # pylint: enable=C0103
380+
381+
382+class FakeNetworkProxyFactory(object):
383+ """A fake network proxy factory."""
384+
385+ def __init__(self, called, proxy):
386+ """Create a new instance."""
387+ self.called = called
388+ self.proxy = proxy
389+
390+ def __call__(self, *args, **kwargs):
391+ """Fake construnctor."""
392+ return self
393+
394+ # pylint: disable=C0103
395+ def systemProxyForQuery(self, query):
396+ """Get the system proxy."""
397+ self.called.append(('systemProxyForQuery', query))
398+ return [self.proxy]
399+ # pylint: enable=C0103
400+
401+
402+class SetupProxyTestCase(TestCase):
403+ """Test the proxy setup."""
404+
405+ @defer.inlineCallbacks
406+ def setUp(self):
407+ """Set the different tests."""
408+ yield super(SetupProxyTestCase, self).setUp()
409+ self.called = []
410+ self.proxy = 'fake_proxy'
411+
412+ self.network_proxy = FakeQNetworkProxy(self.called)
413+ self.patch(qtnetwork, 'QNetworkProxy', self.network_proxy)
414+
415+ self.network_proxy_factory = FakeNetworkProxyFactory(self.called,
416+ self.proxy)
417+ self.patch(qtnetwork, 'QNetworkProxyFactory',
418+ self.network_proxy_factory)
419+
420+ self.settings = dict(https=dict(username='user', password='pasword'))
421+ self.patch(qtnetwork.gsettings, 'get_proxy_settings',
422+ lambda: self.settings)
423+
424+ def fake_build_proxy(settings):
425+ """Fake build proxy."""
426+ self.called.append(('build_proxy', settings))
427+ return self.proxy
428+
429+ self.patch(qtnetwork, 'build_proxy', fake_build_proxy)
430+ qtnetwork.WebClient.proxy_instance = None
431+ self.addCleanup(self._clean_webclient_instance)
432+
433+ def _set_old_platform(self, platform):
434+ """Set back the platform."""
435+ qtnetwork.sys.platform = platform
436+
437+ def _clean_webclient_instance(self):
438+ """Set the webclient not to have a proxy."""
439+ qtnetwork.WebClient.proxy_instance = None
440+
441+
442+class SetupLinuxProxyTestCase(SetupProxyTestCase):
443+ """Test setting up the proxy."""
444+
445+ @defer.inlineCallbacks
446+ def setUp(self):
447+ """Set the different tests."""
448+ yield super(SetupLinuxProxyTestCase, self).setUp()
449+ old_platform = qtnetwork.sys.platform
450+ qtnetwork.sys.platform = 'linux'
451+ self.addCleanup(self._set_old_platform, old_platform)
452+
453+ def test_setup_proxy(self):
454+ """Test setting the proxy."""
455+ qtnetwork.WebClient()
456+ self.assertEqual(self.proxy, qtnetwork.WebClient.proxy_instance)
457+ self.assertIn(('setApplicationProxy', self.proxy), self.called)
458+ self.assertIn(('build_proxy', self.settings), self.called)
459+
460+ def test_setup_instance_present(self):
461+ """Test when the instanc is present."""
462+ # set the instance and assert we did not reset it
463+ qtnetwork.WebClient.proxy_instance = 'other_proxy'
464+ qtnetwork.WebClient()
465+ self.assertNotEqual(self.proxy, qtnetwork.WebClient.proxy_instance)
466+ self.assertNotIn(('setApplicationProxy', self.proxy), self.called)
467+ self.assertNotIn(('build_proxy', self.settings), self.called)
468+
469+
470+class SetupWindowsProxyTestCase(SetupProxyTestCase):
471+ """Test setting up the proxy."""
472+
473+ @defer.inlineCallbacks
474+ def setUp(self):
475+ """Set the different tests."""
476+ yield super(SetupWindowsProxyTestCase, self).setUp()
477+ old_platform = qtnetwork.sys.platform
478+ qtnetwork.sys.platform = 'win32'
479+ self.addCleanup(self._set_old_platform, old_platform)
480+ self.query = 'query'
481+
482+ self.patch(qtnetwork, 'QNetworkProxyQuery', lambda _: self.query)
483+
484+ def test_setup_proxy(self):
485+ """Test setting the proxy."""
486+ qtnetwork.WebClient()
487+ self.assertEqual(self.proxy, qtnetwork.WebClient.proxy_instance)
488+ self.assertIn(('systemProxyForQuery', self.query), self.called)
489+ self.assertIn(('setApplicationProxy', self.proxy), self.called)
490+
491+ def test_setup_instance_present(self):
492+ """Test when the instanc is present."""
493+ qtnetwork.WebClient.proxy_instance = 'other_proxy'
494+ qtnetwork.WebClient()
495+ self.assertNotEqual(self.proxy, qtnetwork.WebClient.proxy_instance)
496+ self.assertNotIn(('systemProxyForQuery', self.query), self.called)
497+ self.assertNotIn(('setApplicationProxy', self.proxy), self.called)
498
499=== modified file 'ubuntu_sso/utils/windows.py'
500--- ubuntu_sso/utils/windows.py 2012-03-16 22:33:29 +0000
501+++ ubuntu_sso/utils/windows.py 2012-04-03 12:14:21 +0000
502@@ -17,3 +17,46 @@
503 """Platform specific constants and functions (for Windows)."""
504
505 PLATFORM_QSS = ":/windows.qss"
506+
507+from twisted.internet import defer
508+from PyQt4.QtCore import QThread, QCoreApplication
509+
510+
511+class DeferredThread(QThread):
512+ """A thread that runs a given function."""
513+
514+ def __init__(self, f, *args, **kwargs):
515+ """Initialize this thread."""
516+ app = QCoreApplication.instance()
517+ super(DeferredThread, self).__init__(app)
518+ self.deferred = defer.Deferred()
519+ self.f = f
520+ self.args = args
521+ self.kwargs = kwargs
522+ self.succeeded = True
523+ self.result = None
524+ self.finished.connect(self.on_finished)
525+
526+ def run(self):
527+ """This code runs inside the thread."""
528+ try:
529+ self.result = self.f(*self.args, **self.kwargs)
530+ # pylint: disable=W0703
531+ except Exception as e:
532+ self.succeeded = False
533+ self.result = e
534+
535+ def on_finished(self):
536+ """The thread has completed."""
537+ if self.succeeded:
538+ self.deferred.callback(self.result)
539+ else:
540+ self.deferred.errback(self.result)
541+
542+
543+# pylint: disable=C0103
544+def qtDeferToThread(f, *args, **kwargs):
545+ """A Qt-based implementation of deferToThread."""
546+ thread = DeferredThread(f, *args, **kwargs)
547+ thread.start()
548+ return thread.deferred

Subscribers

People subscribed via source and target branches