#!/usr/bin/python2

"""
This script exists to watch the test runner and maybe do a few maintainance
tasks in the future. Depending on the setup it may be started as a systemd
service at boottime or after some user interaction triggering the tests.

The following steps come to mind:

 * Start the testing process
 * Keep track of avocado running status across system failures
 * Collect crash information and resume test if the system rebootet. This
   requires avocado 50 and a custom module to write json results before
   a test is started
   (e.g. after a kernel panic)
 * Create result bundle
 * Submit the result bundle (might require user interaction)

"""


import os
import sys
import subprocess
import datetime
import shutil

import fed_laptoptest.session as session

# Grab from /etc/kdump.conf?
CRASHDIR = '/var/crash/'

STATEDIR = '/var/lib/fedora-laptop-testing/'
TESTSDIR = '/usr/share/fedora-laptop-testing/tests'
STARTFILE = os.path.join(STATEDIR, 'job-start')
STATEFILE = os.path.join(STATEDIR, 'job-running')
RESULTDIR = os.path.join(STATEDIR, 'job-results')
BUNDLEDIR = os.path.join(STATEDIR, 'result-bundles')

session._restore_config()

# Remove the one-time start indicator
try:
    os.unlink(STARTFILE)
except OSError:
    pass

def create_bundle(unmanaged=False):
    """Creates a new result bundle in the bundle directoy. Note that the
    creation happens with the directory name "new-bundle" which is then moved
    to the final name. This is done so that the handle for bundles will not
    see incomplete bundles.
    """
    latest = os.path.basename(os.readlink(os.path.join(RESULTDIR, 'latest')))
    tmpbundle = os.path.join(BUNDLEDIR, 'new-bundle')
    if os.path.exists(tmpbundle):
        shutil.rmtree(tmpbundle)

    bundle = os.path.join(BUNDLEDIR, latest)
    os.mkdir(tmpbundle)
    if os.path.exists(bundle):
        shutil.rmtree(bundle)

    for f in os.listdir(RESULTDIR):
        if f == 'latest':
            continue
        shutil.move(os.path.join(RESULTDIR, f), os.path.join(tmpbundle, f))

    if unmanaged:
        f = open(os.path.join(tmpbundle, 'unmanaged'), 'w')
        f.write('This result bundle was created from a manual run of avocado.\n')
        f.write('Result set may be incomplete or even for an unnofficial test\n')
        f.write('and should not be uploaded unless it is known to be a good\n')
        f.write('result set.\n')
        f.flush()

    # Include any kernel crash information if available, just include all
    # even though there may be multiple
    if os.path.isdir(CRASHDIR):
        for f in os.listdir(CRASHDIR):
            os.mkdir(os.path.join(tmpbundle, 'crashes'))
            shutil.move(os.path.join(CRASHDIR, f), os.path.join(tmpbundle, 'crashes', f))

    os.rename(tmpbundle, bundle)
    os.unlink(os.path.join(RESULTDIR, 'latest'))

# Avocado will update the link STATEDIR/job-results/latest immediately at
# startup.

# The purpose of this state file is to check that there are not results left
# over from an earlier run. This should only happen if avocado was run manually
# and wrote results into the result directory.
resume = False

if not os.path.exists(STATEFILE):
    # If there is no STATEFILE then the results directory be empty.
    # If it is not, then create a result bundle directory for it.
    if os.path.islink(os.path.join(RESULTDIR, 'latest')):
        create_bundle(unmanaged=True)

    assert not os.listdir(RESULTDIR), 'Expected %s to be empty at this point.' % RESULTDIR
else:
    resume = True

# Create STATEFILE if it does not exist, sync both file and containg directory
f = open(STATEFILE, 'w')
dfd = os.open(STATEDIR, os.O_RDONLY)
f.flush()
os.fsync(f)
os.fsync(dfd)
del f

if resume:
    # Requires Avocado version 50
    subprocess.call(['avocado', '--config', '/etc/avocado/fedora-laptop-testing.conf', 'run', '--replay', 'latest', '--replay-resume'])
else:
    subprocess.call(['avocado', '--config', '/etc/avocado/fedora-laptop-testing.conf', 'run', TESTSDIR])

session._restore_config()

# Test ran through in its entirety, so create a bundle and remove the STATEFILE
# so we know if a result set was generated by means other than this script
create_bundle()

# Remove state file, avocado run was completed (assume interruptions only
# happen because of system failures).
os.unlink(STATEFILE)
os.fsync(dfd)

subprocess.call(['fedora-laptop-testing-upload', '--run-session'])
session._restore_config()

subprocess.call(['systemctl', 'restart', 'gdm'])

