Test to check container synchronization

Adds a new test script test_container_sync.py to
./tests/object_storage so as to verfify the container to
container synchronization support.

Change-Id: If880ab0e62465c32113cfde2b864841fa363ad19
Implements: blueprint add-swift-container-sync-test
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index f837e69..fc20d0b 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -232,6 +232,12 @@
 # The object-store region
 region = RegionOne
 
+# Number of seconds to time on waiting for a container to container
+# synchronization complete
+container_sync_timeout = 120
+# Number of seconds to wait while looping to check the status of a
+# container to container synchronization
+container_sync_interval = 5
 
 [boto]
 # This section contains configuration options used when executing tests
diff --git a/tempest/config.py b/tempest/config.py
index a7b9d27..e348cce 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -328,6 +328,14 @@
     cfg.StrOpt('region',
                default=None,
                help='The object-store region name to use.'),
+    cfg.StrOpt('container_sync_timeout',
+               default=120,
+               help="Number of seconds to time on waiting for a container"
+                    "to container synchronization complete."),
+    cfg.StrOpt('container_sync_interval',
+               default=5,
+               help="Number of seconds to wait while looping to check the"
+                    "status of a container to container synchronization"),
 ]
 
 
diff --git a/tempest/tests/object_storage/test_container_sync.py b/tempest/tests/object_storage/test_container_sync.py
new file mode 100644
index 0000000..3dea259
--- /dev/null
+++ b/tempest/tests/object_storage/test_container_sync.py
@@ -0,0 +1,126 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# 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 nose.plugins.attrib import attr
+from tempest.common.utils.data_utils import arbitrary_string
+from tempest.common.utils.data_utils import rand_name
+from tempest.tests.object_storage import base
+import unittest2 as unittest
+
+
+class ContainerSyncTest(base.BaseObjectTest):
+
+    @classmethod
+    def setUpClass(cls):
+        super(ContainerSyncTest, cls).setUpClass()
+
+        cls.containers = []
+        cls.objects = []
+        container_sync_timeout = \
+            int(cls.config.object_storage.container_sync_timeout)
+        cls.container_sync_interval = \
+            int(cls.config.object_storage.container_sync_interval)
+        cls.attempts = \
+            int(container_sync_timeout / cls.container_sync_interval)
+
+        # Define container and object clients
+        cls.clients = {}
+        cls.clients[rand_name(name='TestContainerSync')] = \
+            (cls.container_client, cls.object_client)
+        cls.clients[rand_name(name='TestContainerSync')] = \
+            (cls.container_client_alt, cls.object_client_alt)
+        for cont_name, client in cls.clients.items():
+            client[0].create_container(cont_name)
+            cls.containers.append(cont_name)
+
+    @classmethod
+    def tearDownClass(cls):
+        for cont_name, client in cls.clients.items():
+            #Get list of all object in the container
+            objlist = client[0].list_all_container_objects(cont_name)
+
+            #Attempt to delete every object in the container
+            if objlist:
+                for obj in objlist:
+                    resp, _ = client[1].delete_object(cont_name, obj['name'])
+
+            #Attempt to delete the container
+            resp, _ = client[0].delete_container(cont_name)
+
+    @unittest.skip('Until Bug 1093743 is resolved.')
+    @attr(type='positive')
+    def test_container_synchronization(self):
+        #Container to container synchronization
+        #To allow/accept sync requests to/from other accounts
+
+        #Switch container synchronization on and create objects in a containers
+        for cont in (self.containers, self.containers[::-1]):
+            cont_client = [self.clients[c][0] for c in cont]
+            obj_client = [self.clients[c][1] for c in cont]
+
+            #tell first container to syncronize to a second
+            headers = {'X-Container-Sync-Key': 'sync_key',
+                       'X-Container-Sync-To': "%s/%s" %
+                       (cont_client[1].base_url, str(cont[1]))}
+            resp, body = \
+                cont_client[0].put(str(cont[0]), body=None, headers=headers)
+            self.assertTrue(resp['status'] in ('202', '201'),
+                            'Error installing X-Container-Sync-To '
+                            'for the container "%s"' % (cont[0]))
+
+            #Create Object in container
+            object_name = rand_name(name='TestSyncObject')
+            data = object_name[::-1]  # arbitrary_string()
+            resp, _ = obj_client[0].create_object(cont[0], object_name, data)
+            self.assertEqual(resp['status'], '201',
+                             'Error creating the object "%s" in'
+                             'the container "%s"'
+                             % (object_name, cont[0]))
+            self.objects.append(object_name)
+
+        #Wait for Container contents list json format will be not empty
+        cont_client = [self.clients[c][0] for c in self.containers]
+        params = {'format': 'json'}
+        while self.attempts > 0:
+            # get first container content
+            resp, object_list_0 = \
+                cont_client[0].\
+                list_container_contents(self.containers[0], params=params)
+            self.assertEqual(resp['status'], '200',
+                             'Error listing the destination container`s'
+                             ' "%s" contents' % (self.containers[0]))
+            object_list_0 = {obj['name']: obj for obj in object_list_0}
+            # get second container content
+            resp, object_list_1 = \
+                cont_client[1].\
+                list_container_contents(self.containers[1], params=params)
+            self.assertEqual(resp['status'], '200',
+                             'Error listing the destination container`s'
+                             ' "%s" contents' % (self.containers[1]))
+            object_list_1 = {obj['name']: obj for obj in object_list_1}
+            # check that containers is not empty and has equal keys()
+            # or wait for next attepmt
+            if not object_list_0 or not object_list_1 or \
+                    set(object_list_0.keys()) != set(object_list_1.keys()):
+                time.sleep(self.container_sync_interval)
+                self.attempts -= 1
+            else:
+                break
+
+        # Check for synchronization
+        self.assertEqual(object_list_0, object_list_1,
+                         'Different object lists in containers.')