# Copyright 2014 Red Hat
#
# All Rights Reserved.
#
#    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.

from oslo_log import log as logging

from tempest import config
from tempest.scenario import manager
from tempest import test

CONF = config.CONF

LOG = logging.getLogger(__name__)

# Loop for up to 120 seconds waiting on notifications
# NOTE(chdent): The choice of 120 seconds is fairly
# arbitrary: Long enough to give the notifications the
# chance to travel across a highly latent bus but not
# so long as to allow excessive latency to never be visible.
# TODO(chdent): Ideally this value would come from configuration.
NOTIFICATIONS_WAIT = 120
NOTIFICATIONS_SLEEP = 1


class TestSwiftTelemetry(manager.SwiftScenarioTest):
    """
    Test that swift uses the ceilometer middleware.
     * create container.
     * upload a file to the created container.
     * retrieve the file from the created container.
     * wait for notifications from ceilometer.
    """

    @classmethod
    def skip_checks(cls):
        super(TestSwiftTelemetry, cls).skip_checks()
        if not CONF.service_available.ceilometer:
            skip_msg = ("%s skipped as ceilometer is not available" %
                        cls.__name__)
            raise cls.skipException(skip_msg)
        elif CONF.telemetry.too_slow_to_test:
            skip_msg = "Ceilometer feature for fast work mysql is disabled"
            raise cls.skipException(skip_msg)

    @classmethod
    def setup_clients(cls):
        super(TestSwiftTelemetry, cls).setup_clients()
        cls.telemetry_client = cls.os_operator.telemetry_client

    def _confirm_notifications(self, container_name, obj_name):
        """
        Loop seeking for appropriate notifications about the containers
        and objects sent to swift.
        """

        def _check_samples():
            """
            Return True only if we have notifications about some
            containers and some objects and the notifications are about
            the expected containers and objects.
            Otherwise returning False will case _check_samples to be
            called again.
            """
            results = self.telemetry_client.list_samples(
                'storage.objects.incoming.bytes')
            LOG.debug('got samples %s', results)

            # Extract container info from samples.
            containers, objects = [], []
            for sample in results:
                meta = sample['resource_metadata']
                if meta.get('container') and meta['container'] != 'None':
                    containers.append(meta['container'])
                elif (meta.get('target.metadata:container') and
                      meta['target.metadata:container'] != 'None'):
                    containers.append(meta['target.metadata:container'])

                if meta.get('object') and meta['object'] != 'None':
                    objects.append(meta['object'])
                elif (meta.get('target.metadata:object') and
                      meta['target.metadata:object'] != 'None'):
                    objects.append(meta['target.metadata:object'])

            return (container_name in containers and obj_name in objects)

        self.assertTrue(test.call_until_true(_check_samples,
                                             NOTIFICATIONS_WAIT,
                                             NOTIFICATIONS_SLEEP),
                        'Correct notifications were not received after '
                        '%s seconds.' % NOTIFICATIONS_WAIT)

    @test.idempotent_id('6d6b88e5-3e38-41bc-b34a-79f713a6cb84')
    @test.services('object_storage', 'telemetry')
    def test_swift_middleware_notifies(self):
        container_name = self.create_container()
        obj_name, _ = self.upload_object_to_container(container_name)
        self._confirm_notifications(container_name, obj_name)
