# Copyright 2015 Rackspace, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import multiprocessing
import os
import time

from oslo_log import log as logging
from oslotest import base as test_base
import requests

from ironic_python_agent import agent
# NOTE(lucasagomes): This import is needed so we can register the
# configuration options prior to IPA prior to starting the service
from ironic_python_agent import config  # noqa
from ironic_python_agent import netutils


class FunctionalBase(test_base.BaseTestCase):

    def setUp(self):
        """Start the agent and wait for it to start"""
        super(FunctionalBase, self).setUp()
        mpl = multiprocessing.log_to_stderr()
        mpl.setLevel(logging.INFO)
        self.test_port = os.environ.get('TEST_PORT', '9999')
        # Build a basic standalone agent using the config option defaults.
        # 127.0.0.1:6835 is the fake Ironic client.

        self.agent = agent.IronicPythonAgent(
            api_url='http://127.0.0.1:6835',
            advertise_address=agent.Host('localhost', 9999),
            listen_address=agent.Host(netutils.get_wildcard_address(),
                                      int(self.test_port)),
            ip_lookup_attempts=3,
            ip_lookup_sleep=10,
            network_interface=None,
            lookup_timeout=300,
            lookup_interval=1,
            standalone=True,
            agent_token=None)
        self.process = multiprocessing.Process(
            target=self.agent.run)
        self.process.start()
        self.addCleanup(self.process.terminate)

        # Wait for process to start, otherwise we have a race for tests
        sleep_time = 0.1
        tries = 0
        max_tries = int(os.environ.get('IPA_WAIT_TRIES', '100'))
        while tries < max_tries:
            try:
                return self.request('get', 'commands')
            except requests.ConnectionError:
                time.sleep(sleep_time)
                tries += 1

        raise IOError('Agent did not start after %s seconds.'
                      % (max_tries * sleep_time))

    def request(self, method, path, expect_error=None, expect_json=True,
                **kwargs):
        """Send a request to the agent and verifies response.

        :param method: type of request to send as a string
        :param path: desired API endpoint to request, for example 'commands'
        :param expect_error: error code to expect, if an error is expected
        :param expect_json: whether to expect a JSON response. if True, convert
                            it to a dict before returning, otherwise return the
                            Response object
        :param kwargs: keyword args to pass to the request method
        :raises: HTTPError if an error is returned that was not expected
        :raises: AssertionError if a received HTTP status code does not match
                 expect_error
        :returns: the response object
        """
        res = requests.request(method, 'http://localhost:%s/v1/%s' %
                               (self.test_port, path), **kwargs)
        if expect_error is not None:
            self.assertEqual(expect_error, res.status_code)
        else:
            res.raise_for_status()
        if expect_json:
            return res.json()
        else:
            return res