# -*- coding: utf-8 -*-
# Moovida - Home multimedia server
# Copyright (C) 2006-2009 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Moovida with Fluendo's plugins.
#
# The GPL part of Moovida is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Moovida" in the root directory of this distribution package
# for details on that license.
#
# Author: Benjamin Kampmann


"""
Test whether the update_checker works fine
"""

from elisa.core.utils.update_checker import UpdateChecker, UPDATES_URL
from elisa.core import common

from twisted.trial.unittest import TestCase
from twisted.internet import defer, reactor




class PluginRegistryMock(object):
    def update_cache(self):
        return defer.succeed(None)

class ConfigMock(object):
    def get_option(self, *args, **kw):
        return False

class ApplicationMock(object):
    plugin_registry = PluginRegistryMock()
    config = ConfigMock()

class PageGetterMock(object):
    def __init__(self):
        self.requests = []

    def _get(self, url):
        # Mock to replace a call to the real page getter
        self.requests.append(url)
        data = 'user_id:666\nversion : 0.5\ninstaller_url:http://example.com'
        return defer.succeed(data)


class TestUpdateChecker(TestCase):

    install_date = 'test_date'
    user_id = 'superid'
    version = '0.5'

    def setUp(self):
        extra_affiliation_params = {'aen': '', 'entity_id': '',
                                    'referrer': '',
                                    'traffic_unit': ''}
        self.checker = UpdateChecker(self.install_date, self.user_id,
                                     self.version, **extra_affiliation_params)
        self.page_getter = PageGetterMock()
        self._patch_all()

    def _patch_all(self):
        # TestCase objects in twisted < 8 don't provide monkey patching.
        # Too bad...
        self._patched = {}
        self._patched['common.application'] = common.application
        common.application = ApplicationMock()
        self._patched['self.checker._get'] = self.checker._get
        self.checker._get = self.page_getter._get
        # FIXME: The update of the plugin cache is currently untested.
        self._patched['self.checker._update_plugin_cache'] = \
            self.checker._update_plugin_cache
        self.checker._update_plugin_cache = lambda x: None

    def tearDown(self):
        self.checker.stop()
        self._unpatch_all()

    def _unpatch_all(self):
        self.checker._update_plugin_cache = \
            self._patched['self.checker._update_plugin_cache']
        self.checker._get = self._patched['self.checker._get']
        common.application = self._patched['common.application']

    def test_parsing(self):
        data = 'user_id:666\nversion : 0.5\n installer_url:http://example.com'

        expected_result = {'user_id': '666', 'version': '0.5',
                           'installer_url': 'http://example.com'}

        result = self.checker.parse_result(data)
        self.assertEquals(expected_result, result)

    def test_makes_right_request(self):
        # we fake the result
        self.checker.operating_system = "linux"
        self.checker.extra_affiliation_params = {'aen': '2', 'entity_id': '1',
                                                 'referrer': 'foo',
                                                 'traffic_unit': 'bar'}

        url_params = {'os': 'linux', 'date': self.install_date,
                      'user_id': self.user_id, 'version': self.version}
        url_params.update(self.checker.extra_affiliation_params)
        url = UPDATES_URL % url_params

        def check(result, url):
            self.assertEquals(len(self.page_getter.requests), 1)
            self.assertEquals(self.page_getter.requests[0], url)

        dfr = self.checker.request()
        dfr.addCallback(check, url)
        return dfr

    def test_stop_cleans_up(self):
        # Start the checker, that will do a first request and wait for the
        # callback. We set a timeout so the request is not allowed to be
        # pending for too long. When tearing down the test case, all the
        # pending calls will be stopped, and the reactor should not be left in
        # an unclean state.
        dfr = defer.Deferred()
        def callbacker(result):
            dfr.callback(result)

        self.checker.start(callbacker)
        return dfr

    test_stop_cleans_up.timeout = 4

    def test_start_calls_a_loop(self):
        self.counter = 0

        dfr = defer.Deferred()
        def callbacker(result):
            self.counter += 1
            if self.counter == 3:
                reactor.callLater(0.1, dfr.callback, result)

        # we make it run faster
        self.checker.check_interval = 1
        self.checker.start(callbacker)
        return dfr

    test_start_calls_a_loop.timeout = 4
