Skip to content

Commit

Permalink
Merge branch 'martin-volf-py3_1.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
Leonidas Poulopoulos committed Jul 5, 2016
2 parents 4ae3ecf + 9e485ef commit 5b4da19
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 35 deletions.
37 changes: 22 additions & 15 deletions ncclient/transport/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ def _colonify(fp):
finga += ":" + fp[idx:idx+2]
return finga

if sys.version_info.major < 3:
def textify(buf):
return buf
else:
def textify(buf):
return buf.decode('UTF-8')

class SSHSession(Session):

"Implements a :rfc:`4742` NETCONF session over SSH."
Expand Down Expand Up @@ -173,20 +180,20 @@ def _parse11(self):
if not x:
logger.debug('No more data to read')
# Store the current chunk to the message list
chunk = ''.join(chunk_list)
message_list.append(chunk)
chunk = b''.join(chunk_list)
message_list.append(textify(chunk))
break # done reading
logger.debug('x: %s', x)
if state == idle:
if x == '\n':
if x == b'\n':
state = instart
inendpos = 1
else:
logger.debug('%s (%s: expect newline)'%(pre, state))
raise Exception
elif state == instart:
if inendpos == 1:
if x == '#':
if x == b'#':
inendpos += 1
else:
logger.debug('%s (%s: expect "#")'%(pre, state))
Expand All @@ -202,10 +209,10 @@ def _parse11(self):
if inendpos == MAX_STARTCHUNK_SIZE:
logger.debug('%s (%s: no. too long)'%(pre, state))
raise Exception
elif x == '\n':
num = ''.join(num_list)
elif x == b'\n':
num = b''.join(num_list)
num_list = [] # Reset num_list
try: num = long(num)
try: num = int(num)
except:
logger.debug('%s (%s: invalid no.)'%(pre, state))
raise Exception
Expand All @@ -219,7 +226,7 @@ def _parse11(self):
inendpos += 1 # > 3 now #
num_list.append(x)
else:
log.debug('%s (%s: expect digit)'%(pre, state))
logger.debug('%s (%s: expect digit)'%(pre, state))
raise Exception
elif state == inmsg:
chunk_list.append(x)
Expand All @@ -228,24 +235,24 @@ def _parse11(self):
if chunkleft == 0:
inendpos = 0
state = inbetween
chunk = ''.join(chunk_list)
message_list.append(chunk)
chunk = b''.join(chunk_list)
message_list.append(textify(chunk))
chunk_list = [] # Reset chunk_list
logger.debug('parsed new chunk: %s'%(chunk))
elif state == inbetween:
if inendpos == 0:
if x == '\n': inendpos += 1
if x == b'\n': inendpos += 1
else:
logger.debug('%s (%s: expect newline)'%(pre, state))
raise Exception
elif inendpos == 1:
if x == '#': inendpos += 1
if x == b'#': inendpos += 1
else:
logger.debug('%s (%s: expect "#")'%(pre, state))
raise Exception
else:
inendpos += 1 # == 3 now #
if x == '#':
if x == b'#':
state = inend
elif x.isdigit():
# More trunks
Expand All @@ -257,14 +264,14 @@ def _parse11(self):
raise Exception
elif state == inend:
if inendpos == 3:
if x == '\n':
if x == b'\n':
inendpos = 0
state = idle
logger.debug('dispatching message')
self._dispatch_message(''.join(message_list))
# reset
rest = buf.read()
buf = StringIO()
buf = BytesIO()
buf.write(rest)
buf.seek(0)
message_list = []
Expand Down
52 changes: 32 additions & 20 deletions test/unit/transport/test_ssh.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import unittest
from mock import patch
from ncclient.transport.ssh import *
from ncclient.transport.ssh import SSHSession
from ncclient.transport import AuthenticationError, SessionCloseError
import paramiko
from ncclient.devices.junos import JunosDeviceHandler
import sys

rpc_reply = """<rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.1X46/junos" attrib1 = "test">
reply_data = """<rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.1X46/junos" attrib1 = "test">
<software-information>
<host-name>R1</host-name>
<product-model>firefly-perimeter</product-model>
Expand All @@ -17,34 +19,44 @@
<cli>
<banner></banner>
</cli>
</rpc-reply>
]]>]]>
<rpc-reply>
</rpc-reply>"""

reply_ok = """<rpc-reply>
<ok/>
<rpc-reply/>"""

rpc_reply = reply_data + "\n]]>]]>\n" + reply_ok

reply_ok_chunk = "\n#%d\n%s\n##\n" % (len(reply_ok), reply_ok)

rpc_reply11 = "\n#%d\n%s\n#%d\n%s\n##\n%s" % (
30, reply_data[:30], len(reply_data[30:]), reply_data[30:],
reply_ok_chunk)


class TestSSH(unittest.TestCase):

@patch('ncclient.transport.ssh.Session._dispatch_message')
def test_parse(self, mock_dispatch):
def _test_parsemethod(self, mock_dispatch, parsemethod, reply, ok_chunk):
device_handler = JunosDeviceHandler({'name': 'junos'})
obj = SSHSession(device_handler)
if sys.version >= "3.0":
b = bytes(rpc_reply, "utf-8")
obj._buffer.write(b)
obj._parse()
dispatched_str = (b[0:509]).strip().decode("utf-8")
call = mock_dispatch.call_args_list[0][0][0]
self.assertEqual(call, dispatched_str)
self.assertEqual(obj._buffer.getvalue(), b[515:])
obj._buffer.write(bytes(reply, "utf-8"))
remainder = bytes(ok_chunk, "utf-8")
else:
obj._buffer.write(rpc_reply)
obj._parse()
dispatched_str = (rpc_reply[0:509]).strip()
call = mock_dispatch.call_args_list[0][0][0]
self.assertEqual(call, dispatched_str)
self.assertEqual(obj._buffer.getvalue(), rpc_reply[515:])
obj._buffer.write(reply)
remainder = ok_chunk
parsemethod(obj)
call = mock_dispatch.call_args_list[0][0][0]
self.assertEqual(call, reply_data)
self.assertEqual(obj._buffer.getvalue(), remainder)

@patch('ncclient.transport.ssh.Session._dispatch_message')
def test_parse(self, mock_dispatch):
self._test_parsemethod(mock_dispatch, SSHSession._parse, rpc_reply, "\n" + reply_ok)

@patch('ncclient.transport.ssh.Session._dispatch_message')
def test_parse11(self, mock_dispatch):
self._test_parsemethod(mock_dispatch, SSHSession._parse11, rpc_reply11, reply_ok_chunk)

@patch('paramiko.transport.Transport.auth_publickey')
@patch('paramiko.agent.AgentSSH.get_keys')
Expand Down

0 comments on commit 5b4da19

Please sign in to comment.