#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
#

"""
System tests involving one or more brokers and dispatch routers integrated
with waypoints.
"""
import unittest, system_test
from system_test import Qdrouterd, message, MISSING_REQUIREMENTS
from itertools import cycle

class DistributedQueueTest(system_test.TestCase): # pylint: disable=too-many-public-methods
    """System tests involving routers and qpidd brokers"""

    if MISSING_REQUIREMENTS:
        def test_skip(self):
            self.skipTest(MISSING_REQUIREMENTS)
    else:
        @classmethod
        def setUpClass(cls):
            """Start 3 qpidd brokers, wait for them to be ready."""
            super(DistributedQueueTest, cls).setUpClass()
            cls.qpidds = [cls.tester.qpidd('qpidd%s'%i, port=cls.get_port(), wait=False)
                        for i in xrange(3)]
            for q in cls.qpidds:
                q.wait_ready()

        @classmethod
        def tearDownClass(cls):
            super(DistributedQueueTest, cls).tearDownClass()

        def setUp(self):
            super(DistributedQueueTest, self).setUp()
            self.testq = 'testq.'+self.id().split('.')[-1] # The distributed queue name

        def common_router_conf(self, name, mode='standalone'):
            """Common router configuration for the tests"""
            return Qdrouterd.Config([
                ('container', {'containerName':name}),
                ('router', {'mode': mode, 'routerId': name})
            ])

        def verify_equal_spread(self, send_addresses, receive_addresses):
            """Verify we send/receive to the queue the load was spread over the brokers.
            Send to each of the send_addresses in turn, subscribe to all of the receive_addresses.
            """
            msgr = self.messenger()
            for a in receive_addresses:
                msgr.subscribe(a)
            msgr.flush()
            n = 20                  # Messages per broker
            r = ["x-%02d"%i for i in range(n*len(self.qpidds))]
            for b, a in zip(r, cycle(send_addresses)):
                msgr.put(message(address=a, body=b))
            msgr.flush()
            messages = sorted(msgr.fetch().body for i in r)
            msgr.flush()
            self.assertEqual(r, messages)

            qs = [q.management.getQueue(self.testq) for q in self.qpidds]
            enq = sum(q.msgTotalEnqueues for q in qs)
            deq = sum(q.msgTotalDequeues for q in qs)
            self.assertEquals((enq, deq), (len(r), len(r)))
            # Verify each broker handled a reasonable share of the messages.
            self.assert_fair([q.msgTotalEnqueues for q in qs])

        def test_distrbuted_queue(self):
            """Create a distributed queue with N routers and N brokers.
            Each router is connected to all the brokers."""
            for q in self.qpidds:
                q.management.addQueue(self.testq)

            def router(i):
                """Create router<i> with waypoints to each broker."""
                name = "router%s"%i
                rconf = self.common_router_conf(name, mode='interior')
                rconf += [
                    ('listener', {'port':self.get_port(), 'role':'normal'}),
                    ('fixed-address', {'prefix':self.testq, 'phase':0, 'fanout':'single', 'bias':'spread'}),
                    ('fixed-address', {'prefix':self.testq, 'phase':1, 'fanout':'single', 'bias':'spread'})]
                for q in self.qpidds:
                    rconf += [
                        ('connector', {'name':q.name, 'port':q.port}),
                        ('waypoint', {'address':self.testq, 'out-phase':1, 'in-phase':0, 'connector':q.name})]
                return self.qdrouterd(name, rconf, wait=False)
            routers = [router(i) for i in xrange(len(self.qpidds))]
            for r in routers: r.wait_ready()
            addrs = [r.addresses[0]+"/"+self.testq for r in routers]
            self.verify_equal_spread(addrs, addrs)

if __name__ == '__main__':
    unittest.main(system_test.main_module())
