from basetest import * from zfs_autobackup.ExecuteNode import * print("THIS TEST REQUIRES SSH TO LOCALHOST") class TestExecuteNode(unittest2.TestCase): # def setUp(self): # return super().setUp() def basics(self, node ): with self.subTest("simple echo"): self.assertEqual(node.run(["echo","test"]), ["test"]) with self.subTest("error exit code"): with self.assertRaises(ExecuteError): node.run(["false"]) # with self.subTest("multiline without tabsplit"): self.assertEqual(node.run(["echo","l1c1\tl1c2\nl2c1\tl2c2"], tab_split=False), ["l1c1\tl1c2", "l2c1\tl2c2"]) #multiline tabsplit with self.subTest("multiline tabsplit"): self.assertEqual(node.run(["echo","l1c1\tl1c2\nl2c1\tl2c2"], tab_split=True), [['l1c1', 'l1c2'], ['l2c1', 'l2c2']]) #escaping test with self.subTest("escape test"): s="><`'\"@&$()$bla\\/.* !#test _+-={}[]|${bla} $bla" self.assertEqual(node.run(["echo",s]), [s]) #return std err as well, trigger stderr by listing something non existing with self.subTest("stderr return"): (stdout, stderr)=node.run(["sh", "-c", "echo bla >&2"], return_stderr=True, valid_exitcodes=[0]) self.assertEqual(stdout,[]) self.assertRegex(stderr[0],"bla") #slow command, make sure things dont exit too early with self.subTest("early exit test"): start_time=time.time() self.assertEqual(node.run(["sleep","1"]), []) self.assertGreaterEqual(time.time()-start_time,1) #input a string and check it via cat with self.subTest("stdin input string"): self.assertEqual(node.run(["cat"], inp="test"), ["test"]) #command that wants input, while we dont have input, shouldnt hang forever. with self.subTest("stdin process with inp=None (shouldn't hang)"): self.assertEqual(node.run(["cat"]), []) # let the system do the piping with an unescaped |: with self.subTest("system piping test"): #first make sure the actual | character is still properly escaped: self.assertEqual(node.run(["echo","|"]), ["|"]) #now pipe self.assertEqual(node.run(["echo", "abc", node.PIPE, "tr", "a", "A" ]), ["Abc"]) def test_basics_local(self): node=ExecuteNode(debug_output=True) self.basics(node) def test_basics_remote(self): node=ExecuteNode(ssh_to="localhost", debug_output=True) self.basics(node) ################ def test_readonly(self): node=ExecuteNode(debug_output=True, readonly=True) self.assertEqual(node.run(["echo","test"], readonly=False), []) self.assertEqual(node.run(["echo","test"], readonly=True), ["test"]) ################ def pipe(self, nodea, nodeb): with self.subTest("pipe data"): output=nodea.run(["dd", "if=/dev/zero", "count=1000"],pipe=True) self.assertEqual(nodeb.run(["md5sum"], inp=output), ["816df6f64deba63b029ca19d880ee10a -"]) with self.subTest("exit code both ends of pipe ok"): output=nodea.run(["true"], pipe=True) nodeb.run(["true"], inp=output) with self.subTest("error on pipe input side"): with self.assertRaises(ExecuteError): output=nodea.run(["false"], pipe=True) nodeb.run(["true"], inp=output) with self.subTest("error on both sides, ignore exit codes"): output=nodea.run(["false"], pipe=True, valid_exitcodes=[]) nodeb.run(["false"], inp=output, valid_exitcodes=[]) with self.subTest("error on pipe output side "): with self.assertRaises(ExecuteError): output=nodea.run(["true"], pipe=True) nodeb.run(["false"], inp=output) with self.subTest("error on both sides of pipe"): with self.assertRaises(ExecuteError): output=nodea.run(["false"], pipe=True) nodeb.run(["false"], inp=output) with self.subTest("check stderr on pipe output side"): output=nodea.run(["true"], pipe=True, valid_exitcodes=[0]) (stdout, stderr)=nodeb.run(["sh", "-c", "echo bla >&2"], inp=output, return_stderr=True, valid_exitcodes=[0]) self.assertEqual(stdout,[]) self.assertRegex(stderr[0], "bla" ) with self.subTest("check stderr on pipe input side (should be only printed)"): output=nodea.run(["sh", "-c", "echo bla >&2"], pipe=True, valid_exitcodes=[0]) (stdout, stderr)=nodeb.run(["true"], inp=output, return_stderr=True, valid_exitcodes=[0]) self.assertEqual(stdout,[]) self.assertEqual(stderr,[]) def test_pipe_local_local(self): nodea=ExecuteNode(debug_output=True) nodeb=ExecuteNode(debug_output=True) self.pipe(nodea, nodeb) def test_pipe_remote_remote(self): nodea=ExecuteNode(ssh_to="localhost", debug_output=True) nodeb=ExecuteNode(ssh_to="localhost", debug_output=True) self.pipe(nodea, nodeb) def test_pipe_local_remote(self): nodea=ExecuteNode(debug_output=True) nodeb=ExecuteNode(ssh_to="localhost", debug_output=True) self.pipe(nodea, nodeb) def test_pipe_remote_local(self): nodea=ExecuteNode(ssh_to="localhost", debug_output=True) nodeb=ExecuteNode(debug_output=True) self.pipe(nodea, nodeb) def test_cwd(self): nodea=ExecuteNode(ssh_to="localhost", debug_output=True) nodeb=ExecuteNode(debug_output=True) #change to a directory with a space and execute a system pipe, check if all piped commands are executed in correct directory. shelltest("mkdir '/tmp/space test' 2>/dev/null; true") self.assertEqual(nodea.run(cmd=["pwd", ExecuteNode.PIPE, "cat"], cwd="/tmp/space test"), ["/tmp/space test"]) self.assertEqual(nodea.run(cmd=["cat", ExecuteNode.PIPE, "pwd"], cwd="/tmp/space test"), ["/tmp/space test"]) self.assertEqual(nodeb.run(cmd=["pwd", ExecuteNode.PIPE, "cat"], cwd="/tmp/space test"), ["/tmp/space test"]) self.assertEqual(nodeb.run(cmd=["cat", ExecuteNode.PIPE, "pwd"], cwd="/tmp/space test"), ["/tmp/space test"]) def test_script_handlers(self): def test(node): results = [] node.script(lines=["echo line1", "echo line2 1>&2", "exit 123"], stdout_handler=lambda line: results.append(line), stderr_handler=lambda line: results.append(line), exit_handler=lambda exit_code: results.append(exit_code), valid_exitcodes=[123] ) self.assertEqual(results, ["line1", "line2", 123 ]) with self.subTest("remote"): test(ExecuteNode(ssh_to="localhost", debug_output=True)) # with self.subTest("local"): test(ExecuteNode(debug_output=True)) def test_script_defaults(self): result=[] nodea=ExecuteNode(debug_output=True) nodea.script(lines=["echo test"], stdout_handler=lambda line: result.append(line)) self.assertEqual(result, ["test"]) def test_script_pipe(self): result=[] nodea=ExecuteNode() cmd_pipe=nodea.script(lines=["echo test"], pipe=True) nodea.script(lines=["tr e E"], inp=cmd_pipe,stdout_handler=lambda line: result.append(line)) self.assertEqual(result, ["tEst"]) def test_mixed(self): #should be able to mix run() and script() node=ExecuteNode() result=[] pipe=node.run(["echo", "test"], pipe=True) node.script(["tr e E"], inp=pipe, stdout_handler=lambda line: result.append(line)) self.assertEqual(result, ["tEst"])