1# vim: set fileencoding=utf-8 : 2# Copyright © 2009 Nokia Corporation 3# Copyright © 2009–2011 Collabora Ltd. 4# 5# This library is free software; you can redistribute it and/or 6# modify it under the terms of the GNU Lesser General Public 7# License as published by the Free Software Foundation; either 8# version 2.1 of the License, or (at your option) any later version. 9# 10# This library is distributed in the hope that it will be useful, but 11# WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13# Lesser General Public License for more details. 14# 15# You should have received a copy of the GNU Lesser General Public 16# License along with this library; if not, write to the Free Software 17# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18# 02110-1301 USA 19 20import os 21import time 22 23import dbus 24import dbus.service 25 26from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \ 27 call_async, assertEquals, assertSameSets 28from mctest import exec_test, SimulatedConnection, create_fakecm_account,\ 29 SimulatedChannel 30import constants as cs 31 32def test(q, bus, mc, **kwargs): 33 cm_name_ref = dbus.service.BusName( 34 tp_name_prefix + '.ConnectionManager.fakecm', bus=bus) 35 36 # Create an account 37 params = dbus.Dictionary( 38 {"account": "someguy@example.com", 39 "password": "secrecy", 40 "nickname": "albinoblacksheep", 41 }, signature='sv') 42 (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params) 43 44 # Enable the account 45 account.Set(cs.ACCOUNT, 'Enabled', True, 46 dbus_interface=cs.PROPERTIES_IFACE) 47 q.expect('dbus-signal', 48 path=account.object_path, 49 signal='AccountPropertyChanged', 50 interface=cs.ACCOUNT) 51 52 # Go online 53 requested_presence = dbus.Struct((dbus.UInt32(2), dbus.String('brb'), 54 dbus.String('Be back soon!'))) 55 account.Set(cs.ACCOUNT, 56 'RequestedPresence', requested_presence, 57 dbus_interface=cs.PROPERTIES_IFACE) 58 59 e = q.expect('dbus-method-call', method='RequestConnection', 60 args=['fakeprotocol', params], 61 destination=tp_name_prefix + '.ConnectionManager.fakecm', 62 path=tp_path_prefix + '/ConnectionManager/fakecm', 63 interface=tp_name_prefix + '.ConnectionManager', 64 handled=False) 65 66 conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_', 67 'myself') 68 69 q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so') 70 71 # MC does some setup, including fetching the list of Channels 72 73 q.expect_many( 74 EventPattern('dbus-method-call', 75 interface=cs.PROPERTIES_IFACE, method='GetAll', 76 args=[cs.CONN_IFACE_REQUESTS], 77 path=conn.object_path, handled=True), 78 ) 79 80 # MC calls GetStatus (maybe) and then Connect 81 82 q.expect('dbus-method-call', method='Connect', 83 path=conn.object_path, handled=True) 84 85 # Connect succeeds 86 conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE) 87 88 # Assert that the NormalizedName is harvested from the Connection at some 89 # point 90 while 1: 91 e = q.expect('dbus-signal', 92 interface=cs.ACCOUNT, signal='AccountPropertyChanged', 93 path=account.object_path) 94 if 'NormalizedName' in e.args[0]: 95 assert e.args[0]['NormalizedName'] == 'myself', e.args 96 break 97 98 # Check the requested presence is online 99 properties = account.GetAll(cs.ACCOUNT, 100 dbus_interface=cs.PROPERTIES_IFACE) 101 assert properties is not None 102 assert properties.get('RequestedPresence') == requested_presence, \ 103 properties.get('RequestedPresence') 104 105 # Set some parameters. They include setting account to \\, as a regression 106 # test for part of fd.o #28557. 107 call_async(q, account, 'UpdateParameters', 108 { 109 'account': r'\\', 110 'secret-mushroom': '/Amanita muscaria/', 111 'snakes': dbus.UInt32(42), 112 'com.example.Badgerable.Badgered': True, 113 }, 114 [], 115 dbus_interface=cs.ACCOUNT) 116 117 set_call, ret, _ = q.expect_many( 118 EventPattern('dbus-method-call', 119 path=conn.object_path, 120 interface=cs.PROPERTIES_IFACE, method='Set', 121 args=['com.example.Badgerable', 'Badgered', True], 122 handled=False), 123 EventPattern('dbus-return', 124 method='UpdateParameters'), 125 EventPattern('dbus-signal', 126 path=account.object_path, 127 interface=cs.ACCOUNT, signal='AccountPropertyChanged', 128 args=[{'Parameters': { 129 'account': r'\\', 130 'com.example.Badgerable.Badgered': True, 131 'password': 'secrecy', 132 'nickname': 'albinoblacksheep', 133 'secret-mushroom': '/Amanita muscaria/', 134 'snakes': 42, 135 }}]), 136 ) 137 138 # the D-Bus property should be set instantly; the others will take effect 139 # on reconnection 140 not_yet = ret.value[0] 141 not_yet.sort() 142 assert not_yet == ['account', 'secret-mushroom', 'snakes'], not_yet 143 144 # Try to update 'account' to a value of the wrong type; MC should complain, 145 # without having changed the value of 'snakes'. 146 call_async(q, account, 'UpdateParameters', 147 { 'account': dbus.UInt32(39), 148 'snakes': dbus.UInt32(39), 149 }, 150 [], 151 dbus_interface=cs.ACCOUNT) 152 q.expect('dbus-error', name=cs.INVALID_ARGUMENT) 153 154 props = account.Get(cs.ACCOUNT, 'Parameters', 155 dbus_interface=cs.PROPERTIES_IFACE) 156 assertEquals(42, props['snakes']) 157 158 # Try to update a parameter that doesn't exist; again, 'snakes' should not 159 # be changed. 160 call_async(q, account, 'UpdateParameters', 161 { 'accccccount': dbus.UInt32(39), 162 'snakes': dbus.UInt32(39), 163 }, 164 [], 165 dbus_interface=cs.ACCOUNT) 166 q.expect('dbus-error', name=cs.INVALID_ARGUMENT) 167 168 props = account.Get(cs.ACCOUNT, 'Parameters', 169 dbus_interface=cs.PROPERTIES_IFACE) 170 assertEquals(42, props['snakes']) 171 172 # Unset some parameters, including a parameter which doesn't exist at all. 173 # The spec says that “If the given parameters […] do not exist at all, the 174 # account manager MUST accept this without error.” 175 call_async(q, account, 'UpdateParameters', 176 {}, 177 ['nickname', 'com.example.Badgerable.Badgered', 'froufrou'], 178 dbus_interface=cs.ACCOUNT) 179 180 ret, _, _ = q.expect_many( 181 EventPattern('dbus-return', 182 method='UpdateParameters'), 183 EventPattern('dbus-signal', 184 path=account.object_path, 185 interface=cs.ACCOUNT, signal='AccountPropertyChanged', 186 args=[{'Parameters': { 187 'account': r'\\', 188 'password': 'secrecy', 189 'secret-mushroom': '/Amanita muscaria/', 190 'snakes': 42, 191 }}]), 192 EventPattern('dbus-method-call', 193 path=conn.object_path, 194 interface=cs.PROPERTIES_IFACE, method='Set', 195 args=['com.example.Badgerable', 'Badgered', False], 196 handled=False), 197 ) 198 199 # Because com.example.Badgerable.Badgered has a default value (namely 200 # False), unsetting that parameter should cause the default value to be set 201 # on the CM. 202 not_yet = ret.value[0] 203 assertEquals(['nickname'], not_yet) 204 205 # Set contrived-example to its default value; since there's been no 206 # practical change, we shouldn't be told we need to reconnect to apply it. 207 call_async(q, account, 'UpdateParameters', 208 { 'contrived-example': dbus.UInt32(5) }, []) 209 ret, _ = q.expect_many( 210 EventPattern('dbus-return', method='UpdateParameters'), 211 EventPattern('dbus-signal', 212 path=account.object_path, 213 interface=cs.ACCOUNT, signal='AccountPropertyChanged', 214 args=[{'Parameters': { 215 'account': r'\\', 216 'password': 'secrecy', 217 'secret-mushroom': '/Amanita muscaria/', 218 'snakes': 42, 219 "contrived-example": 5, 220 }}]), 221 ) 222 not_yet = ret.value[0] 223 assertEquals([], not_yet) 224 225 # Unset contrived-example; again, MC should be smart enough to know we 226 # don't need to do anything. 227 call_async(q, account, 'UpdateParameters', {}, ['contrived-example']) 228 ret, _ = q.expect_many( 229 EventPattern('dbus-return', method='UpdateParameters'), 230 EventPattern('dbus-signal', 231 path=account.object_path, 232 interface=cs.ACCOUNT, signal='AccountPropertyChanged', 233 args=[{'Parameters': { 234 'account': r'\\', 235 'password': 'secrecy', 236 'secret-mushroom': '/Amanita muscaria/', 237 'snakes': 42, 238 }}]), 239 ) 240 not_yet = ret.value[0] 241 assertEquals([], not_yet) 242 243 # Unset contrived-example again; the spec decrees that “If the given 244 # parameters were not, in fact, stored, […] the account manager MUST accept 245 # this without error.” 246 call_async(q, account, 'UpdateParameters', {}, ['contrived-example']) 247 ret = q.expect('dbus-return', method='UpdateParameters') 248 not_yet = ret.value[0] 249 assertEquals([], not_yet) 250 251 cache_dir = os.environ['XDG_CACHE_HOME'] 252 253 # Now that we're using GVariant-based storage, the backslashes aren't 254 # escaped. 255 assertEquals(r'\\', 256 kwargs['fake_accounts_service'].accounts 257 [account.object_path[len(cs.ACCOUNT_PATH_PREFIX):]] 258 [2] # parameters of known type 259 ['account']) 260 assertEquals(None, 261 kwargs['fake_accounts_service'].accounts 262 [account.object_path[len(cs.ACCOUNT_PATH_PREFIX):]] 263 [3] # parameters of unknown type 264 .get('account', None)) 265 266if __name__ == '__main__': 267 exec_test(test, {}, pass_kwargs=True) 268