Merge lp:~diegosarmentero/ubuntuone-control-panel/socket-communication into lp:ubuntuone-control-panel
- socket-communication
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | dobey | ||||
Approved revision: | 393 | ||||
Merged at revision: | 378 | ||||
Proposed branch: | lp:~diegosarmentero/ubuntuone-control-panel/socket-communication | ||||
Merge into: | lp:ubuntuone-control-panel | ||||
Diff against target: |
351 lines (+188/-10) 6 files modified
ubuntuone/controlpanel/gui/qt/gui.py (+16/-0) ubuntuone/controlpanel/gui/qt/main/tests/test_main.py (+1/-1) ubuntuone/controlpanel/gui/qt/tests/test_start.py (+11/-0) ubuntuone/controlpanel/gui/qt/uniqueapp/__init__.py (+56/-0) ubuntuone/controlpanel/gui/qt/uniqueapp/tests/test_unique_app.py (+99/-4) ubuntuone/controlpanel/gui/tests/__init__.py (+5/-5) |
||||
To merge this branch: | bzr merge lp:~diegosarmentero/ubuntuone-control-panel/socket-communication | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike McCracken (community) | Approve | ||
dobey (community) | Approve | ||
Review via email: mp+132409@code.launchpad.net |
Commit message
- Adding socket communication, so the new instances can send messages to the already running instance (LP: #1063927).
Description of the change
Currently this only supports the "switch to tab" option, because it's the only one that is being used, and it didn't make any sense to me to send the other args to the already running application, although it can be easily extended.
You can test this IRL, running an instance of UbuntuOne Client (the one which adds the "Share a File" option will be the best option to test it) adding this branch to the PYTHONPATH of that instance, and choose the "Share a file" option from the menu and see how control panel behaves.
- 378. By Diego Sarmentero
-
fixing docstring
- 379. By Diego Sarmentero
-
executes show normal for not arg cases
- 380. By Diego Sarmentero
-
always raise
- 381. By Diego Sarmentero
-
improve tests
- 382. By Diego Sarmentero
-
fixing activatewindow
- 383. By Diego Sarmentero
-
adding showNormal
- 384. By Diego Sarmentero
-
removing commented line
- 385. By Diego Sarmentero
-
removed unused code
dobey (dobey) wrote : | # |
Just updated with the latest revno of this, and it's still opening 2 instances of the control panel for me.
- 386. By Diego Sarmentero
-
adding try-except
- 387. By Diego Sarmentero
-
force raise
- 388. By Diego Sarmentero
-
show on minimized
- 389. By Diego Sarmentero
-
improve tests redeability
dobey (dobey) wrote : | # |
I still don't like that it doesn't guarantee that focus will be grabbed, or that the window will be raised, but this does seem to be a problem with Qt itself.
- 390. By Diego Sarmentero
-
adding comment to explain protocol
Mike McCracken (mikemc) wrote : | # |
The code is a little fragile wrt crashes. (This branch hasn't made it any worse, but now's a good time to fix this, since it's short and related.)
If CP crashes and doesn't get to call removeServer, then the socket file is left around and future servers can't be started with the same name, so from then on, every invocation of CP will fail to connect to a server, think it's the unique instance, and start up happily.
I'd like to suggest a couple of improvements:
1. check self.ready, the response from server.listen. If this is false, log server.
2. call self.cleanup() (or just server.
This should be ok to call unconditionally, because if we get to this line, we've failed to connect to any server on that socket, and we really should be the unique instance.
NOTE: windows doesn't use socket files, but Qt says that removeServer does nothing on windows, so at least this shouldn't break anything.
With these changes, I am seeing no problems on osx even when I cause a CP crash and verify that there's a zombie socket file before I try re-starting CP.
- 391. By Diego Sarmentero
-
Making sure that the server is cleaned in case of fail
Diego Sarmentero (diegosarmentero) wrote : | # |
> The code is a little fragile wrt crashes. (This branch hasn't made it any
> worse, but now's a good time to fix this, since it's short and related.)
>
> If CP crashes and doesn't get to call removeServer, then the socket file is
> left around and future servers can't be started with the same name, so from
> then on, every invocation of CP will fail to connect to a server, think it's
> the unique instance, and start up happily.
>
> I'd like to suggest a couple of improvements:
> 1. check self.ready, the response from server.listen. If this is false, log
> server.
> works and having this log would've made it a lot easier to find the problem I
> was seeing.
>
> 2. call self.cleanup() (or just server.
> the event that another CP has crashed, leaving around a socket file, this will
> clean it up so server.listen should always succeed like we want.
>
> This should be ok to call unconditionally, because if we get to this line,
> we've failed to connect to any server on that socket, and we really should be
> the unique instance.
>
> NOTE: windows doesn't use socket files, but Qt says that removeServer does
> nothing on windows, so at least this shouldn't break anything.
>
> With these changes, I am seeing no problems on osx even when I cause a CP
> crash and verify that there's a zombie socket file before I try re-starting
> CP.
Done!
- 392. By Diego Sarmentero
-
adding more tests
- 393. By Diego Sarmentero
-
removing unused import
Mike McCracken (mikemc) wrote : | # |
looks good, tests pass on darwin. thanks!
Preview Diff
1 | === modified file 'ubuntuone/controlpanel/gui/qt/gui.py' | |||
2 | --- ubuntuone/controlpanel/gui/qt/gui.py 2012-08-20 17:51:54 +0000 | |||
3 | +++ ubuntuone/controlpanel/gui/qt/gui.py 2012-11-05 17:30:44 +0000 | |||
4 | @@ -61,6 +61,21 @@ | |||
5 | 61 | else: | 61 | else: |
6 | 62 | self.entry = None | 62 | self.entry = None |
7 | 63 | 63 | ||
8 | 64 | def connect_app_signal(self, app): | ||
9 | 65 | """Connect App signals.""""" | ||
10 | 66 | app.switch_to.connect(self.switch_to) | ||
11 | 67 | app.activate_window.connect(self.raise_to_top) | ||
12 | 68 | |||
13 | 69 | def raise_to_top(self): | ||
14 | 70 | """Force the application to raise in top of any other app.""" | ||
15 | 71 | self.activateWindow() | ||
16 | 72 | self.raise_() | ||
17 | 73 | if self.isMinimized(): | ||
18 | 74 | self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) | ||
19 | 75 | self.showNormal() | ||
20 | 76 | self.setWindowFlags(QtCore.Qt.Window) | ||
21 | 77 | self.showNormal() | ||
22 | 78 | |||
23 | 64 | def _setup(self): | 79 | def _setup(self): |
24 | 65 | """Do some extra setupping for the UI.""" | 80 | """Do some extra setupping for the UI.""" |
25 | 66 | self.ui.control_panel.finished.connect(self.close) | 81 | self.ui.control_panel.finished.connect(self.close) |
26 | @@ -128,6 +143,7 @@ | |||
27 | 128 | window.check_updates() | 143 | window.check_updates() |
28 | 129 | window.show() | 144 | window.show() |
29 | 130 | window.raise_() | 145 | window.raise_() |
30 | 146 | window.connect_app_signal(app) | ||
31 | 131 | else: | 147 | else: |
32 | 132 | window = None | 148 | window = None |
33 | 133 | if with_icon or minimized: | 149 | if with_icon or minimized: |
34 | 134 | 150 | ||
35 | === modified file 'ubuntuone/controlpanel/gui/qt/main/tests/test_main.py' | |||
36 | --- ubuntuone/controlpanel/gui/qt/main/tests/test_main.py 2012-10-04 20:47:39 +0000 | |||
37 | +++ ubuntuone/controlpanel/gui/qt/main/tests/test_main.py 2012-11-05 17:30:44 +0000 | |||
38 | @@ -274,7 +274,7 @@ | |||
39 | 274 | """Ensure the new_instance signal is connected.""" | 274 | """Ensure the new_instance signal is connected.""" |
40 | 275 | main.main([sys.argv[0]]) | 275 | main.main([sys.argv[0]]) |
41 | 276 | self.assertEqual(self.app.new_instance.target, | 276 | self.assertEqual(self.app.new_instance.target, |
43 | 277 | self.start.window.raise_) | 277 | [self.start.window.raise_]) |
44 | 278 | 278 | ||
45 | 279 | def test_darwin_installs_qt4reactor(self): | 279 | def test_darwin_installs_qt4reactor(self): |
46 | 280 | """Ensure the qt4 reactor is installed when requested.""" | 280 | """Ensure the qt4 reactor is installed when requested.""" |
47 | 281 | 281 | ||
48 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_start.py' | |||
49 | --- ubuntuone/controlpanel/gui/qt/tests/test_start.py 2012-06-28 05:32:24 +0000 | |||
50 | +++ ubuntuone/controlpanel/gui/qt/tests/test_start.py 2012-11-05 17:30:44 +0000 | |||
51 | @@ -36,6 +36,7 @@ | |||
52 | 36 | def __init__(self): | 36 | def __init__(self): |
53 | 37 | self.args = [] | 37 | self.args = [] |
54 | 38 | self.updates_checked = defer.Deferred() | 38 | self.updates_checked = defer.Deferred() |
55 | 39 | self.app = None | ||
56 | 39 | 40 | ||
57 | 40 | def __call__(self, *args, **kwargs): | 41 | def __call__(self, *args, **kwargs): |
58 | 41 | self.args.append((args, kwargs)) | 42 | self.args.append((args, kwargs)) |
59 | @@ -57,6 +58,10 @@ | |||
60 | 57 | self.updates_checked.callback(None) | 58 | self.updates_checked.callback(None) |
61 | 58 | return self.updates_checked | 59 | return self.updates_checked |
62 | 59 | 60 | ||
63 | 61 | def connect_app_signal(self, app): | ||
64 | 62 | """Fake connect_app_signal.""" | ||
65 | 63 | self.app = app | ||
66 | 64 | |||
67 | 60 | 65 | ||
68 | 61 | class StartTestCase(TestCase): | 66 | class StartTestCase(TestCase): |
69 | 62 | """Test the qt control panel.""" | 67 | """Test the qt control panel.""" |
70 | @@ -124,3 +129,9 @@ | |||
71 | 124 | # a timeout in this test means that the check_updates method | 129 | # a timeout in this test means that the check_updates method |
72 | 125 | # was not called | 130 | # was not called |
73 | 126 | yield self.main_window.updates_checked | 131 | yield self.main_window.updates_checked |
74 | 132 | |||
75 | 133 | def test_connect_app_signals_is_called(self): | ||
76 | 134 | """Check that connect_app_signal is properly called on start.""" | ||
77 | 135 | gui.start(close_callback=self.close_cb) | ||
78 | 136 | app = gui.QtGui.QApplication.instance() | ||
79 | 137 | self.assertEqual(self.main_window.app, app) | ||
80 | 127 | 138 | ||
81 | === modified file 'ubuntuone/controlpanel/gui/qt/uniqueapp/__init__.py' | |||
82 | --- ubuntuone/controlpanel/gui/qt/uniqueapp/__init__.py 2012-04-24 17:59:49 +0000 | |||
83 | +++ ubuntuone/controlpanel/gui/qt/uniqueapp/__init__.py 2012-11-05 17:30:44 +0000 | |||
84 | @@ -20,15 +20,31 @@ | |||
85 | 20 | 20 | ||
86 | 21 | from PyQt4 import QtNetwork, QtGui, QtCore | 21 | from PyQt4 import QtNetwork, QtGui, QtCore |
87 | 22 | 22 | ||
88 | 23 | from ubuntuone.controlpanel.logger import setup_logging | ||
89 | 24 | |||
90 | 25 | |||
91 | 26 | logger = setup_logging('uniqueapp') | ||
92 | 27 | |||
93 | 28 | # Arg with valid value | ||
94 | 29 | SOCKET_MESSAGES = { | ||
95 | 30 | '--switch-to': ["folders", "share_links", "devices", | ||
96 | 31 | "settings", "account"], | ||
97 | 32 | } | ||
98 | 33 | |||
99 | 23 | 34 | ||
100 | 24 | class UniqueApplication(QtGui.QApplication): | 35 | class UniqueApplication(QtGui.QApplication): |
101 | 25 | 36 | ||
102 | 26 | """A dummy UniqueApplication class.""" | 37 | """A dummy UniqueApplication class.""" |
103 | 27 | 38 | ||
104 | 28 | new_instance = QtCore.pyqtSignal() | 39 | new_instance = QtCore.pyqtSignal() |
105 | 40 | switch_to = QtCore.pyqtSignal(unicode) | ||
106 | 41 | activate_window = QtCore.pyqtSignal() | ||
107 | 29 | 42 | ||
108 | 30 | def __init__(self, argv, key): | 43 | def __init__(self, argv, key): |
109 | 31 | super(UniqueApplication, self).__init__(argv) | 44 | super(UniqueApplication, self).__init__(argv) |
110 | 45 | self.mapping_signals = { | ||
111 | 46 | '--switch-to': self.switch_to, | ||
112 | 47 | } | ||
113 | 32 | self.key = key | 48 | self.key = key |
114 | 33 | self.server = QtNetwork.QLocalServer(self) | 49 | self.server = QtNetwork.QLocalServer(self) |
115 | 34 | self.server.newConnection.connect(self.new_instance.emit) | 50 | self.server.newConnection.connect(self.new_instance.emit) |
116 | @@ -38,11 +54,51 @@ | |||
117 | 38 | socket.connectToServer(key, QtCore.QIODevice.WriteOnly) | 54 | socket.connectToServer(key, QtCore.QIODevice.WriteOnly) |
118 | 39 | if socket.waitForConnected(500): | 55 | if socket.waitForConnected(500): |
119 | 40 | # Connected, exit | 56 | # Connected, exit |
120 | 57 | self._send_messages(socket, argv) | ||
121 | 41 | sys.exit() | 58 | sys.exit() |
122 | 42 | 59 | ||
123 | 43 | # Not connected, start server | 60 | # Not connected, start server |
124 | 61 | self.cleanup() | ||
125 | 44 | self.ready = self.server.listen(key) | 62 | self.ready = self.server.listen(key) |
126 | 63 | if not self.ready: | ||
127 | 64 | logger.debug(self.server.errorString()) | ||
128 | 65 | self.server.newConnection.connect(self._process_messages) | ||
129 | 45 | 66 | ||
130 | 46 | def cleanup(self): | 67 | def cleanup(self): |
131 | 47 | """Remove the socket when we die.""" | 68 | """Remove the socket when we die.""" |
132 | 48 | self.server.removeServer(self.key) | 69 | self.server.removeServer(self.key) |
133 | 70 | |||
134 | 71 | def _send_messages(self, socket, argv): | ||
135 | 72 | """Send messages to the running application.""" | ||
136 | 73 | # This only take care of those args that are defined in SOCKET_MESSAGES | ||
137 | 74 | # at this moment just "--switch-to", sending a message to the already | ||
138 | 75 | # running client with: "arg=arg_value". If we have more than a single | ||
139 | 76 | # arg, each arg is concatenated with "|". | ||
140 | 77 | try: | ||
141 | 78 | data = [] | ||
142 | 79 | size_argv = len(argv) | ||
143 | 80 | for index in range(2, size_argv): | ||
144 | 81 | if (argv[index] in SOCKET_MESSAGES and index < size_argv and | ||
145 | 82 | argv[index + 1] in SOCKET_MESSAGES[argv[index]]): | ||
146 | 83 | data.append('%s=%s' % (argv[index], argv[index + 1])) | ||
147 | 84 | message = '|'.join(data) | ||
148 | 85 | socket.write(message) | ||
149 | 86 | socket.flush() | ||
150 | 87 | socket.close() | ||
151 | 88 | except: | ||
152 | 89 | # The message couldn't be send through the socket, | ||
153 | 90 | # but we avoided to open multiple instances of control panel. | ||
154 | 91 | pass | ||
155 | 92 | |||
156 | 93 | def _process_messages(self): | ||
157 | 94 | """Get the messages from the other instances.""" | ||
158 | 95 | connection = self.server.nextPendingConnection() | ||
159 | 96 | connection.waitForReadyRead() | ||
160 | 97 | data = unicode(connection.readAll()).split('|') | ||
161 | 98 | connection.close() | ||
162 | 99 | for item in data: | ||
163 | 100 | item_value = item.split('=') | ||
164 | 101 | signal = self.mapping_signals.get(item_value[0]) | ||
165 | 102 | if signal: | ||
166 | 103 | signal.emit(item_value[1]) | ||
167 | 104 | self.activate_window.emit() | ||
168 | 49 | 105 | ||
169 | === modified file 'ubuntuone/controlpanel/gui/qt/uniqueapp/tests/test_unique_app.py' | |||
170 | --- ubuntuone/controlpanel/gui/qt/uniqueapp/tests/test_unique_app.py 2012-04-24 17:59:49 +0000 | |||
171 | +++ ubuntuone/controlpanel/gui/qt/uniqueapp/tests/test_unique_app.py 2012-11-05 17:30:44 +0000 | |||
172 | @@ -19,9 +19,9 @@ | |||
173 | 19 | from PyQt4 import QtCore | 19 | from PyQt4 import QtCore |
174 | 20 | from twisted.internet.defer import inlineCallbacks | 20 | from twisted.internet.defer import inlineCallbacks |
175 | 21 | 21 | ||
176 | 22 | from ubuntuone.controlpanel.gui.tests import FakeSignal | ||
177 | 22 | from ubuntuone.controlpanel.gui.qt import uniqueapp | 23 | from ubuntuone.controlpanel.gui.qt import uniqueapp |
178 | 23 | from ubuntuone.controlpanel.tests import TestCase | 24 | from ubuntuone.controlpanel.tests import TestCase |
179 | 24 | from ubuntuone.controlpanel.gui.tests import FakeSignal | ||
180 | 25 | 25 | ||
181 | 26 | 26 | ||
182 | 27 | #pylint: disable=C0103 | 27 | #pylint: disable=C0103 |
183 | @@ -32,6 +32,7 @@ | |||
184 | 32 | self.connect_calls = [] | 32 | self.connect_calls = [] |
185 | 33 | self.connect_timeouts = [] | 33 | self.connect_timeouts = [] |
186 | 34 | self.connect_succeeds = True | 34 | self.connect_succeeds = True |
187 | 35 | self.message = None | ||
188 | 35 | 36 | ||
189 | 36 | def connectToServer(self, *args, **kwargs): | 37 | def connectToServer(self, *args, **kwargs): |
190 | 37 | """Fake connectToServer.""" | 38 | """Fake connectToServer.""" |
191 | @@ -42,18 +43,51 @@ | |||
192 | 42 | self.connect_timeouts.append(timeout) | 43 | self.connect_timeouts.append(timeout) |
193 | 43 | return self.connect_succeeds | 44 | return self.connect_succeeds |
194 | 44 | 45 | ||
195 | 46 | def write(self, message): | ||
196 | 47 | """Fake write.""" | ||
197 | 48 | self.message = message | ||
198 | 49 | |||
199 | 50 | def flush(self): | ||
200 | 51 | """Fake flush.""" | ||
201 | 52 | |||
202 | 53 | def close(self): | ||
203 | 54 | """Fake close.""" | ||
204 | 55 | |||
205 | 56 | def waitForReadyRead(self): | ||
206 | 57 | """Fake waitForReadyRead.""" | ||
207 | 58 | |||
208 | 59 | def readAll(self): | ||
209 | 60 | """Fake readAll: return the message.""" | ||
210 | 61 | return self.message | ||
211 | 62 | |||
212 | 45 | 63 | ||
213 | 46 | class FakeLocalServer(object): | 64 | class FakeLocalServer(object): |
214 | 47 | 65 | ||
215 | 48 | """A fake QLocalServer.""" | 66 | """A fake QLocalServer.""" |
216 | 49 | 67 | ||
218 | 50 | def __init__(self): | 68 | def __init__(self, connected=True): |
219 | 51 | self.newConnection = FakeSignal() | 69 | self.newConnection = FakeSignal() |
220 | 52 | self.listen_args = [] | 70 | self.listen_args = [] |
221 | 71 | self.socket = None | ||
222 | 72 | self._removed_key = None | ||
223 | 73 | self._is_connected = connected | ||
224 | 53 | 74 | ||
225 | 54 | def listen(self, *args, **kwargs): | 75 | def listen(self, *args, **kwargs): |
226 | 55 | """Fake listen.""" | 76 | """Fake listen.""" |
227 | 56 | self.listen_args.append((args, kwargs)) | 77 | self.listen_args.append((args, kwargs)) |
228 | 78 | return self._is_connected | ||
229 | 79 | |||
230 | 80 | def nextPendingConnection(self): | ||
231 | 81 | """Fake nextPendingConnection.""" | ||
232 | 82 | return self.socket | ||
233 | 83 | |||
234 | 84 | def removeServer(self, key): | ||
235 | 85 | """Fake removeServer.""" | ||
236 | 86 | self._removed_key = key | ||
237 | 87 | |||
238 | 88 | def errorString(self): | ||
239 | 89 | """Fake errorString.""" | ||
240 | 90 | return 'error' | ||
241 | 57 | 91 | ||
242 | 58 | 92 | ||
243 | 59 | class FakeApplication(object): | 93 | class FakeApplication(object): |
244 | @@ -77,6 +111,21 @@ | |||
245 | 77 | self.patch(uniqueapp.UniqueApplication, "aboutToQuit", self.fake_quit) | 111 | self.patch(uniqueapp.UniqueApplication, "aboutToQuit", self.fake_quit) |
246 | 78 | self.patch(uniqueapp.QtGui, "QApplication", FakeApplication) | 112 | self.patch(uniqueapp.QtGui, "QApplication", FakeApplication) |
247 | 79 | 113 | ||
248 | 114 | def test_cleanup_called_on_init(self): | ||
249 | 115 | """Check that cleanup is called on initialization.""" | ||
250 | 116 | uniapp = uniqueapp.UniqueApplication([], "key") | ||
251 | 117 | self.assertEqual("key", uniapp.server._removed_key) | ||
252 | 118 | |||
253 | 119 | def test_on_failed_connection(self): | ||
254 | 120 | """Check the flow of the program on connection fail.""" | ||
255 | 121 | data = [] | ||
256 | 122 | local_server = FakeLocalServer(False) | ||
257 | 123 | self.patch(uniqueapp.QtNetwork, "QLocalServer", | ||
258 | 124 | lambda parent: local_server) | ||
259 | 125 | self.patch(uniqueapp.logger, "debug", data.append) | ||
260 | 126 | uniqueapp.UniqueApplication([], "key") | ||
261 | 127 | self.assertEqual(data, ['error']) | ||
262 | 128 | |||
263 | 80 | def test_client_socket(self): | 129 | def test_client_socket(self): |
264 | 81 | """Check that the client socket is used correctly.""" | 130 | """Check that the client socket is used correctly.""" |
265 | 82 | self.local_socket.connect_succeeds = True | 131 | self.local_socket.connect_succeeds = True |
266 | @@ -105,10 +154,56 @@ | |||
267 | 105 | app = uniqueapp.UniqueApplication([], "key") | 154 | app = uniqueapp.UniqueApplication([], "key") |
268 | 106 | # Yes, this is ugly. I can't find any other meaningful | 155 | # Yes, this is ugly. I can't find any other meaningful |
269 | 107 | # way to compare them though. | 156 | # way to compare them though. |
271 | 108 | self.assertEqual(str(app.server.newConnection.target.__self__), | 157 | self.assertEqual(str(app.server.newConnection.target[0].__self__), |
272 | 109 | str(app.new_instance)) | 158 | str(app.new_instance)) |
273 | 159 | self.assertEqual(app.server.newConnection.target[1], | ||
274 | 160 | app._process_messages) | ||
275 | 110 | 161 | ||
276 | 111 | def test_cleanup(self): | 162 | def test_cleanup(self): |
277 | 112 | """Check that cleanup is called with the right key.""" | 163 | """Check that cleanup is called with the right key.""" |
278 | 113 | app = uniqueapp.UniqueApplication([], "key") | 164 | app = uniqueapp.UniqueApplication([], "key") |
280 | 114 | self.assertEqual(self.fake_quit.target, app.cleanup) | 165 | self.assertEqual(self.fake_quit.target, [app.cleanup]) |
281 | 166 | |||
282 | 167 | def test_send_messages_valid(self): | ||
283 | 168 | """Check the message is created correctly.""" | ||
284 | 169 | self.local_socket.connect_succeeds = True | ||
285 | 170 | argv = ['python', 'ubuntuone-control-panel-qt', | ||
286 | 171 | '--switch-to', 'share_links'] | ||
287 | 172 | uniqueapp.UniqueApplication(argv, "key") | ||
288 | 173 | expected = "--switch-to=share_links" | ||
289 | 174 | self.assertEqual(self.local_socket.message, expected) | ||
290 | 175 | |||
291 | 176 | def test_send_messages_invalid(self): | ||
292 | 177 | """Check the message is created correctly.""" | ||
293 | 178 | self.local_socket.connect_succeeds = True | ||
294 | 179 | argv = ['python', 'ubuntuone-control-panel-qt'] | ||
295 | 180 | uniqueapp.UniqueApplication(argv, "key") | ||
296 | 181 | expected = "" | ||
297 | 182 | self.assertEqual(self.local_socket.message, expected) | ||
298 | 183 | |||
299 | 184 | def test_process_message_with_message(self): | ||
300 | 185 | """Check that we are able to parse the message received.""" | ||
301 | 186 | data = [] | ||
302 | 187 | self.local_socket.connect_succeeds = True | ||
303 | 188 | argv = ['python', 'ubuntuone-control-panel-qt', | ||
304 | 189 | '--switch-to', 'share_links'] | ||
305 | 190 | app = uniqueapp.UniqueApplication(argv, "key") | ||
306 | 191 | self.local_server.socket = self.local_socket | ||
307 | 192 | app.switch_to.connect(data.append) | ||
308 | 193 | app.activate_window.connect(lambda: data.append(True)) | ||
309 | 194 | |||
310 | 195 | app.server.newConnection.emit() | ||
311 | 196 | self.assertEqual(data, ["share_links", True]) | ||
312 | 197 | |||
313 | 198 | def test_process_message_no_message(self): | ||
314 | 199 | """Check that we are able to parse the message received.""" | ||
315 | 200 | data = [] | ||
316 | 201 | self.local_socket.connect_succeeds = True | ||
317 | 202 | argv = ['python', 'ubuntuone-control-panel-qt'] | ||
318 | 203 | app = uniqueapp.UniqueApplication(argv, "key") | ||
319 | 204 | self.local_server.socket = self.local_socket | ||
320 | 205 | app.switch_to.connect(data.append) | ||
321 | 206 | app.activate_window.connect(lambda: data.append(True)) | ||
322 | 207 | |||
323 | 208 | app.server.newConnection.emit() | ||
324 | 209 | self.assertEqual(data, [True]) | ||
325 | 115 | 210 | ||
326 | === modified file 'ubuntuone/controlpanel/gui/tests/__init__.py' | |||
327 | --- ubuntuone/controlpanel/gui/tests/__init__.py 2012-04-24 17:59:49 +0000 | |||
328 | +++ ubuntuone/controlpanel/gui/tests/__init__.py 2012-11-05 17:30:44 +0000 | |||
329 | @@ -185,17 +185,17 @@ | |||
330 | 185 | 185 | ||
331 | 186 | def __init__(self, *args, **kwargs): | 186 | def __init__(self, *args, **kwargs): |
332 | 187 | """Initialize.""" | 187 | """Initialize.""" |
334 | 188 | self.target = None | 188 | self.target = [] |
335 | 189 | 189 | ||
336 | 190 | def connect(self, target): | 190 | def connect(self, target): |
337 | 191 | """Fake connect.""" | 191 | """Fake connect.""" |
339 | 192 | self.target = target | 192 | self.target.append(target) |
340 | 193 | 193 | ||
341 | 194 | def disconnect(self, *args): | 194 | def disconnect(self, *args): |
342 | 195 | """Fake disconnect.""" | 195 | """Fake disconnect.""" |
344 | 196 | self.target = None | 196 | self.target = [] |
345 | 197 | 197 | ||
346 | 198 | def emit(self, *args): | 198 | def emit(self, *args): |
347 | 199 | """Fake emit.""" | 199 | """Fake emit.""" |
350 | 200 | if self.target: | 200 | for target in self.target: |
351 | 201 | self.target(*args) | 201 | target(*args) |
This is still not working for me (the tab does switch, but the window doesn't get focus, or raised from minimized state). Also, the latest change seems to result in the unique app support being broken, and I get multiple control panel instances with it.