def test_config_output(self): # importing because it sets up `peewee` logging, which is checked at the test below from neo.Implementations.Wallets.peewee.UserWallet import UserWallet args = ['output'] with patch( 'neo.Prompt.Commands.Config.prompt', side_effect=[1, 1, 1, "a", "\n", "\n"] ): # tests changing the level and keeping the current level. Entering "a" has no effect. res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(res['generic'], "DEBUG") self.assertEqual(res['vm'], "DEBUG") self.assertEqual(res['db'], "DEBUG") self.assertEqual(res['peewee'], "ERROR") self.assertEqual(res['network'], "INFO") self.assertEqual(res['network.verbose'], "INFO") # test with keyboard interrupt with patch('sys.stdout', new=StringIO()) as mock_print: with patch('neo.Prompt.Commands.Config.prompt', side_effect=[KeyboardInterrupt]): res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Output configuration cancelled", mock_print.getvalue())
def test_config(self): # with no subcommand res = CommandConfig().execute(None) self.assertFalse(res) # with invalid command args = ['badcommand'] res = CommandConfig().execute(args) self.assertFalse(res)
def test_config_node_requests(self): # test no input args = ['node-requests'] res = CommandConfig().execute(args) self.assertFalse(res) # test updating block request size # first make sure we have a predictable state NodeLeader.Instance().Reset() leader = NodeLeader.Instance() leader.ADDRS = ["127.0.0.1:20333", "127.0.0.2:20334"] leader.DEAD_ADDRS = ["127.0.0.1:20335"] # test slow setting args = ['node-requests', 'slow'] res = CommandConfig().execute(args) self.assertTrue(res) # test normal setting args = ['node-requests', 'normal'] res = CommandConfig().execute(args) self.assertTrue(res) # test fast setting args = ['node-requests', 'fast'] res = CommandConfig().execute(args) self.assertTrue(res) # test bad setting args = ['node-requests', 'blah'] res = CommandConfig().execute(args) self.assertFalse(res) # test custom setting args = ['node-requests', '20', '6000'] res = CommandConfig().execute(args) self.assertTrue(res) # test bad custom input args = ['node-requests', '20', 'blah'] res = CommandConfig().execute(args) self.assertFalse(res) # test bad custom setting: breqmax should be greater than breqpart args = ['node-requests', '20', '10'] res = CommandConfig().execute(args) self.assertFalse(res) # test another bad custom setting: breqpart should not exceed 500 args = ['node-requests', '600', '5000'] res = CommandConfig().execute(args) self.assertFalse(res)
def test_config_minpeers(self): # test no input and verify output confirming current minpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['minpeers'] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn( f"Maintaining minpeers at {settings.CONNECTED_PEER_MIN}", mock_print.getvalue()) # test changing the number of minpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['minpeers', "6"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(int(res), settings.CONNECTED_PEER_MIN) self.assertIn(f"Minpeers set to {settings.CONNECTED_PEER_MIN}", mock_print.getvalue()) # test bad input with patch('sys.stdout', new=StringIO()) as mock_print: args = ['minpeers', "blah"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Please supply a positive integer for minpeers", mock_print.getvalue()) # test negative number with patch('sys.stdout', new=StringIO()) as mock_print: args = ['minpeers', "-1"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Please supply a positive integer for minpeers", mock_print.getvalue()) # test minpeers greater than maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['minpeers', f"{settings.CONNECTED_PEER_MAX + 1}"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn( "minpeers setting cannot be bigger than maxpeers setting", mock_print.getvalue())
def test_config_vm_log(self): # test no input args = ['vm-log'] res = CommandConfig().execute(args) self.assertFalse(res) # test turning them on args = ['vm-log', 'on'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertTrue(settings.log_vm_instructions) # test turning them off args = ['vm-log', '0'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertFalse(settings.log_vm_instructions) # test bad input args = ['vm-log', 'blah'] res = CommandConfig().execute(args) self.assertFalse(res)
def test_config_debug_notify(self): # test no input args = ['sc-debug-notify'] res = CommandConfig().execute(args) self.assertFalse(res) # test turning them on args = ['sc-debug-notify', 'on'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertTrue(settings.emit_notify_events_on_sc_execution_error) # test turning them off args = ['sc-debug-notify', '0'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertFalse(settings.emit_notify_events_on_sc_execution_error) # test bad input args = ['sc-debug-notify', 'blah'] res = CommandConfig().execute(args) self.assertFalse(res)
def test_config_sc_events(self): # test no input args = ['sc-events'] res = CommandConfig().execute(args) self.assertFalse(res) # test turning them on args = ['sc-events', 'on'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertTrue(settings.log_smart_contract_events) # test turning them off args = ['sc-events', '0'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertFalse(settings.log_smart_contract_events) # test bad input args = ['sc-events', 'blah'] res = CommandConfig().execute(args) self.assertFalse(res)
def test_config_output(self): # importing because it sets up `peewee` logging, which is checked at the test below from neo.Implementations.Wallets.peewee.UserWallet import UserWallet args = ['output'] with patch('neo.Prompt.Commands.Config.prompt', side_effect=[1, 1, 1, "\n", "\n", "\n"]): # tests changing the level and keeping the current level res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(res['generic'], "DEBUG") self.assertEqual(res['vm'], "DEBUG") self.assertEqual(res['db'], "DEBUG") self.assertEqual(res['peewee'], "ERROR") self.assertEqual(res['network'], "INFO") self.assertEqual(res['network.verbose'], "INFO")
def test_config_maxpeers(self): # test no input and verify output confirming current maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers'] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn(f"Maintaining maxpeers at {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # test changing the number of maxpeers args = ['maxpeers', "6"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(int(res), settings.CONNECTED_PEER_MAX) # test bad input args = ['maxpeers', "blah"] res = CommandConfig().execute(args) self.assertFalse(res) # test negative number args = ['maxpeers', "-1"] res = CommandConfig().execute(args) self.assertFalse(res)
def test_config_nep8(self): # test with missing flag argument with patch('sys.stdout', new=StringIO()) as mock_print: args = ['nep8'] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Please specify the required parameter", mock_print.getvalue()) # test with invalid option with patch('sys.stdout', new=StringIO()) as mock_print: args = ['nep8', 'blah'] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Invalid option", mock_print.getvalue()) # ideally for the next tests we should compile some SC and validate if NEP-8 instructions are used or not # for now the effort required to do so does not seem justified and we'll just rely on applying the setting # test turning on - 1 with patch('sys.stdout', new=StringIO()) as mock_print: args = ['nep8', 'on'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertIn("NEP-8 compiler instruction usage is ON", mock_print.getvalue()) # test turning on - 2 with patch('sys.stdout', new=StringIO()) as mock_print: args = ['nep8', '1'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertIn("NEP-8 compiler instruction usage is ON", mock_print.getvalue()) # test turning off - 1 with patch('sys.stdout', new=StringIO()) as mock_print: args = ['nep8', 'off'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertIn("NEP-8 compiler instruction usage is OFF", mock_print.getvalue()) # test turning off - 2 with patch('sys.stdout', new=StringIO()) as mock_print: args = ['nep8', '0'] res = CommandConfig().execute(args) self.assertTrue(res) self.assertIn("NEP-8 compiler instruction usage is OFF", mock_print.getvalue())
class PromptInterface: prompt_completer = None history = None go_on = True wallet_loop_deferred = None Wallet = None _known_things = [] _commands = [ CommandWallet(), CommandShow(), CommandSearch(), CommandConfig(), CommandSC() ] _command_descs = [ desc for c in _commands for desc in c.command_descs_with_sub_commands() ] commands = { command.command_desc().command: command for command in _commands } start_height = None start_dt = None def __init__(self, history_filename=None): PromptData.Prompt = self if history_filename: PromptInterface.history = PromptFileHistory(history_filename) self.input_parser = InputParser() self.start_height = Blockchain.Default().Height self.start_dt = datetime.datetime.utcnow() def get_bottom_toolbar(self, cli=None): out = [] try: return "[%s] Progress: %s/%s" % ( settings.net_name, str(Blockchain.Default().Height), str(Blockchain.Default().HeaderHeight)) except Exception as e: pass return out def get_completer(self): standard_completions = list({ word for d in self._command_descs for word in d.command.split() }) # Use a set to ensure unicity of words standard_completions += ['quit', 'help', 'exit'] if PromptData.Wallet: for addr in PromptData.Wallet.Addresses: if addr not in self._known_things: self._known_things.append(addr) for alias in PromptData.Wallet.NamedAddr: if alias.Title not in self._known_things: self._known_things.append(alias.Title) for tkn in PromptData.Wallet.GetTokens().values(): if tkn.symbol not in self._known_things: self._known_things.append(tkn.symbol) all_completions = standard_completions + self._known_things PromptInterface.prompt_completer = WordCompleter(all_completions) return PromptInterface.prompt_completer def quit(self): print('Shutting down. This may take a bit...') self.go_on = False PromptData.close_wallet() Blockchain.Default().Dispose() NodeLeader.Instance().Shutdown() reactor.stop() def help(self): prompt_print(f"\nCommands:") for command_group in sorted(self.commands.keys()): command = self.commands[command_group] prompt_print( f" {command_group:<15} - {command.command_desc().short_help}" ) prompt_print( f"\nRun 'COMMAND help' for more information on a command.") def start_wallet_loop(self): if self.wallet_loop_deferred: self.stop_wallet_loop() self.walletdb_loop = task.LoopingCall(PromptData.Wallet.ProcessBlocks) self.wallet_loop_deferred = self.walletdb_loop.start(1) self.wallet_loop_deferred.addErrback(self.on_looperror) def stop_wallet_loop(self): self.wallet_loop_deferred.cancel() self.wallet_loop_deferred = None if self.walletdb_loop and self.walletdb_loop.running: self.walletdb_loop.stop() def on_looperror(self, err): logger.debug("On DB loop error! %s " % err) def run(self): dbloop = task.LoopingCall(Blockchain.Default().PersistBlocks) dbloop_deferred = dbloop.start(.1) dbloop_deferred.addErrback(self.on_looperror) tokens = [("class:neo", 'NEO'), ("class:default", ' cli. Type '), ("class:command", '\'help\' '), ("class:default", 'to get started')] print_formatted_text(FormattedText(tokens), style=token_style) print('\n') while self.go_on: session = PromptSession( "neo> ", completer=self.get_completer(), history=self.history, bottom_toolbar=self.get_bottom_toolbar, style=token_style, refresh_interval=3, ) try: result = session.prompt() except EOFError: # Control-D pressed: quit return self.quit() except KeyboardInterrupt: # Control-C pressed: do nothing continue except Exception as e: logger.error("Exception handling input: %s " % e) try: command, arguments = self.input_parser.parse_input(result) if command is not None and len(command) > 0: command = command.lower() if command in self.commands: cmd = self.commands[command] if len(arguments) > 0 and arguments[-1] == 'help': cmd.handle_help(arguments) else: cmd.execute(arguments) else: if command == 'quit' or command == 'exit': self.quit() elif command == 'help': self.help() elif command is None: print("Please specify a command") else: print("Command '%s' not found" % command) except Exception as e: print("Could not execute command: %s" % e) traceback.print_stack() traceback.print_exc()
def test_config_maxpeers(self): # test no input and verify output confirming current maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers'] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn( f"Maintaining maxpeers at {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # test changing the number of maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "6"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(int(res), settings.CONNECTED_PEER_MAX) self.assertIn(f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # test bad input with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "blah"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Please supply a positive integer for maxpeers", mock_print.getvalue()) # test negative number with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "-1"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Please supply a positive integer for maxpeers", mock_print.getvalue()) # test if the new maxpeers < settings.CONNECTED_PEER_MAX # first make sure we have a predictable state NodeLeader.Instance().Reset() leader = NodeLeader.Instance() addr1 = Address("127.0.0.1:20333") addr2 = Address("127.0.0.1:20334") leader.ADDRS = [addr1, addr2] leader.DEAD_ADDRS = [Address("127.0.0.1:20335")] test_node = NeoNode() test_node.host = "127.0.0.1" test_node.port = 20333 test_node.address = Address("127.0.0.1:20333") test_node2 = NeoNode() test_node2.host = "127.0.0.1" test_node2.port = 20333 test_node2.address = Address("127.0.0.1:20334") leader.Peers = [test_node, test_node2] with patch( "neo.Network.NeoNode.NeoNode.Disconnect") as mock_disconnect: # first test if the number of connected peers !< new maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "4"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(len(leader.Peers), 2) self.assertFalse(mock_disconnect.called) self.assertIn(f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # now test if the number of connected peers < new maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "1"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(len(leader.Peers), 1) self.assertEqual(leader.Peers[0].address, test_node.address) self.assertTrue(mock_disconnect.called) self.assertIn(f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue())
def test_config_maxpeers(self): nodemgr = NodeManager() nodemgr.reset_for_test() # test no input and verify output confirming current maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers'] res = CommandConfig().execute(args) self.assertFalse(res) self.assertEqual(settings.CONNECTED_PEER_MAX, 10) self.assertIn( f"Maintaining maxpeers at {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # test changing the number of maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "6"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(settings.CONNECTED_PEER_MAX, 6) self.assertEqual(int(res), settings.CONNECTED_PEER_MAX) self.assertIn(f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # test trying to set maxpeers > 10 with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "12"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Max peers is limited to 10", mock_print.getvalue()) # test bad input with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "blah"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Invalid argument", mock_print.getvalue()) # test negative number with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "-1"] res = CommandConfig().execute(args) self.assertFalse(res) self.assertIn("Please supply a positive integer for maxpeers", mock_print.getvalue()) # test if the new maxpeers < settings.CONNECTED_PEER_MAX # first make sure we have a predictable state node1 = NeoNode(object, object) node2 = NeoNode(object, object) node1.address = "127.0.0.1:20333" node2.address = "127.0.0.1:20334" nodemgr.nodes = [node1, node2] nodemgr.loop = object with patch("neo.Network.node.NeoNode.disconnect") as mock_disconnect: # first test if the number of connected peers !< new maxpeers self.assertEqual(nodemgr.max_clients, 6) # verifying the current number of maxpeers with patch('sys.stdout', new=StringIO()) as mock_print: args = ['maxpeers', "4"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(nodemgr.max_clients, 4) self.assertFalse(mock_disconnect.called) self.assertEqual(settings.CONNECTED_PEER_MAX, 4) self.assertIn(f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) # now test if the number of connected peers < new maxpeers and < current minpeers self.assertEqual(settings.CONNECTED_PEER_MIN, 4) # verifying the current minpeers value with patch('sys.stdout', new=StringIO()) as mock_print: with patch('neo.Prompt.Commands.Config.wait_for'): args = ['maxpeers', "1"] res = CommandConfig().execute(args) self.assertTrue(res) self.assertEqual(nodemgr.max_clients, 1) self.assertTrue(mock_disconnect.called) self.assertEqual(settings.CONNECTED_PEER_MAX, 1) self.assertIn( f"Maxpeers set to {settings.CONNECTED_PEER_MAX}", mock_print.getvalue()) self.assertEqual(settings.CONNECTED_PEER_MIN, 1) self.assertIn( f"Minpeers set to {settings.CONNECTED_PEER_MIN}", mock_print.getvalue()) # reset for future tests nodemgr.reset_for_test() nodemgr.loop = None settings.set_max_peers(10)
class PromptInterface: prompt_completer = None history = None go_on = True wallet_loop_deferred = None Wallet = None _known_things = [] _commands = [ CommandWallet(), CommandShow(), CommandSearch(), CommandConfig(), CommandSC() ] _command_descs = [ desc for c in _commands for desc in c.command_descs_with_sub_commands() ] commands = { command.command_desc().command: command for command in _commands } start_height = None start_dt = None prompt_session = None def __init__(self, history_filename=None): PromptData.Prompt = self if history_filename: PromptInterface.history = PromptFileHistory(history_filename) self.input_parser = InputParser() self.start_height = Blockchain.Default().Height self.start_dt = datetime.datetime.utcnow() def get_bottom_toolbar(self, cli=None): out = [] try: if PromptData.Wallet is None: return "[%s] Progress: 0/%s/%s" % ( settings.net_name, str(Blockchain.Default().Height), str(Blockchain.Default().HeaderHeight)) else: return "[%s] Progress: %s/%s/%s" % ( settings.net_name, str(PromptData.Wallet._current_height), str(Blockchain.Default().Height), str(Blockchain.Default().HeaderHeight)) except Exception as e: pass return out def get_completer(self): standard_completions = list({ word for d in self._command_descs for word in d.command.split() }) # Use a set to ensure unicity of words standard_completions += ['quit', 'help', 'exit'] if PromptData.Wallet: for addr in PromptData.Wallet.Addresses: if addr not in self._known_things: self._known_things.append(addr) for alias in PromptData.Wallet.NamedAddr: if alias.Title not in self._known_things: self._known_things.append(alias.Title) for tkn in PromptData.Wallet.GetTokens().values(): if tkn.symbol not in self._known_things: self._known_things.append(tkn.symbol) all_completions = standard_completions + self._known_things PromptInterface.prompt_completer = WordCompleter(all_completions) return PromptInterface.prompt_completer def quit(self): print('Shutting down. This may take a bit...') self.go_on = False PromptData.close_wallet() raise SystemExit def help(self): prompt_print(f"\nCommands:") for command_group in sorted(self.commands.keys()): command = self.commands[command_group] prompt_print( f" {command_group:<15} - {command.command_desc().short_help}" ) prompt_print( f"\nRun 'COMMAND help' for more information on a command.") def on_looperror(self, err): logger.debug("On DB loop error! %s " % err) async def run(self): nodemgr = NodeManager() while not nodemgr.running: await asyncio.sleep(0.1) tokens = [("class:neo", 'NEO'), ("class:default", ' cli. Type '), ("class:command", '\'help\' '), ("class:default", 'to get started')] print_formatted_text(FormattedText(tokens), style=token_style) print('\n') session = PromptSession( "neo> ", completer=self.get_completer(), history=self.history, bottom_toolbar=self.get_bottom_toolbar, style=token_style, refresh_interval=3, ) self.prompt_session = session result = "" while self.go_on: # with patch_stdout(): try: result = await session.prompt(async_=True) except EOFError: # Control-D pressed: quit return self.quit() except KeyboardInterrupt: # Control-C pressed: pause for user input # temporarily mute stdout during user input # components like `network` set at DEBUG level will spam through the console # making it impractical to input user data log_manager.mute_stdio() print('Logging output muted during user input...') try: result = await session.prompt(async_=True) except Exception as e: logger.error("Exception handling input: %s " % e) # and re-enable stdio log_manager.unmute_stdio() except Exception as e: logger.error("Exception handling input: %s " % e) try: command, arguments = self.input_parser.parse_input(result) if command is not None and len(command) > 0: command = command.lower() if command in self.commands: cmd = self.commands[command] if len(arguments) > 0 and arguments[-1] == 'help': cmd.handle_help(arguments) else: cmd.execute(arguments) else: if command == 'quit' or command == 'exit': self.quit() elif command == 'help': self.help() elif command is None: print("Please specify a command") else: print("Command '%s' not found" % command) except Exception as e: print("Could not execute command: %s" % e) traceback.print_stack() traceback.print_exc()