You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

140 lines
5.3 KiB

import unittest
from mock import patch
import gevent
import gevent.queue
from steam.core.cm import CMClient
class CMClient_Scenarios(unittest.TestCase):
test_channel_key = b'SESSION KEY LOL'
def setUp(self):
# mock out crypto
patcher = patch('steam.core.crypto.generate_session_key')
self.addCleanup(patcher.stop)
self.gen_skey = patcher.start()
self.gen_skey.return_value = (self.test_channel_key, b'PUBKEY ENCRYPTED SESSION KEY')
patcher = patch('steam.core.crypto.symmetric_encrypt')
self.addCleanup(patcher.stop)
self.s_enc = patcher.start()
self.s_enc.side_effect = lambda m, k: m
patcher = patch('steam.core.crypto.symmetric_encrypt_HMAC')
self.addCleanup(patcher.stop)
self.s_enc_hmac = patcher.start()
self.s_enc_hmac.side_effect = lambda m, k, mac: m
patcher = patch('steam.core.crypto.symmetric_decrypt')
self.addCleanup(patcher.stop)
self.s_dec = patcher.start()
self.s_dec.side_effect = lambda c, k: c
patcher = patch('steam.core.crypto.symmetric_decrypt_HMAC')
self.addCleanup(patcher.stop)
self.s_dec_hmac = patcher.start()
self.s_dec_hmac.side_effect = lambda c, k, mac: c
# mock out TCPConnection
patcher = patch('steam.core.cm.TCPConnection', autospec=True)
self.addCleanup(patcher.stop)
self.conn = patcher.start().return_value
self.conn_in = gevent.queue.Queue()
self.conn.__iter__.return_value = self.conn_in
# mock out CMServerList
patcher = patch('steam.core.cm.CMServerList', autospec=True)
self.addCleanup(patcher.stop)
self.server_list = patcher.start().return_value
self.server_list.__iter__.return_value = [(127001, 20000+i) for i in range(10)]
self.server_list.bootstrap_from_webapi.return_value = False
self.server_list.bootstrap_from_dns.return_value = False
@patch.object(CMClient, 'emit')
@patch.object(CMClient, '_recv_messages')
def test_connect(self, mock_recv, mock_emit):
# setup
self.conn.connect.return_value = True
self.server_list.__len__.return_value = 10
# run
cm = CMClient()
with gevent.Timeout(2, False):
cm.connect(retry=1)
gevent.idle()
# verify
self.conn.connect.assert_called_once_with((127001, 20000))
mock_emit.assert_called_once_with('connected')
mock_recv.assert_called_once_with()
@patch.object(CMClient, 'emit')
@patch.object(CMClient, '_recv_messages')
def test_connect_auto_discovery_failing(self, mock_recv, mock_emit):
# setup
self.conn.connect.return_value = True
self.server_list.__len__.return_value = 0
# run
cm = CMClient()
with gevent.Timeout(3, False):
cm.connect(retry=1)
gevent.idle()
# verify
self.server_list.bootstrap_from_webapi.assert_called_once_with()
self.server_list.bootstrap_from_dns.assert_called_once_with()
self.conn.connect.assert_not_called()
@patch.object(CMClient, 'emit')
@patch.object(CMClient, '_recv_messages')
def test_connect_auto_discovery_success(self, mock_recv, mock_emit):
# setup
self.conn.connect.return_value = True
self.server_list.__len__.return_value = 0
def fake_servers(*args, **kwargs):
self.server_list.__len__.return_value = 10
return True
self.server_list.bootstrap_from_webapi.side_effect = fake_servers
# run
cm = CMClient()
with gevent.Timeout(3, False):
cm.connect(retry=1)
gevent.idle()
# verify
self.server_list.bootstrap_from_webapi.assert_called_once_with()
self.server_list.bootstrap_from_dns.assert_not_called()
self.conn.connect.assert_called_once_with((127001, 20000))
mock_emit.assert_called_once_with('connected')
mock_recv.assert_called_once_with()
def test_channel_encrypt_sequence(self):
# setup
self.conn.connect.return_value = True
# run ------------
cm = CMClient()
cm.connected = True
gevent.spawn(cm._recv_messages)
# recieve ChannelEncryptRequest
self.conn_in.put(b'\x17\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\x01\x00\x00\x00')
gevent.idle(); gevent.idle(); gevent.idle(); gevent.idle()
self.conn.put_message.assert_called_once_with(b'\x18\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\x80\x00\x00\x00PUBKEY ENCRYPTED SESSION KEY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h-\xc4@\x00\x00\x00\x00')
# recieve ChannelEncryptResult (OK)
self.conn_in.put(b'\x19\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00')
cm.wait_event('channel_secured', timeout=2, raises=True)