#!/usr/local/cpython-3.5/bin/python3

'''Tests for just_one.py'''

from __future__ import print_function

import os
import sys

from unittest import mock # pylint: disable=no-name-in-module

import just_one


def silent_unlink(string):
    '''Unlink the pid file. If it does not yet exist, do not complain'''
    directory = just_one.get_just_one_dir()

    filename = os.path.join(directory, string)

    try:
        os.unlink(filename)
    except (OSError, IOError):
        pass


def create_file(string, pid):
    '''Create the pid file'''
    directory = just_one.get_just_one_dir()

    filename = os.path.join(directory, string)

    with open(filename, 'w') as file_:
        file_.write('{}\n'.format(pid))


def test_start_command_true():
    '''Test start_command'''

    all_good = True

    exit_code = just_one.start_command(verbose=False, command='/bin/true', filename='/tmp/foo')

    if exit_code != 0:
        sys.stderr.write('{}: test_start_command_true: exit_code nonzero: {}\n'.format(sys.argv[0], exit_code))
        all_good = False

    return all_good


def test_start_command_false():
    '''Test start_command'''

    all_good = True

    exit_code = just_one.start_command(verbose=False, command='/bin/false', filename='/tmp/foo')

    if exit_code == 0:
        sys.stderr.write('{}: test_start_command_false: exit_code zero: {}\n'.format(sys.argv[0], exit_code))
        all_good = False

    return all_good


def test_no_preexisting_file():
    '''Test with no preexisting file'''
    all_good = True
    string = 'sleep'
    silent_unlink(string=string)

    with \
            mock.patch('just_one.subprocess.call', autospec=just_one.subprocess.call) as call_mock, \
            mock.patch('just_one.subprocess.Popen', mock.Mock(spec_set=just_one.subprocess.Popen)) as popen_mock \
        :
        _unused_exit_code = just_one.run_one(verbose=False, command='sleep 1', string=string)

    if call_mock.call_count != 0:
        sys.stderr.write('{}: test_no_preexisting_file: call_mock.call_count is {}, should be 0\n'.format(
            sys.argv[0],
            call_mock.call_count,
            ))
        all_good = False

    if popen_mock.call_count != 1:
        sys.stderr.write('{}: test_no_preexisting_file: popen.call_count is {}, should be 1\n'.format(
            sys.argv[0],
            popen_mock.call_count,
            ))
        all_good = False

    return all_good


def test_file_extent_pid_not():
    '''Test with pid nonexistent and successful command start'''
    all_good = True
    string = 'sleep'

    # We use a pid that should never exit on a typical Linux system
    create_file(string=string, pid=9999999)

    with \
            mock.patch('just_one.subprocess.call', mock.Mock(spec_set=just_one.subprocess.call, side_effect=[1])) as call_mock, \
            mock.patch('just_one.subprocess.Popen', mock.Mock(spec_set=just_one.subprocess.Popen)) as popen_mock \
        :
        _unused_exit_code = just_one.run_one(verbose=False, command='sleep 1', string=string)

    if call_mock.call_count != 1:
        sys.stderr.write('{}: test_no_preexisting_file: call_mock.call_count is {}, should be 1\n'.format(
            sys.argv[0],
            call_mock.call_count,
            ))
        all_good = False

    if popen_mock.call_count != 1:
        sys.stderr.write('{}: test_no_preexisting_file: popen.call_count is {}, should be 1\n'.format(
            sys.argv[0],
            popen_mock.call_count,
            ))
        all_good = False

    return all_good


def test_file_and_pid_extent():
    '''Test with file and pid existent'''
    all_good = True
    string = 'sleep'

    # pid 1 should always exist on a Linux/Unix system - it's init
    create_file(string=string, pid=1)

    with \
            mock.patch('just_one.subprocess.call', mock.Mock(spec_set=just_one.subprocess.call, side_effect=[0])) as call_mock, \
            mock.patch('just_one.subprocess.Popen', mock.Mock(spec_set=just_one.subprocess.Popen)) as popen_mock, \
            mock.patch('just_one.sys.stderr.write') \
        :
        _unused_exit_code = just_one.run_one(verbose=False, command='sleep 1', string=string)

    if call_mock.call_count != 1:
        sys.stderr.write('{}: test_no_preexisting_file: call_mock.call_count is {}, should be 1\n'.format(
            sys.argv[0],
            call_mock.call_count,
            ))
        all_good = False

    if popen_mock.call_count != 0:
        sys.stderr.write('{}: test_no_preexisting_file: popen.call_count is {}, should be 0\n'.format(
            sys.argv[0],
            popen_mock.call_count,
            ))
        all_good = False

    return all_good


def test_run_one_true():
    '''Test with no lock and running /bin/true'''
    all_good = True
    string = 'true'

    silent_unlink(string=string)

    exit_code = just_one.run_one(verbose=False, command='/bin/true', string=string)

    if exit_code:
        sys.stderr.write('{}: true returned false\n'.format(sys.argv[0]))
        all_good = False

    return all_good


def test_run_one_false():
    '''Test with no lock and running /bin/false'''
    all_good = True
    string = 'false'

    silent_unlink(string=string)

    exit_code = just_one.run_one(verbose=False, command='/bin/false', string=string)

    if not exit_code:
        sys.stderr.write('{}: false returned true\n'.format(sys.argv[0]))
        all_good = False

    return all_good


def test_pid_exists_always():
    '''Test pid_exits with an always-extent pid'''

    all_good = True

    retval = just_one.pid_exists(verbose=False, pid='1')

    if not retval:
        sys.stderr.write('{}: pid_exists(1) returned bad value: {}\n'.format(sys.argv[0], retval))
        all_good = False

    return all_good


def test_pid_exists_never():
    '''Test pid_exits with a never-extent pid'''

    all_good = True

    retval = just_one.pid_exists(verbose=False, pid='9999999')

    if retval:
        sys.stderr.write('{}: pid_exists(9999999) returned bad value: {}\n'.format(sys.argv[0], retval))
        all_good = False

    return all_good


def main():
    '''Main function'''

    all_good = True
    all_good &= test_no_preexisting_file()
    all_good &= test_file_extent_pid_not()
    all_good &= test_file_and_pid_extent()
    all_good &= test_run_one_true()
    all_good &= test_run_one_false()
    all_good &= test_start_command_true()
    all_good &= test_start_command_false()
    all_good &= test_pid_exists_always()
    all_good &= test_pid_exists_never()

    if all_good:
        sys.exit(0)
    else:
        sys.stderr.write('{}: One or more tests failed\n'.format(sys.argv[0]))
        sys.exit(1)


main()