#!/usr/share/ucs-test/runner python3
## desc: Test changing disabled and locked simultaneously
## tags: [udm]
## roles: [domaincontroller_master]
## exposure: dangerous
## packages:
##   - univention-directory-manager-tools

from __future__ import print_function
import subprocess
import random
import time
import univention.admin.uldap
import univention.testing.ucr as ucr_test
import univention.testing.udm as udm_test
import univention.testing.utils as utils


disabled_states = ('1', '0')
locked_states = ['0', '1']

with ucr_test.UCSTestConfigRegistry() as ucr:
	ldap_base = ucr['ldap/base']
lo, pos = univention.admin.uldap.getMachineConnection(ldap_master=False)
transitions_log = list()


def print_transitions():
	print('    disabled         | locked   -> disabled         | locked')
	print('------------------------------------------------------------')
	print('\n'.join(transitions_log))
	print('{} transitions tested.\n'.format(len(transitions_log)))


def fail(msg):
	print_transitions()
	utils.fail(msg)


def modify_and_check(udm, dn, disabled_state, locked_state):
	print('*** disabled_state={!r} locked_state={!r}'.format(disabled_state, locked_state))
	if dn:
		locked = {}
		if locked_state == '0':
			locked['locked'] = '0'
		udm.modify_object('users/user', dn=dn, disabled=disabled_state, **locked)
		if locked_state == '1':
			locktime = time.strftime("%Y%m%d%H%M%SZ", time.gmtime())
			subprocess.call(['python', '-m', 'univention.lib.account', 'lock', '--dn', dn, '--lock-time', locktime])
	else:
		dn, username = udm.create_user(
			position='cn=users,{}'.format(ldap_base),
			disabled=disabled_state,
		)
		if locked_state == '1':
			locktime = time.strftime("%Y%m%d%H%M%SZ", time.gmtime())
			subprocess.call(['python', '-m', 'univention.lib.account', 'lock', '--dn', dn, '--lock-time', locktime])

	krb_state = b'254' if disabled_state == '1' or 'kerberos' in disabled_state else b'126'
	smb_disabled = disabled_state == '1' or 'windows' in disabled_state
	smb_locked = locked_state in ('1')
	if transitions_log:
		transitions_log[-1] += ' -> {:16} | {:8}'.format(disabled_state, locked_state)

	# length of whitespace in sambaAcctFlags varies. cannot use utils.verify_ldap_object() to test it

	user = lo.get(dn)
	if user['krb5KDCFlags'] != [krb_state]:
		fail('krb5KDCFlags: expected {!r} found {!r}'.format(krb_state, user['krb5KDCFlags']))
	if smb_disabled and b'D' not in user['sambaAcctFlags'][0]:
		fail('sambaAcctFlags: expected D in flags, found {!r}'.format(user['sambaAcctFlags']))
	if (smb_locked and not smb_disabled) and b'L' not in user['sambaAcctFlags'][0]:
		fail('sambaAcctFlags: expected L in flags, found {!r}'.format(user['sambaAcctFlags']))
	if (smb_locked and smb_disabled) and b'L' in user['sambaAcctFlags'][0]:
		fail('sambaAcctFlags: unexpected L in flags: {!r}'.format(user['sambaAcctFlags']))
	if (disabled_state == '1' or 'posix' in disabled_state) and user['shadowExpire'][0] != b'1':
		fail('shadowExpire: expected {!r} found {!r}'.format(['1'], user['shadowExpire']))
	print('*** OK.')
	if transitions_log:
		transitions_log[-1] = 'OK: {}'.format(transitions_log[-1])
	transitions_log.append('{:16} | {:8}'.format(disabled_state, locked_state))
	return dn


if __name__ == '__main__':
	with udm_test.UCSTestUDM() as udm:
		user_dn = None
		locked_state2 = locked_states.pop(random.randint(0, len(locked_states) - 1))
		while locked_states:
			locked_state1 = locked_states.pop(random.randint(0, len(locked_states) - 1))
			disabled_states_list = list(disabled_states)
			disabled_state1 = disabled_states_list.pop(random.randint(0, len(disabled_states_list) - 1))
			user_dn = modify_and_check(udm, user_dn, disabled_state1, locked_state1)
			while disabled_states_list:
				disabled_state2 = disabled_states_list.pop(random.randint(0, len(disabled_states_list) - 1))
				modify_and_check(udm, user_dn, disabled_state2, locked_state2)
				modify_and_check(udm, user_dn, disabled_state1, locked_state1)

	transitions_log.pop(-1)
	print_transitions()
