1# Copyright (C) 2009 Nokia Corporation
2# Copyright (C) 2009-2010 Collabora Ltd.
3#
4# This library is free software; you can redistribute it and/or
5# modify it under the terms of the GNU Lesser General Public
6# License as published by the Free Software Foundation; either
7# version 2.1 of the License, or (at your option) any later version.
8#
9# This library is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public
15# License along with this library; if not, write to the Free Software
16# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17# 02110-1301 USA
18
19import dbus
20
21from servicetest import (EventPattern, tp_name_prefix, tp_path_prefix,
22        call_async, assertEquals)
23from mctest import exec_test, SimulatedConnection, create_fakecm_account
24import constants as cs
25
26def test(q, bus, mc):
27    # Create an account. We're setting register=True here to verify
28    # that after one successful connection, it'll be removed (fd.o #28118).
29    params = dbus.Dictionary({"account": "someguy@example.com",
30        "password": "secrecy",
31        "register": True}, signature='sv')
32    (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
33
34    call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'Enabled', False)
35    q.expect('dbus-return', method='Set')
36
37    # Enable the account
38    call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'Enabled', True)
39
40    # Set online presence
41    presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy',
42            'Fixing MC bugs'), signature='uss')
43    call_async(q, account.Properties, 'Set', cs.ACCOUNT,
44            'RequestedPresence', presence)
45
46    e = q.expect('dbus-method-call', method='RequestConnection',
47            args=['fakeprotocol', params],
48            destination=tp_name_prefix + '.ConnectionManager.fakecm',
49            path=tp_path_prefix + '/ConnectionManager/fakecm',
50            interface=tp_name_prefix + '.ConnectionManager',
51            handled=False)
52
53    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
54            'myself', has_presence=True)
55
56    q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
57
58    # MC calls GetStatus (maybe) and then Connect
59
60    q.expect('dbus-method-call', method='Connect',
61            path=conn.object_path, handled=True)
62
63    # Connect succeeds
64    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
65
66    q.expect('dbus-method-call',
67             interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
68             method='SetPresence',
69             args=list(presence[1:]),
70             handled=True)
71
72    # Connection falls over for a miscellaneous reason
73    conn.ConnectionError('com.example.My.Network.Is.Full.Of.Eels',
74            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'})
75    conn.StatusChanged(cs.CONN_STATUS_DISCONNECTED,
76            cs.CONN_STATUS_REASON_NETWORK_ERROR)
77
78    # MC reconnects. This time, we expect it to have deleted the 'register'
79    # parameter.
80    del params['register']
81
82    disconnected, connecting, e = q.expect_many(
83            EventPattern('dbus-signal', signal='AccountPropertyChanged',
84                predicate=(lambda e:
85                    e.args[0].get('ConnectionStatus') ==
86                        cs.CONN_STATUS_DISCONNECTED),
87                ),
88            EventPattern('dbus-signal', signal='AccountPropertyChanged',
89                predicate=(lambda e:
90                    e.args[0].get('ConnectionStatus') ==
91                        cs.CONN_STATUS_CONNECTING),
92                ),
93            EventPattern('dbus-method-call', method='RequestConnection',
94                args=['fakeprotocol', params],
95                destination=tp_name_prefix + '.ConnectionManager.fakecm',
96                path=tp_path_prefix + '/ConnectionManager/fakecm',
97                interface=tp_name_prefix + '.ConnectionManager',
98                handled=False),
99            )
100
101    assertEquals('/', disconnected.args[0].get('Connection'))
102    assertEquals('com.example.My.Network.Is.Full.Of.Eels',
103            disconnected.args[0].get('ConnectionError'))
104    assertEquals(
105            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
106            disconnected.args[0].get('ConnectionErrorDetails'))
107    assertEquals(cs.CONN_STATUS_DISCONNECTED,
108        disconnected.args[0].get('ConnectionStatus'))
109    assertEquals(cs.CONN_STATUS_REASON_NETWORK_ERROR,
110        disconnected.args[0].get('ConnectionStatusReason'))
111
112    assertEquals('/', connecting.args[0].get('Connection'))
113    assertEquals('com.example.My.Network.Is.Full.Of.Eels',
114            connecting.args[0].get('ConnectionError'))
115    assertEquals(
116            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
117            connecting.args[0].get('ConnectionErrorDetails'))
118    assertEquals(cs.CONN_STATUS_CONNECTING,
119        connecting.args[0].get('ConnectionStatus'))
120    assertEquals(cs.CONN_STATUS_REASON_REQUESTED,
121        connecting.args[0].get('ConnectionStatusReason'))
122
123    # The object path needs to be different from the first simulated
124    # connection which we made above, because the object isn't removed
125    # from this bus and it's actually hard to do so because it's not
126    # really on a bus, it's on the queue. So let's just change the
127    # object path and it's fine.
128    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'second',
129            'myself', has_presence=True)
130
131    q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
132
133    # MC calls GetStatus (maybe) and then Connect
134
135    connecting, _ = q.expect_many(
136            EventPattern('dbus-signal', signal='AccountPropertyChanged',
137                predicate=(lambda e:
138                    e.args[0].get('ConnectionStatus') ==
139                        cs.CONN_STATUS_CONNECTING),
140                ),
141            EventPattern('dbus-method-call', method='Connect',
142                path=conn.object_path, handled=True),
143            )
144
145    assertEquals(conn.object_path, connecting.args[0].get('Connection'))
146    assertEquals('com.example.My.Network.Is.Full.Of.Eels',
147            connecting.args[0].get('ConnectionError'))
148    assertEquals(
149            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
150            connecting.args[0].get('ConnectionErrorDetails'))
151    assertEquals(cs.CONN_STATUS_CONNECTING,
152        connecting.args[0].get('ConnectionStatus'))
153    assertEquals(cs.CONN_STATUS_REASON_REQUESTED,
154        connecting.args[0].get('ConnectionStatusReason'))
155
156    assertEquals('com.example.My.Network.Is.Full.Of.Eels',
157            account.Properties.Get(cs.ACCOUNT, 'ConnectionError'))
158    assertEquals(
159            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
160            account.Properties.Get(cs.ACCOUNT, 'ConnectionErrorDetails'))
161
162    # Connect succeeds
163    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
164
165    connected, _ = q.expect_many(
166            EventPattern('dbus-signal', signal='AccountPropertyChanged',
167                predicate=(lambda e:
168                    e.args[0].get('ConnectionStatus') ==
169                        cs.CONN_STATUS_CONNECTED),
170                ),
171            EventPattern('dbus-method-call',
172                interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
173                method='SetPresence',
174                args=list(presence[1:]),
175                handled=True),
176            )
177
178    assertEquals(conn.object_path, connected.args[0].get('Connection'))
179    assertEquals('', connected.args[0].get('ConnectionError'))
180    assertEquals({}, connected.args[0].get('ConnectionErrorDetails'))
181    assertEquals(cs.CONN_STATUS_CONNECTED,
182        connected.args[0].get('ConnectionStatus'))
183    assertEquals(cs.CONN_STATUS_REASON_REQUESTED,
184        connected.args[0].get('ConnectionStatusReason'))
185
186    assertEquals('', account.Properties.Get(cs.ACCOUNT, 'ConnectionError'))
187    assertEquals({}, account.Properties.Get(cs.ACCOUNT, 'ConnectionErrorDetails'))
188
189if __name__ == '__main__':
190    exec_test(test, {})
191