Merge lp:~mandel/ubuntu-sso-client/implement_windows_networkstatus into lp:ubuntu-sso-client

Proposed by Manuel de la Peña
Status: Merged
Approved by: Manuel de la Peña
Approved revision: 689
Merged at revision: 678
Proposed branch: lp:~mandel/ubuntu-sso-client/implement_windows_networkstatus
Merge into: lp:ubuntu-sso-client
Prerequisite: lp:~mandel/ubuntu-sso-client/implement_windows_keyring
Diff against target: 455 lines (+382/-9)
8 files modified
run-tests (+1/-1)
run-tests.bat (+2/-2)
ubuntu_sso/networkstate/__init__.py (+40/-0)
ubuntu_sso/networkstate/windows.py (+197/-0)
ubuntu_sso/tests/bin/show_nm_state (+1/-1)
ubuntu_sso/tests/networkstate/__init__.py (+17/-0)
ubuntu_sso/tests/networkstate/test_linux_networkstate.py (+5/-5)
ubuntu_sso/tests/networkstate/test_windows_networkstate.py (+119/-0)
To merge this branch: bzr merge lp:~mandel/ubuntu-sso-client/implement_windows_networkstatus
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Alejandro J. Cura (community) linux Approve
Review via email: mp+52091@code.launchpad.net

Commit message

Added the network status implementation for windows.

Description of the change

Added the network status implementation for windows.

To post a comment you must log in.
Revision history for this message
Alejandro J. Cura (alecu) wrote :

Launchpad shows this message: "Conflict adding file run-tests.bat. Moved existing file to run-tests.bat.moved."

This also happens when merging by hand.

Found a few typos (many!):
 * "nameing" -> "naming"
 * "deliberated because we are follwoing" -> "deliberate because we are following"
 * "For more ingo" -> "For more info"
 * "to run in an other" -> "to run in another"
 * "listent" -> "listen"
 * "the machine s connected" -> "the machine is connected"
 * "literner_thread" -> "listener_thread" (more than one replacement)

Otherwise the code looks fine.

review: Needs Fixing
Revision history for this message
Alejandro J. Cura (alecu) wrote :

The "literner" variable name typo is still present in some of the tests.

The really weird thing is that all tests pass, yet this error is only catched by the lint step:

ubuntu_sso/tests/networkstate/test_windows_networkstate.py:
    107: [E1123, TestNetworkManagerState.test_find_online_state_not_connected] Passing unexpected keyword argument 'literner_thread' in function call
    118: [E1123, TestNetworkManagerState.test_find_online_state_connected] Passing unexpected keyword argument 'literner_thread' in function call

review: Needs Fixing
Revision history for this message
Alejandro J. Cura (alecu) wrote :

Ran tests on Linux, detailed review of the code, looking good.

review: Approve (linux)
Revision history for this message
Roberto Alsina (ralsina) wrote :

+1

review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
689. By Manuel de la Peña

Merged with implement_windows_keyring and fixed conflicts.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'run-tests'
2--- run-tests 2010-12-20 15:39:23 +0000
3+++ run-tests 2011-03-15 08:28:29 +0000
4@@ -33,5 +33,5 @@
5 }
6
7 echo "Running test suite for ""$MODULE"
8-`which xvfb-run` u1trial "$MODULE" && style_check
9+`which xvfb-run` u1trial "$MODULE" -i "test_windows_networkstate.py" && style_check
10 rm -rf _trial_temp
11
12=== modified file 'run-tests.bat'
13--- run-tests.bat 2011-03-15 08:28:29 +0000
14+++ run-tests.bat 2011-03-15 08:28:29 +0000
15@@ -51,8 +51,8 @@
16 :PYTHONPRESENT
17 ECHO Python found, executing the tests...
18 :: execute the tests with a number of ignored linux only modules
19-"%PYTHONPATH%\python.exe" "%PYTHONPATH%\Scripts\u1trial" -c ubuntu_sso -i "test_gui.py, test_linux_keyring.py"
20-"%PYTHONPATH%\python.exe" "%PYTHONPATH%\Scripts\u1lint"
21+"%PYTHONPATH%\python.exe" "%PYTHONPATH%\Scripts\u1trial" -c ubuntu_sso -i "test_gui.py, test_linux_keyring.py, test_linux_network_state.py"
22+"%PYTHONPATH%\python.exe" "%PYTHONPATH%\Scripts\u1lint" ubuntu_sso
23 :: test for style if we can, if pep8 is not present, move to the end
24 IF EXIST "%PYTHONPATH%Scripts\pep8.exe"
25 "%PYTHONPATH%\Scripts\pep8.exe" --repeat ubuntu_sso
26
27=== added directory 'ubuntu_sso/networkstate'
28=== added file 'ubuntu_sso/networkstate/__init__.py'
29--- ubuntu_sso/networkstate/__init__.py 1970-01-01 00:00:00 +0000
30+++ ubuntu_sso/networkstate/__init__.py 2011-03-15 08:28:29 +0000
31@@ -0,0 +1,40 @@
32+# -*- coding: utf-8 -*-
33+# Author: Manuel de la Pena <manuel@canonical.com>
34+#
35+# Copyright 2011 Canonical Ltd.
36+#
37+# This program is free software: you can redistribute it and/or modify it
38+# under the terms of the GNU General Public License version 3, as published
39+# by the Free Software Foundation.
40+#
41+# This program is distributed in the hope that it will be useful, but
42+# WITHOUT ANY WARRANTY; without even the implied warranties of
43+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
44+# PURPOSE. See the GNU General Public License for more details.
45+#
46+# You should have received a copy of the GNU General Public License along
47+# with this program. If not, see <http://www.gnu.org/licenses/>.
48+"""Platform specific network status."""
49+
50+import sys
51+
52+# ignore global naming issues.
53+# pylint: disable=C0103
54+
55+NetworkManagerState = None
56+ONLINE = None
57+OFFLINE = None
58+UNKNOWN = None
59+
60+if sys.platform == 'win32':
61+ from ubuntu_sso.networkstate import windows
62+ NetworkManagerState = windows.NetworkManagerState
63+ ONLINE = windows.ONLINE
64+ OFFLINE = windows.OFFLINE
65+ UNKNOWN = windows.UNKNOWN
66+else:
67+ from ubuntu_sso.networkstate import linux
68+ NetworkManagerState = linux.NetworkManagerState
69+ ONLINE = linux.ONLINE
70+ OFFLINE = linux.OFFLINE
71+ UNKNOWN = linux.UNKNOWN
72
73=== renamed file 'ubuntu_sso/networkstate.py' => 'ubuntu_sso/networkstate/linux.py'
74=== added file 'ubuntu_sso/networkstate/windows.py'
75--- ubuntu_sso/networkstate/windows.py 1970-01-01 00:00:00 +0000
76+++ ubuntu_sso/networkstate/windows.py 2011-03-15 08:28:29 +0000
77@@ -0,0 +1,197 @@
78+# -*- coding: utf-8 -*-
79+# Author: Manuel de la Pena <manuel@canonical.com>
80+#
81+# Copyright 2011 Canonical Ltd.
82+#
83+# This program is free software: you can redistribute it and/or modify it
84+# under the terms of the GNU General Public License version 3, as published
85+# by the Free Software Foundation.
86+#
87+# This program is distributed in the hope that it will be useful, but
88+# WITHOUT ANY WARRANTY; without even the implied warranties of
89+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
90+# PURPOSE. See the GNU General Public License for more details.
91+#
92+# You should have received a copy of the GNU General Public License along
93+# with this program. If not, see <http://www.gnu.org/licenses/>.
94+"""Network status implementation on Windows."""
95+
96+# pylint: disable=F0401
97+import pythoncom
98+# pylint: enable=F0401
99+
100+from ctypes import windll, byref
101+from ctypes.wintypes import DWORD
102+from threading import Thread
103+# pylint: disable=F0401
104+from win32com.server.policy import DesignatedWrapPolicy
105+from win32com.client import Dispatch
106+# pylint: enable=F0401
107+
108+from ubuntu_sso.logger import setup_logging
109+
110+logger = setup_logging("ubuntu_sso.networkstate")
111+
112+# naming errors are deliberated because we are following the COM naming to make
113+# it clear for later developers.
114+# pylint: disable=C0103
115+
116+# Values returned by the callback
117+ONLINE, OFFLINE, UNKNOWN = object(), object(), object()
118+
119+## from EventSys.h
120+PROGID_EventSystem = "EventSystem.EventSystem"
121+PROGID_EventSubscription = "EventSystem.EventSubscription"
122+
123+# SENS (System Event Notification Service) values for the events,
124+# this events contain the uuid of the event, the name of the event to be used
125+# as well as the method name of the method in the ISesNetwork interface that
126+# will be executed for the event.
127+# For more info look at:
128+# http://msdn.microsoft.com/en-us/library/aa377384(v=vs.85).aspx
129+
130+SUBSCRIPTION_NETALIVE = ('{cd1dcbd6-a14d-4823-a0d2-8473afde360f}',
131+ 'UbuntuOne Network Alive',
132+ 'ConnectionMade')
133+
134+SUBSCRIPTION_NETALIVE_NOQOC = ('{a82f0e80-1305-400c-ba56-375ae04264a1}',
135+ 'UbuntuOne Net Alive No Info',
136+ 'ConnectionMadeNoQOCInfo')
137+
138+SUBSCRIPTION_NETLOST = ('{45233130-b6c3-44fb-a6af-487c47cee611}',
139+ 'UbuntuOne Network Lost',
140+ 'ConnectionLost')
141+
142+SUBSCRIPTION_REACH = ('{4c6b2afa-3235-4185-8558-57a7a922ac7b}',
143+ 'UbuntuOne Network Reach',
144+ 'ConnectionMade')
145+
146+SUBSCRIPTION_REACH_NOQOC = ('{db62fa23-4c3e-47a3-aef2-b843016177cf}',
147+ 'UbuntuOne Network Reach No Info',
148+ 'ConnectionMadeNoQOCInfo')
149+
150+SUBSCRIPTION_REACH_NOQOC2 = ('{d4d8097a-60c6-440d-a6da-918b619ae4b7}',
151+ 'UbuntuOne Network Reach No Info 2',
152+ 'ConnectionMadeNoQOCInfo')
153+
154+SUBSCRIPTIONS = [SUBSCRIPTION_NETALIVE,
155+ SUBSCRIPTION_NETALIVE_NOQOC,
156+ SUBSCRIPTION_NETLOST,
157+ SUBSCRIPTION_REACH,
158+ SUBSCRIPTION_REACH_NOQOC,
159+ SUBSCRIPTION_REACH_NOQOC2]
160+
161+SENSGUID_EVENTCLASS_NETWORK = '{d5978620-5b9f-11d1-8dd2-00aa004abd5e}'
162+SENSGUID_PUBLISHER = "{5fee1bd6-5b9b-11d1-8dd2-00aa004abd5e}"
163+
164+# uuid of the implemented com interface
165+IID_ISesNetwork = '{d597bab1-5b9f-11d1-8dd2-00aa004abd5e}'
166+
167+
168+class NetworkManager(DesignatedWrapPolicy):
169+ """Implement ISesNetwork to know about the network status."""
170+
171+ _com_interfaces_ = [IID_ISesNetwork]
172+ _public_methods_ = ['ConnectionMade',
173+ 'ConnectionMadeNoQOCInfo',
174+ 'ConnectionLost']
175+ _reg_clsid_ = '{41B032DA-86B5-4907-A7F7-958E59333010}'
176+ _reg_progid_ = "UbuntuOne.NetworkManager"
177+
178+ def __init__(self, connected_cb=None, connected_cb_info=None,
179+ disconnected_cb=None):
180+ # pylint: disable=E1101
181+ self._wrap_(self)
182+ # pylint: enable=E1101
183+ self.connected_cb = connected_cb
184+ self.connected_cb_info = connected_cb_info
185+ self.disconnected_cb = disconnected_cb
186+
187+ def ConnectionMade(self, *args):
188+ """Tell that the connection is up again."""
189+ logger.info('Connection was made.')
190+ if self.connected_cb_info:
191+ self.connected_cb_info()
192+
193+ def ConnectionMadeNoQOCInfo(self, *args):
194+ """Tell that the connection is up again."""
195+ logger.info('Connection was made no info.')
196+ if self.connected_cb:
197+ self.connected_cb()
198+
199+ def ConnectionLost(self, *args):
200+ """Tell the connection was lost."""
201+ logger.info('Connection was lost.')
202+ if self.disconnected_cb:
203+ self.disconnected_cb()
204+
205+ def register(self):
206+ """Register to listen to network events."""
207+ # call the CoInitialize to allow the registration to run in another
208+ # thread
209+ pythoncom.CoInitialize()
210+ # interface to be used by com
211+ manager_interface = pythoncom.WrapObject(self)
212+ event_system = Dispatch(PROGID_EventSystem)
213+ # register to listen to each of the events to make sure that
214+ # the code will work on all platforms.
215+ for current_event in SUBSCRIPTIONS:
216+ # create an event subscription and add it to the event
217+ # service
218+ event_subscription = Dispatch(PROGID_EventSubscription)
219+ event_subscription.EventClassId = SENSGUID_EVENTCLASS_NETWORK
220+ event_subscription.PublisherID = SENSGUID_PUBLISHER
221+ event_subscription.SubscriptionID = current_event[0]
222+ event_subscription.SubscriptionName = current_event[1]
223+ event_subscription.MethodName = current_event[2]
224+ event_subscription.SubscriberInterface = manager_interface
225+ event_subscription.PerUser = True
226+ # store the event
227+ try:
228+ event_system.Store(PROGID_EventSubscription,
229+ event_subscription)
230+ except pythoncom.com_error as e:
231+ logger.error(
232+ 'Error registering %s to event %s', e, current_event[1])
233+
234+ pythoncom.PumpMessages()
235+
236+
237+def is_machine_connected():
238+ """Return if the machine is connected to the internet."""
239+ wininet = windll.wininet
240+ flags = DWORD()
241+ connected = wininet.InternetGetConnectedState(byref(flags), None)
242+ return connected == 1
243+
244+
245+class NetworkManagerState(object):
246+ """Check for status changed in the network on Windows."""
247+
248+ def __init__(self, result_cb, **kwargs):
249+ """Initialize this instance with a result and error callbacks."""
250+ self.result_cb = result_cb
251+
252+ def connection_made(self):
253+ """Return the connection state over the call back."""
254+ self.result_cb(ONLINE)
255+
256+ def connection_lost(self):
257+ """Return the connection was lost over the call back."""
258+ self.result_cb(OFFLINE)
259+
260+ def find_online_state(self, listener=None, listener_thread=None):
261+ """Get the network state and return it thru the set callback."""
262+ # check the current status right now
263+ if is_machine_connected():
264+ self.result_cb(ONLINE)
265+ else:
266+ self.result_cb(OFFLINE)
267+ if listener is None:
268+ # start listening for network changes
269+ listener = NetworkManager(connected_cb=self.connection_made,
270+ disconnected_cb=self.connection_lost)
271+ if listener_thread is None:
272+ listener_thread = Thread(target=listener.register,
273+ name='Ubuntu SSO NetworkManager')
274+ listener_thread.start()
275
276=== modified file 'ubuntu_sso/tests/bin/show_nm_state'
277--- ubuntu_sso/tests/bin/show_nm_state 2010-12-20 14:29:18 +0000
278+++ ubuntu_sso/tests/bin/show_nm_state 2011-03-15 08:28:29 +0000
279@@ -23,7 +23,7 @@
280
281 from dbus.mainloop.glib import DBusGMainLoop
282
283-from ubuntu_sso.networkstate import NetworkManagerState, NM_STATE_NAMES
284+from ubuntu_sso.networkstate.linux import NetworkManagerState, NM_STATE_NAMES
285
286 DBusGMainLoop(set_as_default=True)
287
288
289=== added directory 'ubuntu_sso/tests/networkstate'
290=== added file 'ubuntu_sso/tests/networkstate/__init__.py'
291--- ubuntu_sso/tests/networkstate/__init__.py 1970-01-01 00:00:00 +0000
292+++ ubuntu_sso/tests/networkstate/__init__.py 2011-03-15 08:28:29 +0000
293@@ -0,0 +1,17 @@
294+# -*- coding: utf-8 -*-
295+# Author: Manuel de la Pena <manuel@canonical.com>
296+#
297+# Copyright 2011 Canonical Ltd.
298+#
299+# This program is free software: you can redistribute it and/or modify it
300+# under the terms of the GNU General Public License version 3, as published
301+# by the Free Software Foundation.
302+#
303+# This program is distributed in the hope that it will be useful, but
304+# WITHOUT ANY WARRANTY; without even the implied warranties of
305+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
306+# PURPOSE. See the GNU General Public License for more details.
307+#
308+# You should have received a copy of the GNU General Public License along
309+# with this program. If not, see <http://www.gnu.org/licenses/>.
310+"""Test the different networkstatus implementations."""
311
312=== renamed file 'ubuntu_sso/tests/test_networkstate.py' => 'ubuntu_sso/tests/networkstate/test_linux_networkstate.py'
313--- ubuntu_sso/tests/test_networkstate.py 2010-09-30 18:57:38 +0000
314+++ ubuntu_sso/tests/networkstate/test_linux_networkstate.py 2011-03-15 08:28:29 +0000
315@@ -20,11 +20,11 @@
316 """Tests for the network state detection code."""
317
318 from ubuntu_sso.networkstate import (NetworkManagerState,
319- DBUS_UNKNOWN_SERVICE,
320- ONLINE, OFFLINE, UNKNOWN,
321- NM_STATE_DISCONNECTED,
322- NM_STATE_CONNECTING,
323- NM_STATE_CONNECTED)
324+ ONLINE, OFFLINE, UNKNOWN)
325+from ubuntu_sso.networkstate.linux import (DBUS_UNKNOWN_SERVICE,
326+ NM_STATE_DISCONNECTED,
327+ NM_STATE_CONNECTING,
328+ NM_STATE_CONNECTED)
329
330 from mocker import ARGS, KWARGS, ANY, MockerTestCase
331
332
333=== added file 'ubuntu_sso/tests/networkstate/test_windows_networkstate.py'
334--- ubuntu_sso/tests/networkstate/test_windows_networkstate.py 1970-01-01 00:00:00 +0000
335+++ ubuntu_sso/tests/networkstate/test_windows_networkstate.py 2011-03-15 08:28:29 +0000
336@@ -0,0 +1,119 @@
337+# -*- coding: utf-8 -*-
338+#
339+# Author: Manuel de la Pena<manuel@canonical.com>
340+#
341+# Copyright 2011 Canonical Ltd.
342+#
343+# This program is free software: you can redistribute it and/or modify it
344+# under the terms of the GNU General Public License version 3, as published
345+# by the Free Software Foundation.
346+#
347+# This program is distributed in the hope that it will be useful, but
348+# WITHOUT ANY WARRANTY; without even the implied warranties of
349+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
350+# PURPOSE. See the GNU General Public License for more details.
351+#
352+# You should have received a copy of the GNU General Public License along
353+# with this program. If not, see <http://www.gnu.org/licenses/>.
354+"""Tests for the network manager."""
355+from mocker import MockerTestCase
356+from ubuntu_sso.networkstate.windows import (
357+ NetworkManager,
358+ NetworkManagerState,
359+ ONLINE,
360+ OFFLINE)
361+
362+
363+class TestNetworkManager(MockerTestCase):
364+ """Test he Network Manager."""
365+
366+ def setUp(self):
367+ super(TestNetworkManager, self).setUp()
368+ self.connection_info = self.mocker.mock()
369+ self.connection_no_info = self.mocker.mock()
370+ self.disconnected = self.mocker.mock()
371+ self.manager = NetworkManager(self.connection_no_info,
372+ self.connection_info, self.disconnected)
373+
374+ def test_connection_made(self):
375+ """Ensure db is called."""
376+ self.connection_info()
377+ self.mocker.replay()
378+ self.manager.ConnectionMade()
379+
380+ def test_connection_made_no_cb(self):
381+ """Ensure db is called."""
382+ self.manager.connected_cb_info = None
383+ self.mocker.replay()
384+ self.manager.ConnectionMade()
385+
386+ def test_connection_made_no_info(self):
387+ """Ensure db is called."""
388+ self.connection_no_info()
389+ self.mocker.replay()
390+ self.manager.ConnectionMadeNoQOCInfo()
391+
392+ def test_connection_made_no_info_no_cb(self):
393+ """Ensure db is called."""
394+ self.manager.connected_cb = None
395+ self.mocker.replay()
396+ self.manager.ConnectionMadeNoQOCInfo()
397+
398+ def test_disconnection(self):
399+ """Ensure db is called."""
400+ self.disconnected()
401+ self.mocker.replay()
402+ self.manager.ConnectionLost()
403+
404+ def test_disconnection_no_cb(self):
405+ """Ensure db is called."""
406+ self.manager.disconnected_cb = None
407+ self.mocker.replay()
408+ self.manager.ConnectionLost()
409+
410+
411+class TestNetworkManagerState(MockerTestCase):
412+ """Test he Network Manager State."""
413+
414+ def setUp(self):
415+ super(TestNetworkManagerState, self).setUp()
416+ self.network_manager = self.mocker.mock()
417+ self.is_connected = self.mocker.replace(
418+ 'ubuntu_sso.networkstate.windows.is_machine_connected')
419+ self.thread = self.mocker.mock()
420+ self.cb = self.mocker.mock()
421+ self.state = NetworkManagerState(self.cb)
422+
423+ def test_connection_made(self):
424+ """Test that the cb is actually called."""
425+ self.cb(ONLINE)
426+ self.mocker.replay()
427+ self.state.connection_made()
428+
429+ def test_connection_lost(self):
430+ """Test that the cb is actually called."""
431+ self.cb(OFFLINE)
432+ self.mocker.replay()
433+ self.state.connection_lost()
434+
435+ def test_find_online_state_not_connected(self):
436+ """Test that we do find the online state correctly."""
437+ self.is_connected()
438+ self.mocker.result(False)
439+ self.cb(OFFLINE)
440+ self.mocker.result(self.thread)
441+ self.thread.start()
442+ self.mocker.replay()
443+ self.state.find_online_state(listener=self.network_manager,
444+ listener_thread=self.thread)
445+
446+ def test_find_online_state_connected(self):
447+ """Test that we do find the online state correctly."""
448+ self.is_connected()
449+ self.mocker.result(ONLINE)
450+ self.cb(ONLINE)
451+ self.mocker.result(self.thread)
452+ self.thread.start()
453+ self.mocker.replay()
454+ self.state.find_online_state(listener=self.network_manager,
455+ listener_thread=self.thread)

Subscribers

People subscribed via source and target branches