"""Test the pre-kill hook on Darwin."""
from __future__ import print_function

# system imports
from multiprocessing import Process, Queue
import platform
import re
from unittest import main, TestCase

# third party
from six import StringIO


def do_child_process(child_work_queue, parent_work_queue, verbose):
    import os

    pid = os.getpid()
    if verbose:
        print("child: pid {} started, sending to parent".format(pid))
    parent_work_queue.put(pid)
    if verbose:
        print("child: waiting for shut-down request from parent")
    child_work_queue.get()
    if verbose:
        print("child: received shut-down request.  Child exiting.")


class DarwinPreKillTestCase(TestCase):

    def __init__(self, methodName):
        super(DarwinPreKillTestCase, self).__init__(methodName)
        self.process = None
        self.child_work_queue = None
        self.verbose = False

    def tearDown(self):
        if self.verbose:
            print("parent: sending shut-down request to child")
        if self.process:
            self.child_work_queue.put("hello, child")
            self.process.join()
        if self.verbose:
            print("parent: child is fully shut down")

    def test_sample(self):
        # Ensure we're Darwin.
        if platform.system() != 'Darwin':
            self.skipTest("requires a Darwin-based OS")

        # Start the child process.
        self.child_work_queue = Queue()
        parent_work_queue = Queue()
        self.process = Process(target=do_child_process,
                               args=(self.child_work_queue, parent_work_queue,
                                     self.verbose))
        if self.verbose:
            print("parent: starting child")
        self.process.start()

        # Wait for the child to report its pid.  Then we know we're running.
        if self.verbose:
            print("parent: waiting for child to start")
        child_pid = parent_work_queue.get()

        # Sample the child process.
        from darwin import do_pre_kill
        context_dict = {
            "archs": [platform.machine()],
            "platform_name": None,
            "platform_url": None,
            "platform_working_dir": None
        }

        if self.verbose:
            print("parent: running pre-kill action on child")
        output_io = StringIO()
        do_pre_kill(child_pid, context_dict, output_io)
        output = output_io.getvalue()

        if self.verbose:
            print("parent: do_pre_kill() wrote the following output:", output)
        self.assertIsNotNone(output)

        # We should have a line with:
        # Process:  .* [{pid}]
        process_re = re.compile(r"Process:[^[]+\[([^]]+)\]")
        match = process_re.search(output)
        self.assertIsNotNone(match, "should have found process id for "
                             "sampled process")
        self.assertEqual(1, len(match.groups()))
        self.assertEqual(child_pid, int(match.group(1)))

        # We should see a Call graph: section.
        callgraph_re = re.compile(r"Call graph:")
        match = callgraph_re.search(output)
        self.assertIsNotNone(match, "should have found the Call graph section"
                             "in sample output")

        # We should see a Binary Images: section.
        binary_images_re = re.compile(r"Binary Images:")
        match = binary_images_re.search(output)
        self.assertIsNotNone(match, "should have found the Binary Images "
                             "section in sample output")


if __name__ == "__main__":
    main()
