示例#1
0
    def test_run_pipe_it_should_not_log_by_default(self):
        self.__it_should_not_log_by_default(lambda: shellutil.run_pipe([
            ["date"], [self.__create_tee_script(return_code=1)]
        ]))  # Raises a CommandError

        self.__it_should_not_log_by_default(lambda: shellutil.run_pipe(
            [["date"], ["nonexistent_command"]]))  # Raises an OSError
示例#2
0
    def test_run_pipe_should_capture_the_stderr_of_all_the_commands_in_the_pipe(
            self):
        with self.assertRaises(shellutil.CommandError) as context_manager:
            shellutil.run_pipe([["echo", "TEST STRING"],
                                [self.__create_tee_script()],
                                [self.__create_tee_script()],
                                [self.__create_tee_script(return_code=1)]])

        self.assertEqual(
            "TEST STRING\n" * 3, context_manager.exception.stderr,
            "Expected 3 copies of the test string since there are 3 commands in the pipe"
        )
示例#3
0
    def test_run_pipe_should_raise_an_exception_when_the_last_command_fails(
            self):
        tee_script = self.__create_tee_script(return_code=1)

        self.__it_should_raise_an_exception_when_the_command_fails(
            lambda: shellutil.run_pipe([["echo", "-n", "TEST_STRING\n"],
                                        [tee_script]]))
示例#4
0
    def test_run_pipe_should_return_a_string_by_default(self):
        output = shellutil.run_pipe([["echo", "TEST STRING"],
                                     [self.__create_tee_script()]])

        self.assertTrue(
            isinstance(output, ustr),
            "The return value should be a string. Got: '{0}'".format(
                type(output)))
示例#5
0
    def test_run_pipe_should_execute_a_pipe_with_two_commands(self):
        # Output the same string 3 times and then remove duplicates
        test_string = "A TEST STRING\n"
        pipe = [["echo", "-n", "-e", test_string * 3], ["uniq"]]

        output = shellutil.run_pipe(pipe)

        self.assertEqual(output, test_string)
示例#6
0
    def test_run_pipe_should_return_a_bytes_object_when_encode_output_is_false(
            self):
        output = shellutil.run_pipe(
            [["echo", "TEST STRING"], [self.__create_tee_script()]],
            encode_output=False)

        self.assertTrue(
            isinstance(output, bytes),
            "The return value should be a bytes object. Got: '{0}'".format(
                type(output)))
示例#7
0
    def test_run_pipe_should_execute_a_pipe_with_more_than_two_commands(self):
        #
        # The test pipe splits the output of "ls" in lines and then greps for "."
        #
        # Sample output of "ls -d .":
        #     drwxrwxr-x 13 nam nam 4096 Nov 13 16:54 .
        #
        pipe = [["ls", "-ld", "."], ["sed", "-r", "s/\\s+/\\n/g"],
                ["grep", "\\."]]

        output = shellutil.run_pipe(pipe)

        self.assertEqual(
            ".\n", output,
            "The pipe did not produce the expected output. Got: {0}".format(
                output))
示例#8
0
    def test_run_command_run_pipe_run_get_output_should_keep_track_of_the_running_commands(
            self):
        # The children processes run this script, which creates a file with the PIDs of the script and its parent and then sleeps for a long time
        child_script = os.path.join(self.tmp_dir, "write_pids.py")
        AgentTestCase.create_script(
            child_script, """
import os
import sys
import time

with open(sys.argv[1], "w") as pid_file:
    pid_file.write("{0} {1}".format(os.getpid(), os.getppid()))
time.sleep(120)
""")

        threads = []

        try:
            child_processes = []
            parent_processes = []

            try:
                # each of these files will contain the PIDs of the command that created it and its parent
                pid_files = [
                    os.path.join(self.tmp_dir, "pids.txt.{0}".format(i))
                    for i in range(4)
                ]

                # we test these functions in shellutil
                commands_to_execute = [
                    # run_get_output must be the first in this list; see the code to fetch the PIDs a few lines below
                    lambda: shellutil.run_get_output("{0} {1}".format(
                        child_script, pid_files[0])),
                    lambda: shellutil.run_command([child_script, pid_files[1]]
                                                  ),
                    lambda: shellutil.run_pipe([[child_script, pid_files[2]],
                                                [child_script, pid_files[3]]]),
                ]

                # start each command on a separate thread (since we need to examine the processes running the commands while they are running)
                def invoke(command):
                    try:
                        command()
                    except shellutil.CommandError as command_error:
                        if command_error.returncode != -9:  # test cleanup terminates the commands, so this is expected
                            raise

                for cmd in commands_to_execute:
                    thread = threading.Thread(target=invoke, args=(cmd, ))
                    thread.start()
                    threads.append(thread)

                # now fetch the PIDs in the files created by the commands, but wait until they are created
                if not wait_for(lambda: all(
                        os.path.exists(file) and os.path.getsize(file) > 0
                        for file in pid_files)):
                    raise Exception(
                        "The child processes did not start within the allowed timeout"
                    )

                for sig_file in pid_files:
                    with open(sig_file, "r") as read_handle:
                        pids = read_handle.read().split()
                        child_processes.append(int(pids[0]))
                        parent_processes.append(int(pids[1]))

                # the first item to in the PIDs we fetched corresponds to run_get_output, which invokes the command using the
                # shell, so in that case we need to use the parent's pid (i.e. the shell that we started)
                started_commands = parent_processes[0:1] + child_processes[1:]

                # wait for all the commands to start
                def all_commands_running():
                    all_commands_running.running_commands = shellutil.get_running_commands(
                    )
                    return len(
                        all_commands_running.running_commands
                    ) >= len(commands_to_execute
                             ) + 1  # +1 because run_pipe starts 2 commands

                all_commands_running.running_commands = []

                if not wait_for(all_commands_running):
                    self.fail(
                        "shellutil.get_running_commands() did not report the expected number of commands after the allowed timeout.\nExpected: {0}\nGot: {1}"
                        .format(
                            format_processes(started_commands),
                            format_processes(
                                all_commands_running.running_commands)))

                started_commands.sort()
                all_commands_running.running_commands.sort()

                self.assertEqual(
                    started_commands, all_commands_running.running_commands,
                    "shellutil.get_running_commands() did not return the expected commands.\nExpected: {0}\nGot: {1}"
                    .format(
                        format_processes(started_commands),
                        format_processes(
                            all_commands_running.running_commands)))

            finally:
                # terminate the child processes, since they are blocked
                for pid in child_processes:
                    os.kill(pid, signal.SIGKILL)

            # once the processes complete, their PIDs should go away
            def no_commands_running():
                no_commands_running.running_commands = shellutil.get_running_commands(
                )
                return len(no_commands_running.running_commands) == 0

            no_commands_running.running_commands = []

            if not wait_for(no_commands_running):
                self.fail(
                    "shellutil.get_running_commands() should return empty after the commands complete. Got: {0}"
                    .format(
                        format_processes(
                            no_commands_running.running_commands)))

        finally:
            for thread in threads:
                thread.join(timeout=5)
示例#9
0
 def test_run_pipe_should_write_the_command_error_output_to_the_stderr_parameter(
         self):
     self.__it_should_write_the_command_error_output_to_the_stderr_parameter(
         lambda stderr: shellutil.run_pipe([["echo", "TEST STRING"],
                                            [self.__create_tee_script()]],
                                           stderr=stderr))
示例#10
0
 def test_run_pipe_should_write_the_command_output_to_the_stdout_parameter(
         self):
     self.__it_should_write_the_command_output_to_the_stdout_parameter(
         lambda stdout: shellutil.run_pipe(
             [["echo", "TEST STRING"], ["sort"]], stdout=stdout))
示例#11
0
 def test_run_pipe_should_read_the_command_input_from_the_stdin_parameter(
         self):
     self.__it_should_read_the_command_input_from_the_stdin_parameter(
         lambda stdin: shellutil.run_pipe([["cat"], ["sort"]], stdin=stdin))
示例#12
0
 def test_run_pipe_should_raise_an_exception_when_it_cannot_execute_the_pipe(
         self):
     self.__it_should_raise_an_exception_when_it_cannot_execute_the_command(
         lambda: shellutil.run_pipe(
             [["ls", "-ld", "."], ["nonexistent_command"], ["wc", "-l"]]))