#!/usr/share/ucs-test/runner python3
## desc: Checks if Apps are installed correctly
## tags: [SKIP-UCSSCHOOL, basic, apptest]
## roles-not: [basesystem]
## packages:
##   - univention-directory-manager-tools
##   - univention-management-console-module-appcenter
## exposure: safe

from __future__ import print_function
import subprocess

import univention.testing.utils as utils
from appcentertest import get_requested_apps
from univention.appcenter.app_cache import Apps
from univention.appcenter.ucr import ucr_get

import requests
import lxml.html

# Suppress InsecureRequestWarning: Unverified HTTPS request
import urllib3
urllib3.disable_warnings()


def check_status(app):
	if app.docker:
		print('    Checking running Docker Container')
		assert ucr_get('appcenter/apps/%s/status' % app.id) == 'installed'
		container = ucr_get('appcenter/apps/%s/container' % app.id)
		output = subprocess.check_output(['docker', 'inspect', '-f', '{{.State.Running}}', container]).decode().rstrip('\n')
		if output != 'true':
			utils.fail('ERROR: Container not running!')
		if app.docker_image and app.docker_image.startswith('docker.software-univention.de/ucs-appbox-amd64:'):
			print('    Within container, checking packages', ', '.join(app.default_packages))
			output = subprocess.check_output(['univention-app', 'shell', app.id, 'dpkg', '-s'] + app.default_packages, stderr=subprocess.STDOUT).decode('utf-8')
			for line in output.splitlines():
				if line.startswith('Status: '):
					if line != 'Status: install ok installed':
						print(output)
						utils.fail('ERROR: A package is not installed!')
		else:
			print('    No appbox image, not checking packages')
	else:
		packages = app.default_packages
		if ucr_get('server/role') in ['domaincontroller_master', 'domaincontroller_backup']:
			packages.extend(app.default_packages_master)
		print('    Checking packages', ', '.join(packages))
		output = subprocess.check_output(['dpkg', '-s'] + packages, stderr=subprocess.STDOUT).decode('utf-8')
		for line in output.splitlines():
			if line.startswith('Status: '):
				if line != 'Status: install ok installed':
					print(output)
					utils.fail('ERROR: A package is not installed!')


def check_ldap(app, apps):
	dn = 'univentionAppID=%s_%s,cn=%s,cn=apps,cn=univention,%s' % (app.id, app.version, app.id, ucr_get('ldap/base'))
	utils.verify_ldap_object(dn, {'univentionAppVersion': [app.version]})
	utils.verify_ldap_object(dn, {'univentionAppName': ['[en] %s' % app.name], 'univentionAppInstalledOnServer': ['%s.%s' % (ucr_get('hostname'), ucr_get('domainname'))]}, strict=False)
	for app_version in apps.get_all_apps_with_id(app.id):
		if app_version == app:
			continue
		dn = 'univentionAppID=%s_%s,cn=%s,cn=apps,cn=univention,%s' % (app_version.id, app_version.version, app_version.id, ucr_get('ldap/base'))
		utils.verify_ldap_object(dn, should_exist=False)


def check_webinterface(app):
	if not app.web_interface:
		print('    Skipping Webinterface check')
		return
	print('    Webinterface for', app)
	if app.has_local_web_interface():
		fqdn = '%s.%s' % (ucr_get('hostname'), ucr_get('domainname'))
		if app.web_interface_port_http:
			port = app.web_interface_port_http
			if app.auto_mod_proxy:
				port = 80
			if port != 80:
				port = ':%d' % port
			else:
				port = ''
			url = 'http://%s%s%s' % (fqdn, port, app.web_interface)
			_check_url(url)
		if app.web_interface_port_https:
			port = app.web_interface_port_https
			if app.auto_mod_proxy:
				port = 443
			if port != 443:
				port = ':%d' % port
			else:
				port = ''
			url = 'https://%s%s%s' % (fqdn, port, app.web_interface)
			_check_url(url)
	else:
		_check_url(app.web_interface)


def _check_url(url):
	print('       Checking', url)
	requests_timeout = 30
	r = requests.get(url, timeout=requests_timeout, verify=False)
	print('       ...', r.status_code)
	if r.status_code not in [401, 403]:
		assert not str(r.status_code).startswith(('4', '5'))
	print('       ...', r.url)
	url = r.url

	# check meta refresh
	soup = lxml.html.fromstring(r.text)
	refresh = soup.cssselect('meta[http-equiv="refresh"]')
	if refresh:
		refresh_url = refresh[0].get('content')
		if refresh_url:
			print('Found meta refresh: %s' % refresh_url)
			# e.g., 0;URL=controller.pl?action=LoginScreen/user_login
			index = refresh_url.lower().find('url=')
			if index > 0:
				refresh_url = refresh_url[index + 4:]
				if not refresh_url.lower().startswith('http'):
					refresh_url = '%s%s' % (url, refresh_url)
				_check_url(refresh_url)


apps = Apps()
for app in get_requested_apps():
	print('Checking', app)
	if not app._allowed_on_local_server():
		print('    Not allowed ... skipping')
		continue
	check_status(app)
	check_ldap(app, apps)
	check_webinterface(app)
