#!/usr/bin/env python
# ***** BEGIN LICENSE BLOCK *****
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
# ***** END LICENSE BLOCK *****

import copy
import os
import sys

# load modules from parent dir
sys.path.insert(1, os.path.dirname(sys.path[0]))

from mozharness.base.errors import BaseErrorList, TarErrorList, ZipErrorList
from mozharness.base.log import ERROR, WARNING, FATAL, INFO
from mozharness.base.script import (
    BaseScript,
    PreScriptAction,
)
from mozharness.base.transfer import TransferMixin
from mozharness.base.vcs.vcsbase import MercurialScript
from mozharness.mozilla.blob_upload import BlobUploadMixin, blobupload_config_options
from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
from mozharness.mozilla.mozbase import MozbaseMixin
from mozharness.mozilla.buildbot import TBPL_SUCCESS, TBPL_WARNING, TBPL_FAILURE
from mozharness.mozilla.structuredlog import StructuredOutputParser
from mozharness.mozilla.testing.unittest import TestSummaryOutputParserHelper
from mozharness.mozilla.gaia import GaiaMixin

class LuciddreamTest(TestingMixin, MercurialScript, MozbaseMixin, BaseScript,
                     BlobUploadMixin, TransferMixin, GaiaMixin):
    config_options = [[
        ["--emulator-url"],
        {"action": "store",
         "dest": "emulator_url",
         "default": None,
         "help": "URL to the emulator zip",
     }
    ], [
        ["--gaia-profile"],
        {"action": "store",
         "dest": "gaia_profile",
         "help": "path to gaia profile",
     }
    ], [
        ["--gaia-repo"],
        {"action": "store",
         "dest": "gaia_repo",
         "default": "https://hg.mozilla.org/integration/gaia-central",
         "help": "url of gaia repo to clone"
         }
    ], [
        ["--gaia-branch"],
        {"action": "store",
         "dest": "gaia_branch",
         "default": "default",
         "help": "branch of gaia repo to clone"
         }
    ], [
        ["--b2g-desktop-path"],
        {"action": "store",
         "dest": "b2gdesktop_path",
         "help": "path to b2gdesktop binary",
     }
    ], [
        ["--b2g-desktop-url"],
        {"action": "store",
         "dest": "b2gdesktop_url",
         "help": "URL to b2gdesktop archive",
     }
    ], [
        ["--xre-path"],
        {"action": "store",
         "dest": "xre_path",
         "default": "xulrunner-sdk",
         "help": "directory (relative to gaia repo) of xulrunner-sdk"
         }
    ], [
        ["--xre-url"],
        {"action": "store",
         "dest": "xre_url",
         "default": None,
         "help": "url of desktop xre archive"
         }
    ]] + copy.deepcopy(testing_config_options) \
       + copy.deepcopy(blobupload_config_options)


    def __init__(self, require_config_file=False):
        super(LuciddreamTest, self).__init__(
            config_options=self.config_options,
            all_actions=['clobber',
                         'read-buildbot-config',
                         'download-and-extract',
                         'pull',
                         'create-virtualenv',
                         'install',
                         'run-tests'],
            default_actions=['clobber',
                             'read-buildbot-config',
                             'download-and-extract',
                             'pull',
                             'create-virtualenv',
                             'install',
                             'run-tests'],
            require_config_file=require_config_file,
            config={
                'require_test_zip': True,
                'emulator': 'arm',
                'virtualenv_modules': [
                    'mozinstall',
                ],
            }
        )

        # these are necessary since self.config is read only
        c = self.config
        self.installer_url = c.get('installer_url')
        self.installer_path = c.get('installer_path')
        self.emulator_url = c.get('emulator_url')
        self.binary_path = c.get('binary_path')
        self.test_url = c.get('test_url')

        if c.get('structured_output'):
            self.parser_class = StructuredOutputParser
        else:
            self.parser_class = TestSummaryOutputParserHelper

    def query_abs_dirs(self):
        if self.abs_dirs:
            return self.abs_dirs
        abs_dirs = super(LuciddreamTest, self).query_abs_dirs()
        dirs = {}
        dirs['abs_blob_upload_dir'] = os.path.join(
            abs_dirs['abs_work_dir'], 'logs')
        dirs['abs_test_install_dir'] = os.path.join(
            abs_dirs['abs_work_dir'], 'tests')
        dirs['abs_emulator_dir'] = os.path.join(
            abs_dirs['abs_work_dir'], 'emulator')
        dirs['abs_b2g-distro_dir'] = os.path.join(
            dirs['abs_emulator_dir'], 'b2g-distro')
        dirs['abs_b2g_desktop'] = os.path.join(
            abs_dirs['abs_work_dir'], 'b2gdesktop')
        gaia_root_dir = self.config.get('gaia_dir')
        if not gaia_root_dir:
            gaia_root_dir = self.config['base_work_dir']
        dirs['abs_gaia_dir'] = os.path.join(gaia_root_dir, 'gaia')
        abs_dirs.update(dirs)
        self.abs_dirs = abs_dirs

        return self.abs_dirs

    def install_emulator(self):
        dirs = self.query_abs_dirs()
        self.mkdir_p(dirs['abs_emulator_dir'])
        tarfile = self.download_file(self.emulator_url,
                                     parent_dir=dirs['abs_work_dir'],
                                     error_level=FATAL)
        self.emulator_path = tarfile
        tar = self.query_exe('tar', return_type='list')
        self.run_command(tar + ['zxf', self.emulator_path],
                         cwd=dirs['abs_emulator_dir'],
                         error_list=TarErrorList,
                         halt_on_failure=True, fatal_exit_code=3)

    def install(self, **kwargs):
        super(LuciddreamTest, self).install(**kwargs)
        dirs = self.query_abs_dirs()
        self.install_app(app='b2g',
                         target_dir=dirs['abs_b2g_desktop'],
                         installer_path=self.b2gdesktop_archive)

    def setup_gaia(self):
        dirs = self.query_abs_dirs()
        self.make_gaia(dirs['abs_gaia_dir'],
                       self.config.get('xre_path'),
                       xre_url=self.config.get('xre_url'),
                       debug=False,
                       noftu=False,
                       build_config_path=None)

    def pull(self, **kwargs):
        if self.config.get('b2gdesktop_url') or self.config.get('b2gdesktop_path'):
            GaiaMixin.pull(self, **kwargs)
        super(LuciddreamTest, self).pull(**kwargs)

    def download_and_extract(self):
        super(LuciddreamTest, self).download_and_extract()
        if self.config.get('emulator_url'):
            self.install_emulator()
        if self.config.get('b2gdesktop_url'):
            dirs = self.query_abs_dirs()
            self.mkdir_p(dirs['abs_b2g_desktop'])
            self.b2gdesktop_archive = self.download_file(self.config.get('b2gdesktop_url'),
                                                         parent_dir=dirs['abs_work_dir'])

    @PreScriptAction('create-virtualenv')
    def _pre_create_virtualenv(self, action):
        dirs = self.query_abs_dirs()
        requirements = os.path.join(dirs['abs_test_install_dir'],
                                    'config',
                                    'marionette_requirements.txt')
        self.register_virtualenv_module(requirements=[requirements],
                                        two_pass=True)

        luciddream_dir = os.path.join(dirs['abs_test_install_dir'],
                                      'luciddream')
        self.register_virtualenv_module(
            'luciddream',
            url=luciddream_dir,
            requirements=[os.path.join(luciddream_dir, 'requirements.txt')],
        )

    def run_tests(self):
        """
        Run the tests
        """
        dirs = self.query_abs_dirs()
        env = {}
        env = self.query_env(partial_env=env)

        ld_dir = os.path.join(dirs['abs_test_install_dir'], 'luciddream')

        if self.config.get('b2gdesktop_path') or self.config.get('b2gdesktop_url'):
            self.setup_gaia()

        ld_parser = self.parser_class(config=self.config,
                                      log_obj=self.log_obj,
                                      error_list=BaseErrorList)
 
        cmd = [self.query_python_path('python'),
               os.path.join(ld_dir, 'luciddream', 'runluciddream.py')
               ]

        str_format_values = {
            'browser_path': self.binary_path,
            'raw_log_file': os.path.join(dirs['abs_work_dir'], 'luciddream_raw.log'),
            'error_summary_file': os.path.join(dirs['abs_work_dir'], 'luciddream_errorsummary.log'),
            'test_manifest': os.path.join(ld_dir, 'example-tests', 'luciddream.ini')
        }

        if self.config.get('emulator_url'):
            str_format_values['emulator_path'] = dirs['abs_b2g-distro_dir']
        else:
            if self.config.get('b2gdesktop_url'):
                str_format_values['fxos_desktop_path'] = os.path.join(dirs['abs_b2g_desktop'], 'b2g', 'b2g')
            else:
                str_format_values['fxos_desktop_path'] = self.config.get('b2gdesktop_path')
            str_format_values['gaia_profile'] = os.path.join(dirs['abs_gaia_dir'], 'profile')

        suite = 'luciddream-emulator' if self.config.get('emulator_url') else 'luciddream-b2gdt'
        options = self.config['suite_definitions'][suite]['options']
        for option in options:
            option = option % str_format_values
            if not option.endswith('None'):
                cmd.append(option)

        code = self.run_command(cmd, env=env,
                                output_timeout=1000,
                                output_parser=ld_parser,
                                success_codes=[0],
                                cwd=dirs['abs_work_dir'])

        level = INFO
        if code == 0 and ld_parser.passed > 0 and ld_parser.failed == 0:
            status = "success"
            tbpl_status = TBPL_SUCCESS
        elif ld_parser.failed > 0:
            status = "test failures"
            tbpl_status = TBPL_WARNING
        else:
            status = "harness failures"
            level = ERROR
            tbpl_status = TBPL_FAILURE

        ld_parser.print_summary('luciddream')

        self.log("Luciddream exited with return code %s: %s" % (code, status),
                 level=level)
        self.buildbot_status(tbpl_status)

        if not os.path.exists(dirs['abs_blob_upload_dir']):
            self.mkdir_p(dirs['abs_blob_upload_dir'])
        for filename in os.listdir(dirs['abs_work_dir']):
            if filename.endswith('.log'):
                self.copyfile(os.path.join(dirs['abs_work_dir'], filename),
                              os.path.join(dirs['abs_blob_upload_dir'], filename))


if __name__ == '__main__':
    luciddreamTest = LuciddreamTest()
    luciddreamTest.run_and_exit()
