import datetime

import common
from autotest_lib.frontend import setup_test_environment
from autotest_lib.frontend import thread_local
from autotest_lib.frontend.afe import models, model_attributes
from autotest_lib.client.common_lib import global_config
from autotest_lib.client.common_lib.test_utils import mock

class FrontendTestMixin(object):
    # pylint: disable=missing-docstring
    def _fill_in_test_data(self):
        """Populate the test database with some hosts and labels."""
        if models.DroneSet.drone_sets_enabled():
            models.DroneSet.objects.create(
                    name=models.DroneSet.default_drone_set_name())

        acl_group = models.AclGroup.objects.create(name='my_acl')
        acl_group.users.add(models.User.current_user())

        self.hosts = [models.Host.objects.create(hostname=hostname)
                      for hostname in
                      ('host1', 'host2', 'host3', 'host4', 'host5', 'host6',
                       'host7', 'host8', 'host9')]

        acl_group.hosts = self.hosts
        models.AclGroup.smart_get('Everyone').hosts = []

        self.labels = [models.Label.objects.create(name=name) for name in
                       ('label1', 'label2', 'label3',
                        'label6', 'label7', 'unused')]

        platform = models.Label.objects.create(name='myplatform', platform=True)
        for host in self.hosts:
            host.labels.add(platform)

        self.label1, self.label2, self.label3, self.label6, self.label7, _ \
            = self.labels

        self.label3.only_if_needed = True
        self.label3.save()
        self.hosts[0].labels.add(self.label1)
        self.hosts[1].labels.add(self.label2)
        for hostnum in xrange(4,7):  # host5..host7
            self.hosts[hostnum].labels.add(self.label6)
        self.hosts[6].labels.add(self.label7)
        for hostnum in xrange(7,9):  # host8..host9
            self.hosts[hostnum].labels.add(self.label6)
            self.hosts[hostnum].labels.add(self.label7)


    def _frontend_common_setup(self, fill_data=True, setup_tables=True):
        self.god = mock.mock_god(ut=self)
        if setup_tables:
            setup_test_environment.set_up()
        global_config.global_config.override_config_value(
                'SERVER', 'rpc_logging', 'False')
        if fill_data and setup_tables:
            self._fill_in_test_data()


    def _frontend_common_teardown(self):
        setup_test_environment.tear_down()
        thread_local.set_user(None)
        self.god.unstub_all()


    def _create_job(self, hosts=[], metahosts=[], priority=0, active=False,
                    synchronous=False, hostless=False,
                    drone_set=None, control_file='control',
                    owner='autotest_system', parent_job_id=None):
        """
        Create a job row in the test database.

        @param hosts - A list of explicit host ids for this job to be
                scheduled on.
        @param metahosts - A list of label ids for each host that this job
                should be scheduled on (meta host scheduling).
        @param priority - The job priority (integer).
        @param active - bool, mark this job as running or not in the database?
        @param synchronous - bool, if True use synch_count=2 otherwise use
                synch_count=1.
        @param hostless - if True, this job is intended to be hostless (in that
                case, hosts, and metahosts must all be empty)
        @param owner - The owner of the job. Aclgroups from which a job can
                acquire hosts change with the aclgroups of the owners.
        @param parent_job_id - The id of a parent_job. If a job with the id
                doesn't already exist one will be created.

        @raises model.DoesNotExist: If parent_job_id is specified but a job with
            id=parent_job_id does not exist.

        @returns A Django frontend.afe.models.Job instance.
        """
        if not drone_set:
            drone_set = (models.DroneSet.default_drone_set_name()
                         and models.DroneSet.get_default())

        synch_count = synchronous and 2 or 1
        created_on = datetime.datetime(2008, 1, 1)
        status = models.HostQueueEntry.Status.QUEUED
        if active:
            status = models.HostQueueEntry.Status.RUNNING

        parent_job = (models.Job.objects.get(id=parent_job_id)
                      if parent_job_id else None)
        job = models.Job.objects.create(
            name='test', owner=owner, priority=priority,
            synch_count=synch_count, created_on=created_on,
            reboot_before=model_attributes.RebootBefore.NEVER,
            drone_set=drone_set, control_file=control_file,
            parent_job=parent_job, require_ssp=None)

        # Update the job's dependencies to include the metahost.
        for metahost_label in metahosts:
            dep = models.Label.objects.get(id=metahost_label)
            job.dependency_labels.add(dep)

        for host_id in hosts:
            models.HostQueueEntry.objects.create(job=job, host_id=host_id,
                                                 status=status)
            models.IneligibleHostQueue.objects.create(job=job, host_id=host_id)
        for label_id in metahosts:
            models.HostQueueEntry.objects.create(job=job, meta_host_id=label_id,
                                                 status=status)

        if hostless:
            assert not (hosts or metahosts)
            models.HostQueueEntry.objects.create(job=job, status=status)
        return job


    def _create_job_simple(self, hosts, use_metahost=False,
                           priority=0, active=False, drone_set=None,
                           parent_job_id=None):
        """An alternative interface to _create_job"""
        args = {'hosts' : [], 'metahosts' : []}
        if use_metahost:
            args['metahosts'] = hosts
        else:
            args['hosts'] = hosts
        return self._create_job(
                priority=priority, active=active, drone_set=drone_set,
                parent_job_id=parent_job_id, **args)
