from ploneintranet.asynctasks.browser.status import get_checksum
from ploneintranet.asynctasks.tasks import Post
from ploneintranet.asynctasks.testing import FunctionalTestCase
from ploneintranet.asynctasks.testing import IntegrationTestCase

import random
import redis.exceptions
import subprocess
import time
import transaction


class TestDispatch(IntegrationTestCase):
    def test_redis(self):
        """
        Verify that redis is running.

        Required for other tests.
        """
        self.assertTrue(self.redis_running(), "redis server not reachable")

    def test_celery(self):
        """Verify that celery worker is running.

        Required for other tests.
        """
        # pwd = /(buildout:dir)/parts/test
        cmd = "../../bin/celery -A ploneintranet.asynctasks.celerytasks status"
        try:
            res = subprocess.check_output(cmd.split(" "))
            self.assertTrue(b"online" in res, "no celery workers online")
        except subprocess.CalledProcessError:
            self.fail("celery worker is not available")

    def test_task(self):
        """Verify delayed task execution"""
        # delay import with side effects until after setup
        from ploneintranet.asynctasks.celerytasks import add

        try:
            result = add.delay(2, 2, 1)
        except redis.exceptions.ConnectionError:
            self.fail("redis not available")
        self.assertFalse(result.ready(), "result should be delayed")
        time.sleep(1)
        if not result.ready():
            time.sleep(1)  # catch unexpected delay
        self.assertTrue(result.ready(), "result should've been ready")
        self.assertEqual(result.get(), 4)


class TestPost(FunctionalTestCase):
    """
    Verify async roundtrip. You can test this interactively
    at: http://localhost:8080/Plone/@@async-status

    You can debug async tests by attaching another terminal to the testenv
    and starting celery in debug mode there::
    docker exec -it <container> bash
    bin/celery -A ploneintranet.asynctasks.celerytasks worker -l DEBUG
    """

    def test_post(self):
        """Verify http post async task execution"""
        if not self.redis_running():
            self.fail("requires redis")
            return

        self.basic_auth()  # set up basic authentication
        url = "@@async-checktask"
        checksum = random.random()
        data = dict(checksum=checksum)
        result = Post(self.portal, self.request)(url, data)
        self.waitfor(result)
        # we need to commit in order to see the other transaction
        transaction.commit()
        try:
            got_checksum = get_checksum()
        except KeyError:
            self.fail("no checksum annotations available at all!")
        # the checksum got mangled a bit in transmission
        self.assertEqual(str(checksum), str(got_checksum))

    def test_cookie_cleaner(self):
        """Test that cookie with newlines are not breaking our code"""
        if not self.redis_running():
            self.fail("requires redis")

        request = self.request.clone()
        request.cookies = {"__cp": "a\nb"}
        result = Post(self.portal, request)("@@async-checktask", {"checksum": "foo"})
        self.waitfor(result)
        # we need to commit in order to see the other transaction
        transaction.commit()
        # the checksum got mangled a bit in transmission
        self.assertEqual("foo", str(get_checksum()))


# actual "business logic" task tests are in test_tasks
