1# vim: set fileencoding=utf-8 : 2# Copyright © 2011 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 20import dbus.service 21 22from servicetest import ( 23 EventPattern, call_async, sync_dbus, assertEquals, 24) 25from mctest import ( 26 exec_test, create_fakecm_account, expect_fakecm_connection, 27 SimulatedConnection, 28) 29import constants as cs 30 31import config 32 33def sync_connectivity_state(mc): 34 # We cannot simply use sync_dbus here, because nm-glib reports property 35 # changes in an idle (presumably to batch them all together). This is fine 36 # and all that, but means we have to find a way to make sure MC has flushed 37 # its idle queue to avoid this test being racy. (This isn't just 38 # theoretical: this test failed about once per five runs when it used sync_dbus.) 39 # 40 # The test-specific version of MC implements the 'BillyIdle' method, which 41 # returns from a low-priority idle. 42 mc.BillyIdle(dbus_interface='org.freedesktop.Telepathy.MissionControl5.RegressionTests') 43 44def test(q, bus, mc): 45 params = dbus.Dictionary( 46 {"account": "yum yum network manager", 47 "password": "boo boo connman (although your API *is* simpler)", 48 }, signature='sv') 49 (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params) 50 51 # While we're not connected to the internet, RequestConnection should not 52 # be called. 53 request_connection_event = [ 54 EventPattern('dbus-method-call', method='RequestConnection'), 55 ] 56 q.forbid_events(request_connection_event) 57 58 account.Properties.Set(cs.ACCOUNT, 'RequestedPresence', 59 (dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy', 'hlaghalgh')) 60 61 # Turn the account on, re-request an online presence, and even tell it to 62 # connect automatically, to check that none of these make it sign in. 63 call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'Enabled', True) 64 q.expect('dbus-return', method='Set') 65 requested_presence = (dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy', 'gtfo') 66 call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'RequestedPresence', 67 requested_presence) 68 q.expect('dbus-return', method='Set') 69 call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'ConnectAutomatically', 70 True) 71 q.expect('dbus-return', method='Set') 72 # (but actually let's turn ConnectAutomatically off: we want to check that 73 # MC continues to try to apply RequestedPresence if the network connection 74 # goes away and comes back again, regardless of this setting) 75 call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'ConnectAutomatically', 76 False) 77 q.expect('dbus-return', method='Set') 78 79 sync_dbus(bus, q, mc) 80 q.unforbid_events(request_connection_event) 81 82 # Okay, I'm satisfied. Turn the network on. 83 mc.connectivity.go_online() 84 85 expect_fakecm_connection(q, bus, mc, account, params, has_presence=True, 86 expect_before_connect=[ 87 EventPattern('dbus-method-call', method='SetPresence', 88 args=list(requested_presence[1:])), 89 ]) 90 91 if config.HAVE_NM: 92 # If NetworkManager tells us that it is going to disconnect soon, 93 # the connection should be banished. GNetworkMonitor can't tell us 94 # that; either it's online or it isn't. 95 mc.connectivity.go_indeterminate() 96 q.expect('dbus-method-call', method='Disconnect') 97 98 mc.connectivity.go_offline() 99 sync_connectivity_state(mc) 100 101 # When we turn the network back on, MC should try to sign us back on. 102 # In the process, our RequestedPresence should not have been 103 # trampled on, as below. 104 mc.connectivity.go_online() 105 expect_fakecm_connection(q, bus, mc, account, params, 106 has_presence=True, 107 expect_before_connect=[ 108 EventPattern('dbus-method-call', method='SetPresence', 109 args=list(requested_presence[1:])), 110 ]) 111 112 assertEquals(requested_presence, 113 account.Properties.Get(cs.ACCOUNT, 'RequestedPresence')) 114 115 # If we turn the network off, the connection should be banished. 116 mc.connectivity.go_offline() 117 q.expect('dbus-method-call', method='Disconnect') 118 119 # When we turn the network back on, MC should try to sign us back on. 120 mc.connectivity.go_online() 121 e = q.expect('dbus-method-call', method='RequestConnection') 122 123 # In the process, our RequestedPresence should not have been trampled on. 124 # (Historically, MC would replace it with the AutomaticPresence, but that 125 # behaviour was unexpected: if the user explicitly set a status or message, 126 # why should the network connection cutting out and coming back up cause 127 # that to be lost?) 128 assertEquals(requested_presence, 129 account.Properties.Get(cs.ACCOUNT, 'RequestedPresence')) 130 131 # But if we get disconnected before RequestConnection returns, MC should 132 # clean up the new connection when it does, rather than trying to sign it 133 # in. 134 connect_event = [ EventPattern('dbus-method-call', method='Connect'), ] 135 q.forbid_events(connect_event) 136 137 mc.connectivity.go_offline() 138 # Make sure that MC has noticed that the network connection has gone away. 139 sync_connectivity_state(mc) 140 141 conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 142 account.object_path.split('/')[-1], 'myself') 143 q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so') 144 145 q.expect('dbus-method-call', method='Disconnect') 146 147 # So now the user gives up and sets their RequestedPresence to offline. 148 # Because this account does not ConnectAutomatically, if the network 149 # connection comes back up the account should not be brought back online. 150 q.forbid_events(request_connection_event) 151 account.Properties.Set(cs.ACCOUNT, 'RequestedPresence', 152 (dbus.UInt32(cs.PRESENCE_TYPE_OFFLINE), 'offline', '')) 153 mc.connectivity.go_online() 154 # Make sure MC has noticed that the network connection has come back. 155 sync_connectivity_state(mc) 156 157if __name__ == '__main__': 158 exec_test(test, initially_online=False) 159