def createVirtualDevice(self): self.banner = 'Welcome to %s!\n' % self.hostname self.prompt = self.hostname + '> ' self.device = VirtualDevice(self.hostname, echo=True) ls_response = '-rw-r--r-- 1 sab nmc 1628 Aug 18 10:02 file' self.device.add_command('ls', ls_response) self.device.add_command('df', 'foobar') self.device.add_command('exit', '') self.device.add_command('this-command-causes-an-error', '\ncommand not found')
def __init__(self, device=None, **kwargs): """ @note: Also supports all keyword arguments that L{Protocol} supports. @keyword device: The L{Exscript.emulators.VirtualDevice} with which to communicate. """ Protocol.__init__(self, **kwargs) self.device = device self.init_done = False self.cancel = False self.response = None if not self.device: self.device = VirtualDevice('dummy', strict=False)
def __init__(self, device=None, **kwargs): """ .. HINT:: Also supports all keyword arguments that :class:`Protocol` supports. :keyword device: The :class:`Exscript.emulators.VirtualDevice` with which to communicate. """ Protocol.__init__(self, **kwargs) self.device = device self.init_done = False self.cancel = False self.response = None if not self.device: self.device = VirtualDevice('dummy', strict=False)
def __init__(self, hostname, echo=True, login_type=VirtualDevice.LOGIN_TYPE_BOTH, strict=True, banner=None): thebanner = iosbanner % (hostname, hostname, hostname) VirtualDevice.__init__(self, hostname, echo=echo, login_type=login_type, strict=strict, banner=banner or thebanner) self.user_prompt = 'Username: '******'Password: '******'#' for command, handler in commands: self.add_command(command, handler)
def __init__(self, hostname, echo = True, login_type = VirtualDevice.LOGIN_TYPE_BOTH, strict = True, banner = None): thebanner = iosbanner % (hostname, hostname, hostname) VirtualDevice.__init__(self, hostname, echo = echo, login_type = login_type, strict = strict, banner = banner or thebanner) self.user_prompt = 'Username: '******'Password: '******'#' for command, handler in commands: self.add_command(command, handler)
def createVirtualDevice(self): self.banner = 'Welcome to %s!\n' % self.hostname self.prompt = self.hostname + '> ' self.device = VirtualDevice(self.hostname, echo = True) ls_response = '-rw-r--r-- 1 sab nmc 1628 Aug 18 10:02 file' self.device.add_command('ls', ls_response) self.device.add_command('df', 'foobar') self.device.add_command('exit', '') self.device.add_command('this-command-causes-an-error', '\ncommand not found')
def __init__(self, device = None, **kwargs): """ @note: Also supports all keyword arguments that L{Protocol} supports. @keyword device: The L{Exscript.emulators.VirtualDevice} with which to communicate. """ Protocol.__init__(self, **kwargs) self.device = device self.init_done = False self.cancel = False self.response = None if not self.device: self.device = VirtualDevice('dummy', strict = False)
class ProtocolTest(unittest.TestCase): """ Since protocols.Protocol is abstract, this test is only a base class for other protocols. It does not do anything fancy on its own. """ CORRELATE = Protocol def setUp(self): self.hostname = '127.0.0.1' self.port = 1236 self.user = '******' self.password = '******' self.account = Account(self.user, password=self.password) self.daemon = None self.createVirtualDevice() self.createDaemon() if self.daemon is not None: self.daemon.start() time.sleep(.2) self.createProtocol() def tearDown(self): if self.protocol.__class__ != Protocol: self.protocol.close(True) if self.daemon is not None: self.daemon.exit() self.daemon.join() def createVirtualDevice(self): self.banner = 'Welcome to %s!\n' % self.hostname self.prompt = self.hostname + '> ' self.device = VirtualDevice(self.hostname, echo=True) ls_response = '-rw-r--r-- 1 sab nmc 1628 Aug 18 10:02 file' self.device.add_command('ls', ls_response) self.device.add_command('df', 'foobar') self.device.add_command('exit', '') self.device.add_command('this-command-causes-an-error', '\ncommand not found') def createDaemon(self): pass def createProtocol(self): self.protocol = Protocol(timeout=1) def doConnect(self): self.protocol.connect(self.hostname, self.port) def doLogin(self, flush=True): self.doConnect() self.protocol.login(self.account, flush=flush) def doProtocolAuthenticate(self, flush=True): self.doConnect() self.protocol.protocol_authenticate(self.account) def doAppAuthenticate(self, flush=True): self.protocol.app_authenticate(self.account, flush) def doAppAuthorize(self, flush=True): self.protocol.app_authorize(self.account, flush) def _trymatch(self, prompts, string): for regex in prompts: match = regex.search(string) if match: return match return None def testPrompts(self): prompts = ('[sam123@home ~]$', '[MyHost-A1]', '<MyHost-A1>', 'sam@knip:~/Code/exscript$', 'sam@MyHost-X123>', 'sam@MyHost-X123#', 'MyHost-ABC-CDE123>', 'MyHost-A1#', 'S-ABC#', '0123456-1-1-abc#', '0123456-1-1-a>', 'MyHost-A1(config)#', 'MyHost-A1(config)>', 'RP/0/RP0/CPU0:A-BC2#', 'FA/0/1/2/3>', 'FA/0/1/2/3(config)>', 'FA/0/1/2/3(config)#', 'ec-c3-c27s99(su)->', 'foobar:0>', '[email protected]:/# ', '[email protected]:/% ') notprompts = ('one two', ' [MyHost-A1]', '[edit]\r', '[edit]\n', '[edit foo]\r', '[edit foo]\n', '[edit foo]\r\n', '[edit one two]') prompt_re = self.protocol.get_prompt() for prompt in prompts: if not self._trymatch(prompt_re, '\n' + prompt): self.fail('Prompt %s does not match exactly.' % prompt) if not self._trymatch(prompt_re, 'this is a test\r\n' + prompt): self.fail('Prompt %s does not match.' % prompt) if self._trymatch(prompt_re, 'some text ' + prompt): self.fail('Prompt %s matches incorrectly.' % repr(prompt)) for prompt in notprompts: if self._trymatch(prompt_re, prompt): self.fail('Prompt %s matches incorrecly.' % repr(prompt)) if self._trymatch(prompt_re, prompt + ' '): self.fail('Prompt %s matches incorrecly.' % repr(prompt)) if self._trymatch(prompt_re, '\n' + prompt): self.fail('Prompt %s matches incorrecly.' % repr(prompt)) def testConstructor(self): self.assertIsInstance(self.protocol, Protocol) def testCopy(self): self.assertEqual(self.protocol, self.protocol.__copy__()) def testDeepcopy(self): self.assertEqual(self.protocol, self.protocol.__deepcopy__({})) def testIsDummy(self): self.assertEqual(self.protocol.is_dummy(), False) def testSetDriver(self): self.assertTrue(self.protocol.get_driver() is not None) self.assertEqual(self.protocol.get_driver().name, 'generic') self.protocol.set_driver() self.assertTrue(self.protocol.get_driver() is not None) self.assertEqual(self.protocol.get_driver().name, 'generic') self.protocol.set_driver('ios') self.assertTrue(self.protocol.get_driver() is not None) self.assertEqual(self.protocol.get_driver().name, 'ios') self.protocol.set_driver() self.assertTrue(self.protocol.get_driver() is not None) self.assertEqual(self.protocol.get_driver().name, 'generic') def testGetDriver(self): pass # Already tested in testSetDriver() def testAutoinit(self): self.protocol.autoinit() def _test_prompt_setter(self, getter, setter): initial_regex = getter() self.assertIsInstance(initial_regex, list) self.assertTrue(hasattr(initial_regex[0], 'groups')) my_re = re.compile(r'% username') setter(my_re) regex = getter() self.assertIsInstance(regex, list) self.assertTrue(hasattr(regex[0], 'groups')) self.assertEqual(regex[0], my_re) setter() regex = getter() self.assertEqual(regex, initial_regex) def testSetUsernamePrompt(self): self._test_prompt_setter(self.protocol.get_username_prompt, self.protocol.set_username_prompt) def testGetUsernamePrompt(self): pass # Already tested in testSetUsernamePrompt() def testSetPasswordPrompt(self): self._test_prompt_setter(self.protocol.get_password_prompt, self.protocol.set_password_prompt) def testGetPasswordPrompt(self): pass # Already tested in testSetPasswordPrompt() def testSetPrompt(self): self._test_prompt_setter(self.protocol.get_prompt, self.protocol.set_prompt) def testGetPrompt(self): pass # Already tested in testSetPrompt() def testSetErrorPrompt(self): self._test_prompt_setter(self.protocol.get_error_prompt, self.protocol.set_error_prompt) def testGetErrorPrompt(self): pass # Already tested in testSetErrorPrompt() def testSetLoginErrorPrompt(self): self._test_prompt_setter(self.protocol.get_login_error_prompt, self.protocol.set_login_error_prompt) def testGetLoginErrorPrompt(self): pass # Already tested in testSetLoginErrorPrompt() def testSetConnectTimeout(self): self.assertEqual(self.protocol.get_connect_timeout(), 30) self.protocol.set_connect_timeout(60) self.assertEqual(self.protocol.get_connect_timeout(), 60) def testGetConnectTimeout(self): pass # Already tested in testSetConnectTimeout() def testSetTimeout(self): self.assertEqual(self.protocol.get_timeout(), 1) self.protocol.set_timeout(60) self.assertEqual(self.protocol.get_timeout(), 60) def testGetTimeout(self): pass # Already tested in testSetTimeout() def testConnect(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.connect) return self.assertEqual(self.protocol.response, None) self.doConnect() self.assertEqual(self.protocol.response, None) self.assertEqual(self.protocol.get_host(), self.hostname) def testLogin(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.login, self.account) return # Password login. self.doLogin(flush=False) self.assertTrue(self.protocol.response is not None) self.assertTrue(len(self.protocol.response) > 0) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) # Key login. self.tearDown() self.setUp() key = PrivateKey.from_file('foo', keytype='rsa') account = Account(self.user, self.password, key=key) self.doConnect() self.assertFalse(self.protocol.is_protocol_authenticated()) self.assertFalse(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) self.protocol.login(account, flush=False) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) def testAuthenticate(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.authenticate, self.account) return self.doConnect() # Password login. self.assertFalse(self.protocol.is_protocol_authenticated()) self.assertFalse(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) self.protocol.authenticate(self.account, flush=False) self.assertTrue(self.protocol.response is not None) self.assertTrue(len(self.protocol.response) > 0) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) # Key login. self.tearDown() self.setUp() key = PrivateKey.from_file('foo', keytype='rsa') account = Account(self.user, self.password, key=key) self.doConnect() self.assertFalse(self.protocol.is_protocol_authenticated()) self.assertFalse(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) self.protocol.authenticate(account, flush=False) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) def testProtocolAuthenticate(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.protocol.protocol_authenticate(self.account) return # There is no guarantee that the device provided any response # during protocol level authentification. self.doProtocolAuthenticate(flush=False) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertFalse(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) def testIsProtocolAuthenticated(self): pass # See testProtocolAuthenticate() def testAppAuthenticate(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.app_authenticate, self.account) return self.testProtocolAuthenticate() self.doAppAuthenticate(flush=False) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) def testIsAppAuthenticated(self): pass # See testAppAuthenticate() def testAppAuthorize(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.app_authorize) return self.doProtocolAuthenticate(flush=False) self.doAppAuthenticate(flush=False) response = self.protocol.response # Authorize should see that a prompt is still in the buffer, # and do nothing. self.doAppAuthorize(flush=False) self.assertEqual(self.protocol.response, response) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) self.doAppAuthorize(flush=True) self.assertEqual(self.protocol.response, response) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) def testAppAuthorize2(self): # Same test as above, but using flush=True all the way. # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.app_authorize) return self.doProtocolAuthenticate(flush=True) self.doAppAuthenticate(flush=True) response = self.protocol.response # At this point app_authorize should fail because the buffer is # empty due to flush=True above. In other words, app_authorize # will wait for a prompt until a timeout happens. self.assertRaises(TimeoutException, self.doAppAuthorize) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) def testAutoAppAuthorize(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(TypeError, self.protocol.auto_app_authorize) return self.testAppAuthenticate() response = self.protocol.response # This should do nothing, because our test host does not # support AAA. Can't think of a way to test against a # device using AAA. self.protocol.auto_app_authorize(self.account, flush=False) self.assertEqual(self.protocol.response, response) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) self.protocol.auto_app_authorize(self.account, flush=True) self.assertEqual(self.protocol.response, response) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) def testIsAppAuthorized(self): pass # see testAppAuthorize() def testSend(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.send, 'ls') return self.doLogin() self.protocol.execute('ls') self.protocol.send('df\r') self.assertTrue(self.protocol.response is not None) self.assertTrue(self.protocol.response.startswith('ls')) self.protocol.send('exit\r') self.assertTrue(self.protocol.response is not None) self.assertTrue(self.protocol.response.startswith('ls')) def testExecute(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.execute, 'ls') return self.doLogin() self.protocol.execute('ls') self.assertTrue(self.protocol.response is not None) self.assertTrue(self.protocol.response.startswith('ls')) # Make sure that we raise an error if the device responds # with something that matches any of the error prompts. self.protocol.set_error_prompt('.') self.assertRaises(InvalidCommandException, self.protocol.execute, 'this-command-causes-an-error') def testWaitfor(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.waitfor, 'ls') return self.doLogin() oldresponse = self.protocol.response self.protocol.send('ls\r') self.assertEqual(oldresponse, self.protocol.response) self.protocol.waitfor(re.compile(r'[\r\n]')) self.assertNotEqual(oldresponse, self.protocol.response) oldresponse = self.protocol.response self.protocol.waitfor(re.compile(r'[\r\n]')) self.assertEqual(oldresponse, self.protocol.response) def testExpect(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.expect, 'ls') return self.doLogin() oldresponse = self.protocol.response self.protocol.send('ls\r') self.assertEqual(oldresponse, self.protocol.response) self.protocol.expect(re.compile(r'[\r\n]')) self.assertNotEqual(oldresponse, self.protocol.response) def testExpectPrompt(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.expect, 'ls') return self.doLogin() oldresponse = self.protocol.response self.protocol.send('ls\r') self.assertEqual(oldresponse, self.protocol.response) self.protocol.expect_prompt() self.assertNotEqual(oldresponse, self.protocol.response) def testAddMonitor(self): # Set the monitor callback up. def monitor_cb(thedata, *args, **kwargs): thedata['args'] = args thedata['kwargs'] = kwargs data = {} self.protocol.add_monitor('abc', partial(monitor_cb, data)) # Simulate some non-matching data. self.protocol.buffer.append(u'aaa') self.assertEqual(data, {}) # Simulate some matching data. self.protocol.buffer.append(u'abc') self.assertEqual(len(data.get('args')), 3) self.assertEqual(data.get('args')[0], self.protocol) self.assertEqual(data.get('args')[1], 0) self.assertEqual(data.get('args')[2].group(0), 'abc') self.assertEqual(data.get('kwargs'), {}) def testGetBuffer(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: return self.assertEqual(str(self.protocol.buffer), '') self.doLogin() # Depending on whether the connected host sends a banner, # the buffer may or may not contain anything now. before = str(self.protocol.buffer) self.protocol.send('ls\r') self.protocol.waitfor(self.protocol.get_prompt()) self.assertNotEqual(str(self.protocol.buffer), before) def _cancel_cb(self, data): self.protocol.cancel_expect() def testCancelExpect(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: return self.doLogin() oldresponse = self.protocol.response self.protocol.data_received_event.connect(self._cancel_cb) self.protocol.send('ls\r') self.assertEqual(oldresponse, self.protocol.response) self.assertRaises(ExpectCancelledException, self.protocol.expect, 'notgoingtohappen') def testInteract(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.interact) return # Can't really be tested. def testClose(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.close) return self.doConnect() self.protocol.close(True) def testGetHost(self): self.assertTrue(self.protocol.get_host() is None) if self.protocol.__class__ == Protocol: return self.doConnect() self.assertEqual(self.protocol.get_host(), self.hostname) def testGuessOs(self): self.assertEqual('unknown', self.protocol.guess_os()) # Other tests can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.close) return self.doConnect() self.assertEqual('unknown', self.protocol.guess_os()) self.protocol.login(self.account) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) self.assertEqual('shell', self.protocol.guess_os())
class Dummy(Protocol): """ This protocol adapter does not open a network connection, but talks to a L{Exscript.emulators.VirtualDevice} internally. """ def __init__(self, device=None, **kwargs): """ @note: Also supports all keyword arguments that L{Protocol} supports. @keyword device: The L{Exscript.emulators.VirtualDevice} with which to communicate. """ Protocol.__init__(self, **kwargs) self.device = device self.init_done = False self.cancel = False self.response = None if not self.device: self.device = VirtualDevice('dummy', strict=False) def is_dummy(self): return True def _expect_any(self, prompt_list, flush=True): self._doinit() # Cancelled by a callback during self._say(). if self.cancel: self.cancel = False return -2, None, self.response # Look for a match in the buffer. for i, prompt in enumerate(prompt_list): matches = prompt.search(str(self.buffer)) if matches is not None: self.response = self.buffer.head(matches.start()) if flush: self.buffer.pop(matches.end()) return i, matches, self.response # "Timeout". return -1, None, self.response def _say(self, string): self._receive_cb(string) self.buffer.append(string) def cancel_expect(self): self.cancel = True def _connect_hook(self, hostname, port): # To more correctly mimic the behavior of a network device, we # do not send the banner here, but in authenticate() instead. self.buffer.clear() return True def _doinit(self): if not self.init_done: self.init_done = True self._say(self.device.init()) def _protocol_authenticate(self, user, password): self._doinit() def _protocol_authenticate_by_key(self, user, key): self._doinit() def send(self, data): self._dbg(4, 'Sending %s' % repr(data)) self._say(self.device.do(data)) def _domatch(self, prompt, flush): # Wait for a prompt. result, match, self.response = self._expect_any(prompt, flush) if match: self._dbg(2, "Got a prompt, match was %s" % repr(match.group())) else: self._dbg(2, "No prompt match") self._dbg(5, "Response was %s" % repr(str(self.buffer))) if result == -1: error = 'Error while waiting for response from device' raise TimeoutException(error) if result == -2: if self.driver_replaced: self.driver_replaced = False raise DriverReplacedException() else: raise ExpectCancelledException() return result, match def close(self, force=False): self._say('\n') self.buffer.clear()
class ServerTest(unittest.TestCase): CORRELATE = Server.Server def setUp(self): self.host = 'localhost' self.port = 1235 self.device = VirtualDevice(self.host, echo = False) self.daemon = Server.Server(self.host, self.port, self.device) self.device.set_prompt(self.host + ':' + str(self.port) + '> ') def tearDown(self): if self.daemon: self.daemon.exit() if self.daemon.__class__ != Server.Server: self.daemon.join() def _create_daemon(self): raise NotImplementedError() def _create_client(self): raise NotImplementedError() def _add_commands(self): self.device.add_command('exit', self.daemon.exit_command) self.device.add_command('ls', 'ok1') self.device.add_command('ll', 'ok2\nfoobar:1>', prompt = False) self.device.add_command('.+', 'Unknown command.') def testConstructor(self): # Test can not work on the abstract base. if self.daemon.__class__ == Server.Server: return self._create_daemon() self.daemon.start() time.sleep(1) def testStart(self): # Test can not work on the abstract base. if self.daemon.__class__ == Server.Server: return self._create_daemon() self._add_commands() self.daemon.start() time.sleep(1) client = self._create_client() client.set_prompt(re.compile(r'\w+:\d+> ?')) client.connect(self.host, self.port) client.login(Account('user', 'password')) client.execute('ls') self.assertEqual(client.response, 'ok1\n') client.execute('ll') self.assertEqual(client.response, 'ok2\n') client.send('exit\r') def testExitCommand(self): pass # tested in testExit() def testExit(self): # Test can not work on the abstract base. if self.daemon.__class__ == Server.Server: return self.testStart() # Since testStart() sent an "exit" command to the server, # it should be shutting down even without us calling # self.daemon.exit(). self.daemon.join() self.testConstructor()
def setUp(self): self.host = 'localhost' self.port = 1235 self.device = VirtualDevice(self.host, echo = False) self.daemon = Server.Server(self.host, self.port, self.device) self.device.set_prompt(self.host + ':' + str(self.port) + '> ')
def setUp(self): self.host = 'localhost' self.port = 1235 self.device = VirtualDevice(self.host, echo=False) self.daemon = Server(self.host, self.port, self.device) self.device.set_prompt(self.host + ':' + str(self.port) + '> ')
class ServerTest(unittest.TestCase): CORRELATE = Server def setUp(self): self.host = 'localhost' self.port = 1235 self.device = VirtualDevice(self.host, echo=False) self.daemon = Server(self.host, self.port, self.device) self.device.set_prompt(self.host + ':' + str(self.port) + '> ') def tearDown(self): if self.daemon: self.daemon.exit() if self.daemon.__class__ != Server: self.daemon.join() def _create_daemon(self): raise NotImplementedError() def _create_client(self): raise NotImplementedError() def _add_commands(self): self.device.add_command('exit', self.daemon.exit_command) self.device.add_command('ls', 'ok1') self.device.add_command('ll', 'ok2\nfoobar:1>', prompt=False) self.device.add_command('.+', 'Unknown command.') def testConstructor(self): # Test can not work on the abstract base. if self.daemon.__class__ == Server: return self._create_daemon() self.daemon.start() time.sleep(1) def testStart(self): # Test can not work on the abstract base. if self.daemon.__class__ == Server: return self._create_daemon() self._add_commands() self.daemon.start() time.sleep(1) client = self._create_client() client.set_prompt(re.compile(r'\w+:\d+> ?')) client.connect(self.host, self.port) client.login(Account('user', 'password')) client.execute('ls') self.assertEqual(client.response, 'ok1\n') client.execute('ll') self.assertEqual(client.response, 'ok2\n') client.send('exit\r') def testExitCommand(self): pass # tested in testExit() def testExit(self): # Test can not work on the abstract base. if self.daemon.__class__ == Server: return self.testStart() # Since testStart() sent an "exit" command to the server, # it should be shutting down even without us calling # self.daemon.exit(). self.daemon.join() self.testConstructor()
class ProtocolTest(unittest.TestCase): """ Since protocols.Protocol is abstract, this test is only a base class for other protocols. It does not do anything fancy on its own. """ CORRELATE = Protocol def setUp(self): self.hostname = '127.0.0.1' self.port = 1236 self.user = '******' self.password = '******' self.account = Account(self.user, password = self.password) self.daemon = None self.createVirtualDevice() self.createDaemon() if self.daemon is not None: self.daemon.start() time.sleep(.2) self.createProtocol() def tearDown(self): if self.daemon is not None: self.daemon.exit() self.daemon.join() def createVirtualDevice(self): self.banner = 'Welcome to %s!\n' % self.hostname self.prompt = self.hostname + '> ' self.device = VirtualDevice(self.hostname, echo = True) ls_response = '-rw-r--r-- 1 sab nmc 1628 Aug 18 10:02 file' self.device.add_command('ls', ls_response) self.device.add_command('df', 'foobar') self.device.add_command('exit', '') self.device.add_command('this-command-causes-an-error', '\ncommand not found') def createDaemon(self): pass def createProtocol(self): self.protocol = Protocol() def doConnect(self): self.protocol.connect(self.hostname, self.port) def doLogin(self, flush = True): self.doConnect() self.protocol.login(self.account, flush = flush) def doProtocolAuthenticate(self, flush = True): self.doConnect() self.protocol.protocol_authenticate(self.account) def doAppAuthenticate(self, flush = True): self.protocol.app_authenticate(self.account, flush) def doAppAuthorize(self, flush = True): self.protocol.app_authorize(self.account, flush) def _trymatch(self, prompts, string): for regex in prompts: match = regex.search(string) if match: return match return None def testPrompts(self): prompts = ('[sam123@home ~]$', '[MyHost-A1]', '<MyHost-A1>', 'sam@knip:~/Code/exscript$', 'sam@MyHost-X123>', 'sam@MyHost-X123#', 'MyHost-ABC-CDE123>', 'MyHost-A1#', 'S-ABC#', '0123456-1-1-abc#', '0123456-1-1-a>', 'MyHost-A1(config)#', 'MyHost-A1(config)>', 'RP/0/RP0/CPU0:A-BC2#', 'FA/0/1/2/3>', 'FA/0/1/2/3(config)>', 'FA/0/1/2/3(config)#', 'ec-c3-c27s99(su)->', 'foobar:0>', '[email protected]:/# ', '[email protected]:/% ') notprompts = ('one two', ' [MyHost-A1]', '[edit]\r', '[edit]\n', '[edit foo]\r', '[edit foo]\n', '[edit foo]\r\n', '[edit one two]') prompt_re = self.protocol.get_prompt() for prompt in prompts: if not self._trymatch(prompt_re, '\n' + prompt): self.fail('Prompt %s does not match exactly.' % prompt) if not self._trymatch(prompt_re, 'this is a test\r\n' + prompt): self.fail('Prompt %s does not match.' % prompt) if self._trymatch(prompt_re, 'some text ' + prompt): self.fail('Prompt %s matches incorrectly.' % repr(prompt)) for prompt in notprompts: if self._trymatch(prompt_re, prompt): self.fail('Prompt %s matches incorrecly.' % repr(prompt)) if self._trymatch(prompt_re, prompt + ' '): self.fail('Prompt %s matches incorrecly.' % repr(prompt)) if self._trymatch(prompt_re, '\n' + prompt): self.fail('Prompt %s matches incorrecly.' % repr(prompt)) def testConstructor(self): self.assertTrue(isinstance(self.protocol, Protocol)) def testCopy(self): self.assertEqual(self.protocol, self.protocol.__copy__()) def testDeepcopy(self): self.assertEqual(self.protocol, self.protocol.__deepcopy__({})) def testIsDummy(self): self.assertEqual(self.protocol.is_dummy(), False) def testSetDriver(self): self.assertTrue(self.protocol.get_driver() is not None) self.assertEqual(self.protocol.get_driver().name, 'generic') self.protocol.set_driver() self.assertTrue(self.protocol.get_driver() is not None) self.assertEqual(self.protocol.get_driver().name, 'generic') self.protocol.set_driver('ios') self.assertTrue(self.protocol.get_driver() is not None) self.assertEqual(self.protocol.get_driver().name, 'ios') self.protocol.set_driver() self.assertTrue(self.protocol.get_driver() is not None) self.assertEqual(self.protocol.get_driver().name, 'generic') def testGetDriver(self): pass # Already tested in testSetDriver() def testAutoinit(self): self.protocol.autoinit() def _test_prompt_setter(self, getter, setter): initial_regex = getter() self.assertTrue(isinstance(initial_regex, list)) self.assertTrue(hasattr(initial_regex[0], 'groups')) my_re = re.compile(r'% username') setter(my_re) regex = getter() self.assertTrue(isinstance(regex, list)) self.assertTrue(hasattr(regex[0], 'groups')) self.assertEqual(regex[0], my_re) setter() regex = getter() self.assertEqual(regex, initial_regex) def testSetUsernamePrompt(self): self._test_prompt_setter(self.protocol.get_username_prompt, self.protocol.set_username_prompt) def testGetUsernamePrompt(self): pass # Already tested in testSetUsernamePrompt() def testSetPasswordPrompt(self): self._test_prompt_setter(self.protocol.get_password_prompt, self.protocol.set_password_prompt) def testGetPasswordPrompt(self): pass # Already tested in testSetPasswordPrompt() def testSetPrompt(self): self._test_prompt_setter(self.protocol.get_prompt, self.protocol.set_prompt) def testGetPrompt(self): pass # Already tested in testSetPrompt() def testSetErrorPrompt(self): self._test_prompt_setter(self.protocol.get_error_prompt, self.protocol.set_error_prompt) def testGetErrorPrompt(self): pass # Already tested in testSetErrorPrompt() def testSetLoginErrorPrompt(self): self._test_prompt_setter(self.protocol.get_login_error_prompt, self.protocol.set_login_error_prompt) def testGetLoginErrorPrompt(self): pass # Already tested in testSetLoginErrorPrompt() def testSetConnectTimeout(self): self.assertTrue(self.protocol.get_connect_timeout() == 30) self.protocol.set_connect_timeout(60) self.assertTrue(self.protocol.get_connect_timeout() == 60) def testGetConnectTimeout(self): pass # Already tested in testSetConnectTimeout() def testSetTimeout(self): self.assertTrue(self.protocol.get_timeout() == 30) self.protocol.set_timeout(60) self.assertTrue(self.protocol.get_timeout() == 60) def testGetTimeout(self): pass # Already tested in testSetTimeout() def testConnect(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.connect) return self.assertEqual(self.protocol.response, None) self.doConnect() self.assertEqual(self.protocol.response, None) self.assertEqual(self.protocol.get_host(), self.hostname) def testLogin(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.login, self.account) return # Password login. self.doLogin(flush = False) self.assertTrue(self.protocol.response is not None) self.assertTrue(len(self.protocol.response) > 0) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) # Key login. self.tearDown() self.setUp() key = PrivateKey.from_file('foo', keytype = 'rsa') account = Account(self.user, self.password, key = key) self.doConnect() self.assertFalse(self.protocol.is_protocol_authenticated()) self.assertFalse(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) self.protocol.login(account, flush = False) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) def testAuthenticate(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.authenticate, self.account) return self.doConnect() # Password login. self.assertFalse(self.protocol.is_protocol_authenticated()) self.assertFalse(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) self.protocol.authenticate(self.account, flush = False) self.assertTrue(self.protocol.response is not None) self.assertTrue(len(self.protocol.response) > 0) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) # Key login. self.tearDown() self.setUp() key = PrivateKey.from_file('foo', keytype = 'rsa') account = Account(self.user, self.password, key = key) self.doConnect() self.assertFalse(self.protocol.is_protocol_authenticated()) self.assertFalse(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) self.protocol.authenticate(account, flush = False) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) def testProtocolAuthenticate(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.protocol.protocol_authenticate(self.account) return # There is no guarantee that the device provided any response # during protocol level authentification. self.doProtocolAuthenticate(flush = False) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertFalse(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) def testIsProtocolAuthenticated(self): pass # See testProtocolAuthenticate() def testAppAuthenticate(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.app_authenticate, self.account) return self.testProtocolAuthenticate() self.doAppAuthenticate(flush = False) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertFalse(self.protocol.is_app_authorized()) def testIsAppAuthenticated(self): pass # See testAppAuthenticate() def testAppAuthorize(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.app_authorize) return self.doProtocolAuthenticate(flush = False) self.doAppAuthenticate(flush = False) response = self.protocol.response # Authorize should see that a prompt is still in the buffer, # and do nothing. self.doAppAuthorize(flush = False) self.assertEqual(self.protocol.response, response) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) self.doAppAuthorize(flush = True) self.assertEqual(self.protocol.response, response) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) def testAutoAppAuthorize(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(TypeError, self.protocol.auto_app_authorize) return self.testAppAuthenticate() response = self.protocol.response # This should do nothing, because our test host does not # support AAA. Can't think of a way to test against a # device using AAA. self.protocol.auto_app_authorize(self.account, flush = False) self.assertEqual(self.protocol.response, response) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) self.protocol.auto_app_authorize(self.account, flush = True) self.assertEqual(self.protocol.response, response) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) def testIsAppAuthorized(self): pass # see testAppAuthorize() def testSend(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.send, 'ls') return self.doLogin() self.protocol.execute('ls') self.protocol.send('df\r') self.assertTrue(self.protocol.response is not None) self.assertTrue(self.protocol.response.startswith('ls')) self.protocol.send('exit\r') self.assertTrue(self.protocol.response is not None) self.assertTrue(self.protocol.response.startswith('ls')) def testExecute(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.execute, 'ls') return self.doLogin() self.protocol.execute('ls') self.assertTrue(self.protocol.response is not None) self.assertTrue(self.protocol.response.startswith('ls')) # Make sure that we raise an error if the device responds # with something that matches any of the error prompts. self.protocol.set_error_prompt('.') self.assertRaises(InvalidCommandException, self.protocol.execute, 'this-command-causes-an-error') def testWaitfor(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.waitfor, 'ls') return self.doLogin() oldresponse = self.protocol.response self.protocol.send('ls\r') self.assertEqual(oldresponse, self.protocol.response) self.protocol.waitfor(re.compile(r'[\r\n]')) self.assertNotEqual(oldresponse, self.protocol.response) oldresponse = self.protocol.response self.protocol.waitfor(re.compile(r'[\r\n]')) self.assertEqual(oldresponse, self.protocol.response) def testExpect(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.expect, 'ls') return self.doLogin() oldresponse = self.protocol.response self.protocol.send('ls\r') self.assertEqual(oldresponse, self.protocol.response) self.protocol.expect(re.compile(r'[\r\n]')) self.assertNotEqual(oldresponse, self.protocol.response) def testExpectPrompt(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.expect, 'ls') return self.doLogin() oldresponse = self.protocol.response self.protocol.send('ls\r') self.assertEqual(oldresponse, self.protocol.response) self.protocol.expect_prompt() self.assertNotEqual(oldresponse, self.protocol.response) def testAddMonitor(self): # Set the monitor callback up. def monitor_cb(thedata, *args, **kwargs): thedata['args'] = args thedata['kwargs'] = kwargs data = {} self.protocol.add_monitor('abc', partial(monitor_cb, data)) # Simulate some non-matching data. self.protocol.buffer.append('aaa') self.assertEqual(data, {}) # Simulate some matching data. self.protocol.buffer.append('abc') self.assertEqual(len(data.get('args')), 3) self.assertEqual(data.get('args')[0], self.protocol) self.assertEqual(data.get('args')[1], 0) self.assertEqual(data.get('args')[2].group(0), 'abc') self.assertEqual(data.get('kwargs'), {}) def testGetBuffer(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: return self.assertEqual(str(self.protocol.buffer), '') self.doLogin() # Depending on whether the connected host sends a banner, # the buffer may or may not contain anything now. before = str(self.protocol.buffer) self.protocol.send('ls\r') self.protocol.waitfor(self.protocol.get_prompt()) self.assertNotEqual(str(self.protocol.buffer), before) def _cancel_cb(self, data): self.protocol.cancel_expect() def testCancelExpect(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: return self.doLogin() oldresponse = self.protocol.response self.protocol.data_received_event.connect(self._cancel_cb) self.protocol.send('ls\r') self.assertEqual(oldresponse, self.protocol.response) self.assertRaises(ExpectCancelledException, self.protocol.expect, 'notgoingtohappen') def testInteract(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.interact) return # Can't really be tested. def testClose(self): # Test can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.close) return self.doConnect() self.protocol.close(True) def testGetHost(self): self.assertTrue(self.protocol.get_host() is None) if self.protocol.__class__ == Protocol: return self.doConnect() self.assertEqual(self.protocol.get_host(), self.hostname) def testGuessOs(self): self.assertEqual('unknown', self.protocol.guess_os()) # Other tests can not work on the abstract base. if self.protocol.__class__ == Protocol: self.assertRaises(Exception, self.protocol.close) return self.doConnect() self.assertEqual('unknown', self.protocol.guess_os()) self.protocol.login(self.account) self.assertTrue(self.protocol.is_protocol_authenticated()) self.assertTrue(self.protocol.is_app_authenticated()) self.assertTrue(self.protocol.is_app_authorized()) self.assertEqual('shell', self.protocol.guess_os())
def testDummy(self): # Test simple instance with banner. protocol = Dummy(device = self.device) protocol.connect('testhost') self.assertEqual(str(protocol.buffer), '') self.assertEqual(protocol.response, None) protocol.close() # Test login. protocol = Dummy(device = self.device) protocol.connect('testhost') self.assertEqual(str(protocol.buffer), '') self.assertEqual(protocol.response, None) protocol.login(self.account, flush = False) self.assertEqual(protocol.buffer.tail(len(self.prompt)), self.prompt) protocol.close() # Test login with user prompt. device = VirtualDevice(self.hostname, echo = True, login_type = VirtualDevice.LOGIN_TYPE_USERONLY) protocol = self._create_dummy_and_eat_banner(device) self.assertEqual(str(protocol.buffer), 'User: '******'Password: '******'User: '******'') self.assertEqual(protocol.response, self.user + '\r') protocol.close() # Test login with password prompt and wait parameter. device = VirtualDevice(self.hostname, echo = True, login_type = VirtualDevice.LOGIN_TYPE_PASSWORDONLY) protocol = self._create_dummy_and_eat_banner(device) self.assertEqual(str(protocol.buffer), 'Password: '******'') self.assertEqual(protocol.response, self.password + '\r') protocol.close() # Test login with port number. protocol = self._create_dummy_and_eat_banner(device, 1234) self.assertEqual(str(protocol.buffer), 'Password: '******'') self.assertEqual(protocol.response, self.password + '\r') protocol.close() # Test a custom response. device = VirtualDevice(self.hostname, echo = True, login_type = VirtualDevice.LOGIN_TYPE_NONE) protocol = Dummy(device = device) command = re.compile(r'testcommand') response = 'hello world\r\n%s> ' % self.hostname device.add_command(command, response, prompt = False) protocol.set_prompt(re.compile(r'> $')) protocol.connect('testhost') protocol.expect(re.compile(re.escape(self.banner))) self.assertEqual(protocol.response, '') self.assertEqual(str(protocol.buffer), self.prompt) protocol.expect_prompt() self.assertEqual(str(protocol.buffer), '') self.assertEqual(protocol.response, self.hostname) protocol.execute('testcommand') expected = 'testcommand\rhello world\r\n' + self.hostname self.assertEqual(protocol.response, expected) self.assertEqual(str(protocol.buffer), '') protocol.close()
class Dummy(Protocol): """ This protocol adapter does not open a network connection, but talks to a L{Exscript.emulators.VirtualDevice} internally. """ def __init__(self, device = None, **kwargs): """ @note: Also supports all keyword arguments that L{Protocol} supports. @keyword device: The L{Exscript.emulators.VirtualDevice} with which to communicate. """ Protocol.__init__(self, **kwargs) self.device = device self.init_done = False self.cancel = False self.response = None if not self.device: self.device = VirtualDevice('dummy', strict = False) def is_dummy(self): return True def _expect_any(self, prompt_list, flush = True): self._doinit() # Cancelled by a callback during self._say(). if self.cancel: self.cancel = False return -2, None, self.response # Look for a match in the buffer. for i, prompt in enumerate(prompt_list): matches = prompt.search(str(self.buffer)) if matches is not None: self.response = self.buffer.head(matches.start()) if flush: self.buffer.pop(matches.end()) return i, matches, self.response # "Timeout". return -1, None, self.response def _say(self, string): self._receive_cb(string) self.buffer.append(string) def cancel_expect(self): self.cancel = True def _connect_hook(self, hostname, port): # To more correctly mimic the behavior of a network device, we # do not send the banner here, but in authenticate() instead. self.buffer.clear() return True def _doinit(self): if not self.init_done: self.init_done = True self._say(self.device.init()) def _protocol_authenticate(self, user, password): self._doinit() def _protocol_authenticate_by_key(self, user, key): self._doinit() def send(self, data): self._dbg(4, 'Sending %s' % repr(data)) self._say(self.device.do(data)) def _domatch(self, prompt, flush): # Wait for a prompt. result, match, self.response = self._expect_any(prompt, flush) if match: self._dbg(2, "Got a prompt, match was %s" % repr(match.group())) else: self._dbg(2, "No prompt match") self._dbg(5, "Response was %s" % repr(str(self.buffer))) if result == -1: error = 'Error while waiting for response from device' raise TimeoutException(error) if result == -2: if self.driver_replaced: self.driver_replaced = False raise DriverReplacedException() else: raise ExpectCancelledException() return result, match def close(self, force = False): self._say('\n') self.buffer.clear()