# pylint: disable=missing-docstring
from __future__ import absolute_import, division, print_function, unicode_literals

import sys
import unittest

from django.contrib.auth.models import AnonymousUser
from django.test import LiveServerTestCase

from guardian.shortcuts import assign_perm

from resolwe.flow.models import Collection, Process, Storage
from resolwe.test import ProcessTestCase, check_installed, tag_process, with_docker_executor, with_resolwe_host


class AccessAPIFromExecutorProcessTestCase(ProcessTestCase, LiveServerTestCase):

    def _create_collection(self):
        """Create a test collection that will be accessed via a test process.

        Assign :class:`~django.contrib.auth.models.AnonymousUser`
        ``view_collection`` permission to the created collection.

        :return: created test collection
        :rtype: Collection

        """
        collection = Collection.objects.create(
            name='collection-foo',
            contributor=self.contributor,
        )
        assign_perm("view_collection", AnonymousUser(), collection)
        return collection

    def create_process(self):
        """Create a test process that will query the API for collections.

        Get the list of all collections using ``curl`` to query the Live
        Resolwe host.

        :return: created test process
        :rtype: Process

        """
        process = Process.objects.create(
            name='Test accessing API from process',
            requirements={'expression-engine': 'jinja', 'resources': {'network': True}},
            contributor=self.contributor,
            type='data:test:api-access',
            input_schema=[],
            output_schema=[
                {
                    'name': 'collection-list',
                    'type': 'basic:json:',
                    'required': False,
                },
            ],
            run={
                'language': 'bash',
                # NOTE: Resolwe Runtime Utilities are not available in the
                # resolwe/test:base Docker image so we need to use plain echo
                # NOTE: curl must be called with --silent argument to not ouput
                # its progress since it can interfere with parsing of JSON on
                # process' standard output
                'program': r"""
echo "{\"collection-list\": $(curl --silent --show-error $RESOLWE_HOST_URL/collection)}"
"""
            }
        )
        return process

    def setUp(self):
        """Custom initilization of :class:`~ProcessTestCase`."""
        super(AccessAPIFromExecutorProcessTestCase, self).setUp()

        self.process = self.create_process()

    def check_results(self, data):
        """Check if information obtained for collection via API is correct."""
        if 'collection-list' not in data.output:
            self.fail(
                "The test process didn't obtain collection list from the live Resolwe host." +
                self._debug_info(data)
            )
        collection_list = Storage.objects.get(data=data).json
        self.assertEqual(len(collection_list), 1)
        self.assertEqual(collection_list[0]['slug'], self.collection.slug)

    @unittest.skipUnless(*check_installed('curl'))
    @with_resolwe_host
    @tag_process('test-accessing-api-from-process')
    def test_access_api_from_local_executor_process(self):  # pylint: disable=invalid-name
        """Test if a process running via local executor can access API."""
        data = self.run_process(self.process.slug)
        self.check_results(data)

    @unittest.skipUnless(*check_installed('curl'))
    @tag_process('test-accessing-api-from-process')
    def test_access_api_from_local_executor_process_without_decorator(self):  # pylint: disable=invalid-name
        """Test if a process running via local executor cannot access API."""
        data = self.run_process(self.process.slug)
        with self.assertRaises(AssertionError):
            self.check_results(data)

    @unittest.skipUnless(
        sys.platform.startswith('linux'),
        "Accessing live Resolwe host from a Docker container on non-Linux systems is not possible yet."
    )
    @with_resolwe_host
    @with_docker_executor
    @tag_process('test-accessing-api-from-process')
    def test_access_api_from_docker_executor_process(self):
        """Test if a process running via Docker executor can access API."""
        # pylint: disable=invalid-name
        # NOTE: pylint gets confused if the above string is inline with the method name
        data = self.run_process(self.process.slug)
        self.check_results(data)

    @unittest.skipUnless(
        sys.platform.startswith('linux'),
        "Accessing live Resolwe host from a Docker container on non-Linux systems is not possible yet."
    )
    @with_docker_executor
    @with_resolwe_host
    @tag_process('test-accessing-api-from-process')
    def test_access_api_from_docker_executor_process_reverse_decorators(self):
        """Test if a process running via Docker executor can access API."""
        # pylint: disable=invalid-name
        # NOTE: pylint gets confused if the above string is inline with the method name
        data = self.run_process(self.process.slug)
        self.check_results(data)
