# -*- coding: utf-8 -*-

from pytest import raises
from os import makedirs, remove, removedirs, getpid
from sys import exit
from os.path import isfile, join, isdir
from glob import glob
import stat

from pyeole import lock

lock.LOCK_PATH = '/tmp/test_lock'
lock.LOCK_SYSTEM_PATH = '/tmp/test_lock/eole-system'
OTHERPID=1
PID = lock.PID

file_test = join(lock.LOCK_PATH, 'test.{}'.format(lock.PID))
file_system_test = join(lock.LOCK_SYSTEM_PATH, 'test.{}'.format(
        lock.PID))
file_test_other = join(lock.LOCK_PATH, 'test.{}'.format(OTHERPID))
file_system_test_other = join(lock.LOCK_SYSTEM_PATH, 'test.{}'.format(
        OTHERPID))

file2_test = join(lock.LOCK_PATH, 'test2.{}'.format(lock.PID))
file2_system_test = join(lock.LOCK_SYSTEM_PATH, 'test2.{}'.format(
        lock.PID))

if isdir(lock.LOCK_PATH):
    print('{} already exists !'.format(lock.LOCK_PATH))
    exit(1)

def setup_function(function):
    lock.PID = getpid()
    makedirs(lock.LOCK_SYSTEM_PATH)

def teardown_function(function):
    for file_ in glob(lock.LOCK_SYSTEM_PATH+'/*'):
        remove(file_)
    for file_ in glob(lock.LOCK_PATH+'/*'):
        if not isdir(file_):
            remove(file_)
        else:
            removedirs(file_)

######################################################################
# acquire
######################################################################

def test_lock():
    assert not isfile(file_test)
    lock.acquire('test')
    assert isfile(file_test)

def test_two_locks():
    assert not isfile(file_test)
    assert not isfile(file2_test)
    lock.acquire('test')
    lock.acquire('test2')
    assert isfile(file_test)
    assert isfile(file2_test)

def test_lock_system():
    assert not isfile(file_system_test)
    lock.acquire('test', level='system')
    assert isfile(file_system_test)

def test_two_locks_system():
    assert not isfile(file_system_test)
    assert not isfile(file2_system_test)
    lock.acquire('test', level='system')
    with raises(lock.AlreadyLocked):
        lock.acquire('test2', level='system')
    assert isfile(file_system_test)
    assert not isfile(file2_system_test)

def test_two_locks_system_not_valid():
    assert not isfile(file_system_test)
    assert not isfile(file2_system_test)
    lock.acquire('test', level='system')
    lock.acquire('test2', level='system', valid=False)
    assert isfile(file_system_test)
    assert isfile(file2_system_test)

def test_lock_valid():
    lock.acquire('test')
    with raises(lock.AlreadyLocked):
        lock.acquire('test')

def test_lock_not_valid():
    lock.acquire('test')
    lock.acquire('test', valid=False)

def test_lock_system_valid():
    lock.acquire('test', level='system')
    with raises(lock.AlreadyLocked):
        lock.acquire('test', level='system')

def test_lock_system_not_valid():
    lock.acquire('test', level='system')
    lock.acquire('test', valid=False, level='system')

def test_lock_normal_system():
    lock.acquire('test')
    lock.acquire('test', level='system')

######################################################################
# release
######################################################################

def test_release():
    lock.acquire('test')
    assert isfile(file_test)
    lock.release('test')
    assert not isfile(file_test)

def test_release_two_locks():
    lock.acquire('test')
    lock.acquire('test2')
    assert isfile(file_test)
    assert isfile(file2_test)
    lock.release('test')
    lock.release('test2')
    assert not isfile(file_test)
    assert not isfile(file2_test)

def test_release_system():
    lock.acquire('test', level='system')
    assert isfile(file_system_test)
    lock.release('test', level='system')
    assert not isfile(file_system_test)

def test_release_valid():
    lock.acquire('test')
    lock.release('test')
    with raises(lock.NotLocked):
        lock.release('test')

def test_release_not_valid():
    lock.acquire('test')
    lock.release('test')
    lock.release('test', valid=False)

def test_release_not_valid_release():
    assert not isfile(file_test)
    lock.release('test', valid=False)
    assert not isfile(file_test)

def test_release_system_valid():
    lock.acquire('test', level='system')
    lock.release('test', level='system')
    with raises(lock.NotLocked):
        lock.release('test', level='system')

def test_release_system_not_valid():
    lock.acquire('test', level='system')
    lock.release('test', level='system')
    lock.release('test', level='system', valid=False)

def test_release_system_not_valid_release():
    assert not isfile(file_test)
    lock.release('test', valid=False, level='system')
    assert not isfile(file_test)

def test_release_normal_system():
    lock.acquire('test')
    lock.acquire('test', level='system')
    assert isfile(file_test)
    assert isfile(file_system_test)
    lock.release('test')
    lock.release('test', level='system')
    assert not isfile(file_test)
    assert not isfile(file_system_test)

def test_two_releases_system_not_valid():
    lock.acquire('test', level='system')
    lock.acquire('test2', level='system', valid=False)
    assert isfile(file_system_test)
    assert isfile(file2_system_test)
    lock.release('test', level='system', valid=False)
    lock.release('test2', level='system')
    assert not isfile(file_system_test)
    assert not isfile(file2_system_test)

def test_acquire_invalid_name():
    with raises(ValueError):
        lock.acquire('test.')

def test_acquire_invalid_level():
    with raises(ValueError):
        lock.acquire('test', level='notvalid')

def test_release_invalid_name():
    with raises(ValueError):
        lock.release('test.')

def test_release_invalid_level():
    with raises(ValueError):
        lock.release('test', level='notvalid')

######################################################################
# multi pid
######################################################################

def test_acquire_pid():
    lock.acquire('test')
    lock.PID = OTHERPID
    with raises(lock.AlreadyLocked):
        lock.acquire('test')

def test_acquire_not_valid_pid():
    lock.acquire('test')
    assert isfile(file_test)
    assert not isfile(file_test_other)
    lock.PID = OTHERPID
    lock.acquire('test', valid=False)
    assert not isfile(file_test)
    assert isfile(file_test_other)

def test_acquire_not_force_pid():
    lock.acquire('test')
    assert isfile(file_test)
    assert not isfile(file_test_other)
    lock.PID = OTHERPID
    lock.acquire('test', valid=False)
    assert not isfile(file_test)
    assert isfile(file_test_other)

def test_system_acquire_pid():
    lock.acquire('test', level='system')
    lock.PID = OTHERPID
    with raises(lock.AlreadyLocked):
        lock.acquire('test', level='system')

def test_system_acquire_pid_not_valid():
    lock.acquire('test', level='system')
    assert isfile(file_system_test)
    assert not isfile(file_system_test_other)
    lock.PID = OTHERPID
    lock.acquire('test', valid=False, level='system')
    assert not isfile(file_system_test)
    assert isfile(file_system_test_other)

def test_release_pid():
    lock.acquire('test')
    lock.PID = OTHERPID
    with raises(lock.NotMyLock):
        lock.release('test')

def test_release_not_valid_pid():
    lock.acquire('test')
    assert isfile(file_test)
    lock.PID = OTHERPID
    with raises(lock.NotMyLock):
        lock.release('test', valid=False)
    assert isfile(file_test)

def test_release_force_pid():
    lock.acquire('test')
    assert isfile(file_test)
    lock.PID = OTHERPID
    lock.release('test', force=True)
    assert not isfile(file_test)

def test_system_release_pid():
    lock.acquire('test', level='system')
    lock.PID = OTHERPID
    with raises(lock.AlreadyLocked):
        lock.acquire('test', level='system')

def test_system_release_not_valid_pid():
    lock.acquire('test', level='system')
    assert isfile(file_system_test)
    lock.PID = OTHERPID
    with raises(lock.NotMyLock):
        lock.release('test', valid=False, level='system')
    assert isfile(file_system_test)

def test_system_release_force_pid():
    lock.acquire('test', level='system')
    assert isfile(file_system_test)
    lock.PID = OTHERPID
    lock.release('test', force=True, level='system')
    assert not isfile(file_system_test)

######################################################################
# is locked
######################################################################

def test_is_locked_false():
    assert lock.is_locked('test') == False

def test_is_locked_true():
    lock.acquire('test')
    assert lock.is_locked('test') == True

def test_is_locked_system_false():
    assert lock.is_locked('test', level='system') == False

def test_is_locked_system_true():
    lock.acquire('test', level='system')
    assert lock.is_locked('test', level='system') == True

def test_is_locked_not_system_true():
    lock.acquire('test', level='system')
    assert lock.is_locked('test') == False

def test_is_locked_not_normal_true():
    lock.acquire('test')
    assert lock.is_locked('test', level='system') == False

def test_is_locked_other_pid():
    lock.acquire('test')
    lock.PID = OTHERPID
    assert lock.is_locked('test') == True

def test_is_locked_other_pid():
    lock.acquire('test', level='system')
    lock.PID = OTHERPID
    assert lock.is_locked('test', level='system') == True

def test_is_locked_invalid_name():
    with raises(ValueError):
        lock.is_locked('test.')

def test_is_locked_invalid_level():
    with raises(ValueError):
        lock.is_locked('test', level='notvalid')

######################################################################
# get system lock name
######################################################################

def test_get_system_lock_name():
    assert lock.get_system_lock_name() == []

def test_get_system_lock_name_one():
    lock.acquire('test', level='system')
    lock.get_system_lock_name() == ['test']

def test_get_system_lock_name_two():
    lock.acquire('test', level='system')
    lock.acquire('test2', level='system', valid=False)
    lock.get_system_lock_name() == ['test', 'test2']

def test_get_system_lock_name_one_name():
    lock.acquire('test', level='system')
    lock.get_system_lock_name('test') == []

def test_get_system_lock_name_two_name():
    lock.acquire('test', level='system')
    lock.acquire('test2', level='system', valid=False)
    lock.get_system_lock_name('test') == ['test2']
def test_get_system_lock_not_system():
    lock.acquire('test')
    lock.get_system_lock_name() == []

def test_is_locked_invalid_name():
    with raises(ValueError):
        lock.get_system_lock_name('test.')

