#!/usr/share/ucs-test/runner python3
## desc: Check cron job script lock_expired_accounts
## roles: [domaincontroller_master]
## exposure: dangerous
## packages: [univention-directory-manager-tools]
## bugs: [35088]

from __future__ import print_function
from datetime import datetime, timedelta
import univention.admin.uldap
import univention.admin.modules as udm_modules
import univention.testing.udm as udm_test
import univention.testing.utils as utils
import atexit
import pprint
import subprocess
import time


def main():

	# Since the S4 connector uses a object based synchronization,
	# it is a problem to change the same object in short intervals,
	# see https://forge.univention.org/bugzilla/show_bug.cgi?id=35336
	if utils.s4connector_present():
		atexit.register(utils.start_s4connector)
		utils.stop_s4connector()

	print(time.ctime())
	with udm_test.UCSTestUDM() as udm:
		udm_modules.update()
		lo, position = univention.admin.uldap.getAdminConnection()
		udm_modules.init(lo, position, udm_modules.get('users/user'))

		def create_user(expiry_days_delta, locked_status):
			expiry_time = datetime.utcnow() + timedelta(days=expiry_days_delta)
			userdn, username = udm.create_user(userexpiry=expiry_time.strftime("%Y-%m-%d"), check_for_drs_replication=False, wait_for=False)
			if locked_status == '1':
				locktime = time.strftime("%Y%m%d%H%M%SZ", time.gmtime())
				subprocess.check_call(['python', '-m', 'univention.lib.account', 'lock', '--dn', userdn, '--lock-time', locktime])
			return username

		userdata = {}
		for delta, initial_state, expected_state in [
			[-9, '0', '0'],
			[-8, '0', '0'],
			# [-7, '0', '0'],  disabled due to bug #36210
			# [-6, '0', '1'],  disabled due to bug #36210
			[-5, '0', '1'],
			[-4, '0', '1'],
			[-3, '0', '1'],
			[-2, '0', '1'],
			[-1, '0', '1'],
			# [0, '0', '1'],  disabled due to bug #36210
			[1, '0', '0'],
			[2, '0', '0'],
			[-4, '1', '1'],
			# [0, '1', '1'],  disabled due to bug #36210
			[2, '1', '1'],
		]:
			userdata[create_user(delta, initial_state)] = [initial_state, expected_state]

		ldap_filter = '(|(uid=' + ')(uid='.join(userdata.keys()) + '))'

		results = udm_modules.lookup('users/user', None, lo, scope='sub', filter=ldap_filter)
		if len(results) != len(userdata):
			print('RESULTS: %r' % (pprint.PrettyPrinter(indent=2).pformat(results),))
			utils.fail('Did not find all users prior to script execution!')
		for entry in results:
			entry.open()
			if not entry['locked'] == userdata[entry['username']][0]:
				utils.fail('uid=%s should not be locked for posix prior to script execution!' % (entry['username'],))

		print('Calling lock_expired_accounts...')
		subprocess.check_call(['/usr/share/univention-directory-manager-tools/lock_expired_accounts', '--only-last-week'])
		print('DONE')

		results = udm_modules.lookup('users/user', None, lo, scope='sub', filter=ldap_filter)
		if len(results) != len(userdata):
			print('RESULTS: %r' % (pprint.PrettyPrinter(indent=2).pformat(results),))
			utils.fail('Did not find all users after script execution!')
		for entry in results:
			entry.open()
			if not entry['locked'] == userdata[entry['username']][1]:
				utils.fail('The account uid=%r is not in expected locking state: expected=%r  current=%r' % (entry['username'], userdata[entry['username']][1], entry['locked']))


if __name__ == '__main__':
	main()
