diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py
index fdeca139ec..690cabba7e 100644
--- a/openstackclient/common/clientmanager.py
+++ b/openstackclient/common/clientmanager.py
@@ -20,6 +20,7 @@ import logging
 from openstackclient.compute import client as compute_client
 from openstackclient.identity import client as identity_client
 from openstackclient.image import client as image_client
+from openstackclient.object import client as object_client
 from openstackclient.volume import client as volume_client
 
 
@@ -44,6 +45,7 @@ class ClientManager(object):
     compute = ClientCache(compute_client.make_client)
     identity = ClientCache(identity_client.make_client)
     image = ClientCache(image_client.make_client)
+    object = ClientCache(object_client.make_client)
     volume = ClientCache(volume_client.make_client)
 
     def __init__(self, token=None, url=None, auth_url=None, project_name=None,
diff --git a/openstackclient/object/__init__.py b/openstackclient/object/__init__.py
new file mode 100644
index 0000000000..02be10cd89
--- /dev/null
+++ b/openstackclient/object/__init__.py
@@ -0,0 +1,12 @@
+#   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.
+#
diff --git a/openstackclient/object/client.py b/openstackclient/object/client.py
new file mode 100644
index 0000000000..a83a5c0a3d
--- /dev/null
+++ b/openstackclient/object/client.py
@@ -0,0 +1,58 @@
+#   Copyright 2013 Nebula 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.
+#
+
+"""Object client"""
+
+import logging
+
+from openstackclient.common import utils
+
+LOG = logging.getLogger(__name__)
+
+API_NAME = 'object-store'
+API_VERSIONS = {
+    '1': 'openstackclient.object.client.ObjectClientv1',
+}
+
+
+def make_client(instance):
+    """Returns an object service client."""
+    object_client = utils.get_client_class(
+        API_NAME,
+        instance._api_version[API_NAME],
+        API_VERSIONS)
+    if instance._url:
+        endpoint = instance._url
+    else:
+        endpoint = instance.get_endpoint_for_service_type(API_NAME)
+    LOG.debug('instantiating object client')
+    client = object_client(
+        endpoint=endpoint,
+        token=instance._token,
+    )
+    return client
+
+
+class ObjectClientv1(object):
+
+    def __init__(
+        self,
+        endpoint_type='publicURL',
+        endpoint=None,
+        token=None,
+    ):
+        self.endpoint_type = endpoint_type
+        self.endpoint = endpoint
+        self.token = token
diff --git a/openstackclient/object/v1/__init__.py b/openstackclient/object/v1/__init__.py
new file mode 100644
index 0000000000..02be10cd89
--- /dev/null
+++ b/openstackclient/object/v1/__init__.py
@@ -0,0 +1,12 @@
+#   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.
+#
diff --git a/openstackclient/object/v1/container.py b/openstackclient/object/v1/container.py
new file mode 100644
index 0000000000..8c4db66ae4
--- /dev/null
+++ b/openstackclient/object/v1/container.py
@@ -0,0 +1,100 @@
+#   Copyright 2013 Nebula 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.
+#
+
+"""Container v1 action implementations"""
+
+
+import logging
+
+from cliff import lister
+
+from openstackclient.common import utils
+from openstackclient.object.v1.lib import container as lib_container
+
+
+class ListContainer(lister.Lister):
+    """List containers"""
+
+    log = logging.getLogger(__name__ + '.ListContainer')
+
+    def get_parser(self, prog_name):
+        parser = super(ListContainer, self).get_parser(prog_name)
+        parser.add_argument(
+            "--prefix",
+            metavar="<prefix>",
+            help="Filter list using <prefix>",
+        )
+        parser.add_argument(
+            "--marker",
+            metavar="<marker>",
+            help="Anchor for paging",
+        )
+        parser.add_argument(
+            "--end-marker",
+            metavar="<end-marker>",
+            help="End anchor for paging",
+        )
+        parser.add_argument(
+            "--limit",
+            metavar="<limit>",
+            type=int,
+            help="Limit the number of containers returned",
+        )
+        parser.add_argument(
+            '--long',
+            action='store_true',
+            default=False,
+            help='List additional fields in output',
+        )
+        parser.add_argument(
+            '--all',
+            action='store_true',
+            default=False,
+            help='List all containers (default is 10000)',
+        )
+        return parser
+
+    def take_action(self, parsed_args):
+        self.log.debug('take_action(%s)' % parsed_args)
+
+        if parsed_args.long:
+            columns = ('Name', 'Bytes', 'Count')
+        else:
+            columns = ('Name',)
+
+        kwargs = {}
+        if parsed_args.prefix:
+            kwargs['prefix'] = parsed_args.prefix
+        if parsed_args.marker:
+            kwargs['marker'] = parsed_args.marker
+        if parsed_args.end_marker:
+            kwargs['end_marker'] = parsed_args.end_marker
+        if parsed_args.limit:
+            kwargs['limit'] = parsed_args.limit
+        if parsed_args.all:
+            kwargs['full_listing'] = True
+
+        data = lib_container.list_containers(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            **kwargs
+        )
+        #print "data: %s" % data
+
+        return (columns,
+                (utils.get_dict_properties(
+                    s, columns,
+                    formatters={},
+                ) for s in data))
diff --git a/openstackclient/object/v1/lib/__init__.py b/openstackclient/object/v1/lib/__init__.py
new file mode 100644
index 0000000000..02be10cd89
--- /dev/null
+++ b/openstackclient/object/v1/lib/__init__.py
@@ -0,0 +1,12 @@
+#   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.
+#
diff --git a/openstackclient/object/v1/lib/container.py b/openstackclient/object/v1/lib/container.py
new file mode 100644
index 0000000000..f30533c804
--- /dev/null
+++ b/openstackclient/object/v1/lib/container.py
@@ -0,0 +1,77 @@
+#   Copyright 2010-2012 OpenStack Foundation
+#   Copyright 2013 Nebula 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.
+#
+
+"""Object v1 API library"""
+
+
+def list_containers(
+    api,
+    url,
+    marker=None,
+    limit=None,
+    end_marker=None,
+    prefix=None,
+    full_listing=False,
+):
+    """Get containers in an account
+
+    :param api: a restapi object
+    :param url: endpoint
+    :param marker: marker query
+    :param limit: limit query
+    :param end_marker: end_marker query
+    :param prefix: prefix query
+    :param full_listing: if True, return a full listing, else returns a max
+                         of 10000 listings
+    :returns: list of containers
+    """
+
+    if full_listing:
+        data = listing = list_containers(
+            api,
+            url,
+            marker,
+            limit,
+            end_marker,
+            prefix,
+        )
+        while listing:
+            marker = listing[-1]['name']
+            listing = list_containers(
+                api,
+                url,
+                marker,
+                limit,
+                end_marker,
+                prefix,
+            )
+            if listing:
+                data.extend(listing)
+        return data
+
+    object_url = url
+    query = "format=json"
+    if marker:
+        query += '&marker=%s' % marker
+    if limit:
+        query += '&limit=%d' % limit
+    if end_marker:
+        query += '&end_marker=%s' % end_marker
+    if prefix:
+        query += '&prefix=%s' % prefix
+    url = "%s?%s" % (object_url, query)
+    response = api.request('GET', url)
+    return response.json()
diff --git a/openstackclient/object/v1/lib/object.py b/openstackclient/object/v1/lib/object.py
new file mode 100644
index 0000000000..d7c4a1ce37
--- /dev/null
+++ b/openstackclient/object/v1/lib/object.py
@@ -0,0 +1,97 @@
+#   Copyright 2010-2012 OpenStack Foundation
+#   Copyright 2013 Nebula 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.
+#
+
+"""Object v1 API library"""
+
+
+def list_objects(
+    api,
+    url,
+    container,
+    marker=None,
+    limit=None,
+    end_marker=None,
+    delimiter=None,
+    prefix=None,
+    path=None,
+    full_listing=False,
+):
+    """Get objects in a container
+
+    :param api: a restapi object
+    :param url: endpoint
+    :param container: container name to get a listing for
+    :param marker: marker query
+    :param limit: limit query
+    :param end_marker: marker query
+    :param delimiter: string to delimit the queries on
+    :param prefix: prefix query
+    :param path: path query (equivalent: "delimiter=/" and "prefix=path/")
+    :param full_listing: if True, return a full listing, else returns a max
+                         of 10000 listings
+    :returns: a tuple of (response headers, a list of objects) The response
+              headers will be a dict and all header names will be lowercase.
+    """
+
+    if full_listing:
+        data = listing = list_objects(
+            api,
+            url,
+            container,
+            marker,
+            limit,
+            end_marker,
+            delimiter,
+            prefix,
+            path,
+        )
+        while listing:
+            if delimiter:
+                marker = listing[-1].get('name', listing[-1].get('subdir'))
+            else:
+                marker = listing[-1]['name']
+            listing = list_objects(
+                api,
+                url,
+                container,
+                marker,
+                limit,
+                end_marker,
+                delimiter,
+                prefix,
+                path,
+            )
+            if listing:
+                data.extend(listing)
+        return data
+
+    object_url = url
+    query = "format=json"
+    if marker:
+        query += '&marker=%s' % marker
+    if limit:
+        query += '&limit=%d' % limit
+    if end_marker:
+        query += '&end_marker=%s' % end_marker
+    if delimiter:
+        query += '&delimiter=%s' % delimiter
+    if prefix:
+        query += '&prefix=%s' % prefix
+    if path:
+        query += '&path=%s' % path
+    url = "%s/%s?%s" % (object_url, container, query)
+    response = api.request('GET', url)
+    return response.json()
diff --git a/openstackclient/object/v1/object.py b/openstackclient/object/v1/object.py
new file mode 100644
index 0000000000..c6bd755b32
--- /dev/null
+++ b/openstackclient/object/v1/object.py
@@ -0,0 +1,118 @@
+#   Copyright 2013 Nebula 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.
+#
+
+"""Object v1 action implementations"""
+
+
+import logging
+
+from cliff import lister
+
+from openstackclient.common import utils
+from openstackclient.object.v1.lib import object as lib_object
+
+
+class ListObject(lister.Lister):
+    """List objects"""
+
+    log = logging.getLogger(__name__ + '.ListObject')
+
+    def get_parser(self, prog_name):
+        parser = super(ListObject, self).get_parser(prog_name)
+        parser.add_argument(
+            "container",
+            metavar="<container-name>",
+            help="List contents of container-name",
+        )
+        parser.add_argument(
+            "--prefix",
+            metavar="<prefix>",
+            help="Filter list using <prefix>",
+        )
+        parser.add_argument(
+            "--delimiter",
+            metavar="<delimiter>",
+            help="Roll up items with <delimiter>",
+        )
+        parser.add_argument(
+            "--marker",
+            metavar="<marker>",
+            help="Anchor for paging",
+        )
+        parser.add_argument(
+            "--end-marker",
+            metavar="<end-marker>",
+            help="End anchor for paging",
+        )
+        parser.add_argument(
+            "--limit",
+            metavar="<limit>",
+            type=int,
+            help="Limit the number of objects returned",
+        )
+        parser.add_argument(
+            '--long',
+            action='store_true',
+            default=False,
+            help='List additional fields in output',
+        )
+        parser.add_argument(
+            '--all',
+            action='store_true',
+            default=False,
+            help='List all objects in container (default is 10000)',
+        )
+        return parser
+
+    def take_action(self, parsed_args):
+        self.log.debug('take_action(%s)' % parsed_args)
+
+        if parsed_args.long:
+            columns = (
+                'Name',
+                'Bytes',
+                'Hash',
+                'Content Type',
+                'Last Modified',
+            )
+        else:
+            columns = ('Name',)
+
+        kwargs = {}
+        if parsed_args.prefix:
+            kwargs['prefix'] = parsed_args.prefix
+        if parsed_args.delimiter:
+            kwargs['delimiter'] = parsed_args.delimiter
+        if parsed_args.marker:
+            kwargs['marker'] = parsed_args.marker
+        if parsed_args.end_marker:
+            kwargs['end_marker'] = parsed_args.end_marker
+        if parsed_args.limit:
+            kwargs['limit'] = parsed_args.limit
+        if parsed_args.all:
+            kwargs['full_listing'] = True
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            parsed_args.container,
+            **kwargs
+        )
+
+        return (columns,
+                (utils.get_dict_properties(
+                    s, columns,
+                    formatters={},
+                ) for s in data))
diff --git a/openstackclient/shell.py b/openstackclient/shell.py
index 91b02a2b0a..6cb7c1ee2c 100644
--- a/openstackclient/shell.py
+++ b/openstackclient/shell.py
@@ -38,6 +38,7 @@ KEYRING_SERVICE = 'openstack'
 DEFAULT_COMPUTE_API_VERSION = '2'
 DEFAULT_IDENTITY_API_VERSION = '2.0'
 DEFAULT_IMAGE_API_VERSION = '1'
+DEFAULT_OBJECT_API_VERSION = '1'
 DEFAULT_VOLUME_API_VERSION = '1'
 DEFAULT_DOMAIN = 'default'
 
@@ -187,6 +188,15 @@ class OpenStackShell(app.App):
             help='Image API version, default=' +
                  DEFAULT_IMAGE_API_VERSION +
                  ' (Env: OS_IMAGE_API_VERSION)')
+        parser.add_argument(
+            '--os-object-api-version',
+            metavar='<object-api-version>',
+            default=env(
+                'OS_OBJECT_API_VERSION',
+                default=DEFAULT_OBJECT_API_VERSION),
+            help='Object API version, default=' +
+                 DEFAULT_OBJECT_API_VERSION +
+                 ' (Env: OS_OBJECT_API_VERSION)')
         parser.add_argument(
             '--os-volume-api-version',
             metavar='<volume-api-version>',
@@ -339,14 +349,15 @@ class OpenStackShell(app.App):
             'compute': self.options.os_compute_api_version,
             'identity': self.options.os_identity_api_version,
             'image': self.options.os_image_api_version,
+            'object-store': self.options.os_object_api_version,
             'volume': self.options.os_volume_api_version,
         }
 
         # Add the API version-specific commands
         for api in self.api_version.keys():
             version = '.v' + self.api_version[api].replace('.', '_')
-            self.command_manager.add_command_group(
-                'openstack.' + api + version)
+            cmd_group = 'openstack.' + api.replace('-', '_') + version
+            self.command_manager.add_command_group(cmd_group)
 
         # Commands that span multiple APIs
         self.command_manager.add_command_group(
diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py
index d0cd4a9f81..e0122022a8 100644
--- a/openstackclient/tests/fakes.py
+++ b/openstackclient/tests/fakes.py
@@ -44,6 +44,11 @@ class FakeClientManager(object):
         pass
 
 
+class FakeRESTApi(object):
+    def __init__(self):
+        pass
+
+
 class FakeResource(object):
     def __init__(self, manager, info, loaded=False):
         self.manager = manager
diff --git a/openstackclient/tests/object/__init__.py b/openstackclient/tests/object/__init__.py
new file mode 100644
index 0000000000..02be10cd89
--- /dev/null
+++ b/openstackclient/tests/object/__init__.py
@@ -0,0 +1,12 @@
+#   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.
+#
diff --git a/openstackclient/tests/object/fakes.py b/openstackclient/tests/object/fakes.py
new file mode 100644
index 0000000000..fbc784aae5
--- /dev/null
+++ b/openstackclient/tests/object/fakes.py
@@ -0,0 +1,67 @@
+#   Copyright 2013 Nebula 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.
+#
+
+container_name = 'bit-bucket'
+container_bytes = 1024
+container_count = 1
+
+container_name_2 = 'archive'
+container_name_3 = 'bit-blit'
+
+CONTAINER = {
+    'name': container_name,
+    'bytes': container_bytes,
+    'count': container_count,
+}
+
+CONTAINER_2 = {
+    'name': container_name_2,
+    'bytes': container_bytes * 2,
+    'count': container_count * 2,
+}
+
+CONTAINER_3 = {
+    'name': container_name_3,
+    'bytes': container_bytes * 3,
+    'count': container_count * 3,
+}
+
+object_name_1 = 'punch-card'
+object_bytes_1 = 80
+object_hash_1 = '1234567890'
+object_content_type_1 = 'text'
+object_modified_1 = 'today'
+
+object_name_2 = 'floppy-disk'
+object_bytes_2 = 1440000
+object_hash_2 = '0987654321'
+object_content_type_2 = 'text'
+object_modified_2 = 'today'
+
+OBJECT = {
+    'name': object_name_1,
+    'bytes': object_bytes_1,
+    'hash': object_hash_1,
+    'content_type': object_content_type_1,
+    'last_modified': object_modified_1,
+}
+
+OBJECT_2 = {
+    'name': object_name_2,
+    'bytes': object_bytes_2,
+    'hash': object_hash_2,
+    'content_type': object_content_type_2,
+    'last_modified': object_modified_2,
+}
diff --git a/openstackclient/tests/object/test_container.py b/openstackclient/tests/object/test_container.py
new file mode 100644
index 0000000000..9b53e36037
--- /dev/null
+++ b/openstackclient/tests/object/test_container.py
@@ -0,0 +1,315 @@
+#   Copyright 2013 OpenStack Foundation
+#
+#   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 copy
+import mock
+
+from openstackclient.common import clientmanager
+from openstackclient.object.v1 import container
+from openstackclient.tests.object import fakes as object_fakes
+from openstackclient.tests import utils
+
+
+AUTH_TOKEN = "foobar"
+AUTH_URL = "http://0.0.0.0"
+
+
+class FakeClient(object):
+    def __init__(self, endpoint=None, **kwargs):
+        self.endpoint = AUTH_URL
+        self.token = AUTH_TOKEN
+
+
+class TestObject(utils.TestCommand):
+    def setUp(self):
+        super(TestObject, self).setUp()
+
+        api_version = {"object-store": "1"}
+        self.app.client_manager = clientmanager.ClientManager(
+            token=AUTH_TOKEN,
+            url=AUTH_URL,
+            auth_url=AUTH_URL,
+            api_version=api_version,
+        )
+
+
+class TestObjectClient(TestObject):
+
+    def test_make_client(self):
+        self.assertEqual(self.app.client_manager.object.endpoint, AUTH_URL)
+        self.assertEqual(self.app.client_manager.object.token, AUTH_TOKEN)
+
+
+@mock.patch(
+    'openstackclient.object.v1.container.lib_container.list_containers'
+)
+class TestContainerList(TestObject):
+
+    def setUp(self):
+        super(TestContainerList, self).setUp()
+
+        # Get the command object to test
+        self.cmd = container.ListContainer(self.app, None)
+
+    def test_object_list_containers_no_options(self, c_mock):
+        c_mock.return_value = [
+            copy.deepcopy(object_fakes.CONTAINER),
+            copy.deepcopy(object_fakes.CONTAINER_3),
+            copy.deepcopy(object_fakes.CONTAINER_2),
+        ]
+
+        arglist = []
+        verifylist = []
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+        }
+        c_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.container_name, ),
+            (object_fakes.container_name_3, ),
+            (object_fakes.container_name_2, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_containers_prefix(self, c_mock):
+        c_mock.return_value = [
+            copy.deepcopy(object_fakes.CONTAINER),
+            copy.deepcopy(object_fakes.CONTAINER_3),
+        ]
+
+        arglist = [
+            '--prefix', 'bit',
+        ]
+        verifylist = [
+            ('prefix', 'bit'),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'prefix': 'bit',
+        }
+        c_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.container_name, ),
+            (object_fakes.container_name_3, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_containers_marker(self, c_mock):
+        c_mock.return_value = [
+            copy.deepcopy(object_fakes.CONTAINER),
+            copy.deepcopy(object_fakes.CONTAINER_3),
+        ]
+
+        arglist = [
+            '--marker', object_fakes.container_name,
+        ]
+        verifylist = [
+            ('marker', object_fakes.container_name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'marker': object_fakes.container_name,
+        }
+        c_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.container_name, ),
+            (object_fakes.container_name_3, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_containers_end_marker(self, c_mock):
+        c_mock.return_value = [
+            copy.deepcopy(object_fakes.CONTAINER),
+            copy.deepcopy(object_fakes.CONTAINER_3),
+        ]
+
+        arglist = [
+            '--end-marker', object_fakes.container_name_3,
+        ]
+        verifylist = [
+            ('end_marker', object_fakes.container_name_3),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'end_marker': object_fakes.container_name_3,
+        }
+        c_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.container_name, ),
+            (object_fakes.container_name_3, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_containers_limit(self, c_mock):
+        c_mock.return_value = [
+            copy.deepcopy(object_fakes.CONTAINER),
+            copy.deepcopy(object_fakes.CONTAINER_3),
+        ]
+
+        arglist = [
+            '--limit', '2',
+        ]
+        verifylist = [
+            ('limit', 2),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'limit': 2,
+        }
+        c_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.container_name, ),
+            (object_fakes.container_name_3, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_containers_long(self, c_mock):
+        c_mock.return_value = [
+            copy.deepcopy(object_fakes.CONTAINER),
+            copy.deepcopy(object_fakes.CONTAINER_3),
+        ]
+
+        arglist = [
+            '--long',
+        ]
+        verifylist = [
+            ('long', True),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+        }
+        c_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            **kwargs
+        )
+
+        collist = ('Name', 'Bytes', 'Count')
+        self.assertEqual(columns, collist)
+        datalist = (
+            (
+                object_fakes.container_name,
+                object_fakes.container_bytes,
+                object_fakes.container_count,
+            ),
+            (
+                object_fakes.container_name_3,
+                object_fakes.container_bytes * 3,
+                object_fakes.container_count * 3,
+            ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_containers_all(self, c_mock):
+        c_mock.return_value = [
+            copy.deepcopy(object_fakes.CONTAINER),
+            copy.deepcopy(object_fakes.CONTAINER_2),
+            copy.deepcopy(object_fakes.CONTAINER_3),
+        ]
+
+        arglist = [
+            '--all',
+        ]
+        verifylist = [
+            ('all', True),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'full_listing': True,
+        }
+        c_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.container_name, ),
+            (object_fakes.container_name_2, ),
+            (object_fakes.container_name_3, ),
+        )
+        self.assertEqual(tuple(data), datalist)
diff --git a/openstackclient/tests/object/test_object.py b/openstackclient/tests/object/test_object.py
new file mode 100644
index 0000000000..ddd5b592a9
--- /dev/null
+++ b/openstackclient/tests/object/test_object.py
@@ -0,0 +1,362 @@
+#   Copyright 2013 OpenStack Foundation
+#
+#   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 copy
+import mock
+
+from openstackclient.common import clientmanager
+from openstackclient.object.v1 import object as obj
+from openstackclient.tests.object import fakes as object_fakes
+from openstackclient.tests import utils
+
+
+AUTH_TOKEN = "foobar"
+AUTH_URL = "http://0.0.0.0"
+
+
+class FakeClient(object):
+    def __init__(self, endpoint=None, **kwargs):
+        self.endpoint = AUTH_URL
+        self.token = AUTH_TOKEN
+
+
+class TestObject(utils.TestCommand):
+    def setUp(self):
+        super(TestObject, self).setUp()
+
+        api_version = {"object-store": "1"}
+        self.app.client_manager = clientmanager.ClientManager(
+            token=AUTH_TOKEN,
+            url=AUTH_URL,
+            auth_url=AUTH_URL,
+            api_version=api_version,
+        )
+
+
+class TestObjectClient(TestObject):
+
+    def test_make_client(self):
+        self.assertEqual(self.app.client_manager.object.endpoint, AUTH_URL)
+        self.assertEqual(self.app.client_manager.object.token, AUTH_TOKEN)
+
+
+@mock.patch(
+    'openstackclient.object.v1.object.lib_object.list_objects'
+)
+class TestObjectList(TestObject):
+
+    def setUp(self):
+        super(TestObjectList, self).setUp()
+
+        # Get the command object to test
+        self.cmd = obj.ListObject(self.app, None)
+
+    def test_object_list_objects_no_options(self, o_mock):
+        o_mock.return_value = [
+            copy.deepcopy(object_fakes.OBJECT),
+            copy.deepcopy(object_fakes.OBJECT_2),
+        ]
+
+        arglist = [
+            object_fakes.container_name,
+        ]
+        verifylist = [
+            ('container', object_fakes.container_name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        o_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            object_fakes.container_name,
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.object_name_1, ),
+            (object_fakes.object_name_2, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_objects_prefix(self, o_mock):
+        o_mock.return_value = [
+            copy.deepcopy(object_fakes.OBJECT_2),
+        ]
+
+        arglist = [
+            '--prefix', 'floppy',
+            object_fakes.container_name_2,
+        ]
+        verifylist = [
+            ('prefix', 'floppy'),
+            ('container', object_fakes.container_name_2),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'prefix': 'floppy',
+        }
+        o_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            object_fakes.container_name_2,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.object_name_2, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_objects_delimiter(self, o_mock):
+        o_mock.return_value = [
+            copy.deepcopy(object_fakes.OBJECT_2),
+        ]
+
+        arglist = [
+            '--delimiter', '=',
+            object_fakes.container_name_2,
+        ]
+        verifylist = [
+            ('delimiter', '='),
+            ('container', object_fakes.container_name_2),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'delimiter': '=',
+        }
+        o_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            object_fakes.container_name_2,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.object_name_2, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_objects_marker(self, o_mock):
+        o_mock.return_value = [
+            copy.deepcopy(object_fakes.OBJECT_2),
+        ]
+
+        arglist = [
+            '--marker', object_fakes.object_name_2,
+            object_fakes.container_name_2,
+        ]
+        verifylist = [
+            ('marker', object_fakes.object_name_2),
+            ('container', object_fakes.container_name_2),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'marker': object_fakes.object_name_2,
+        }
+        o_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            object_fakes.container_name_2,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.object_name_2, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_objects_end_marker(self, o_mock):
+        o_mock.return_value = [
+            copy.deepcopy(object_fakes.OBJECT_2),
+        ]
+
+        arglist = [
+            '--end-marker', object_fakes.object_name_2,
+            object_fakes.container_name_2,
+        ]
+        verifylist = [
+            ('end_marker', object_fakes.object_name_2),
+            ('container', object_fakes.container_name_2),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'end_marker': object_fakes.object_name_2,
+        }
+        o_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            object_fakes.container_name_2,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.object_name_2, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_objects_limit(self, o_mock):
+        o_mock.return_value = [
+            copy.deepcopy(object_fakes.OBJECT_2),
+        ]
+
+        arglist = [
+            '--limit', '2',
+            object_fakes.container_name_2,
+        ]
+        verifylist = [
+            ('limit', 2),
+            ('container', object_fakes.container_name_2),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'limit': 2,
+        }
+        o_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            object_fakes.container_name_2,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.object_name_2, ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_objects_long(self, o_mock):
+        o_mock.return_value = [
+            copy.deepcopy(object_fakes.OBJECT),
+            copy.deepcopy(object_fakes.OBJECT_2),
+        ]
+
+        arglist = [
+            '--long',
+            object_fakes.container_name,
+        ]
+        verifylist = [
+            ('long', True),
+            ('container', object_fakes.container_name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+        }
+        o_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            object_fakes.container_name,
+            **kwargs
+        )
+
+        collist = ('Name', 'Bytes', 'Hash', 'Content Type', 'Last Modified')
+        self.assertEqual(columns, collist)
+        datalist = (
+            (
+                object_fakes.object_name_1,
+                object_fakes.object_bytes_1,
+                object_fakes.object_hash_1,
+                object_fakes.object_content_type_1,
+                object_fakes.object_modified_1,
+            ),
+            (
+                object_fakes.object_name_2,
+                object_fakes.object_bytes_2,
+                object_fakes.object_hash_2,
+                object_fakes.object_content_type_2,
+                object_fakes.object_modified_2,
+            ),
+        )
+        self.assertEqual(tuple(data), datalist)
+
+    def test_object_list_objects_all(self, o_mock):
+        o_mock.return_value = [
+            copy.deepcopy(object_fakes.OBJECT),
+            copy.deepcopy(object_fakes.OBJECT_2),
+        ]
+
+        arglist = [
+            '--all',
+            object_fakes.container_name,
+        ]
+        verifylist = [
+            ('all', True),
+            ('container', object_fakes.container_name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+        kwargs = {
+            'full_listing': True,
+        }
+        o_mock.assert_called_with(
+            self.app.restapi,
+            AUTH_URL,
+            object_fakes.container_name,
+            **kwargs
+        )
+
+        collist = ('Name',)
+        self.assertEqual(columns, collist)
+        datalist = (
+            (object_fakes.object_name_1, ),
+            (object_fakes.object_name_2, ),
+        )
+        self.assertEqual(tuple(data), datalist)
diff --git a/openstackclient/tests/object/v1/__init__.py b/openstackclient/tests/object/v1/__init__.py
new file mode 100644
index 0000000000..02be10cd89
--- /dev/null
+++ b/openstackclient/tests/object/v1/__init__.py
@@ -0,0 +1,12 @@
+#   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.
+#
diff --git a/openstackclient/tests/object/v1/lib/__init__.py b/openstackclient/tests/object/v1/lib/__init__.py
new file mode 100644
index 0000000000..02be10cd89
--- /dev/null
+++ b/openstackclient/tests/object/v1/lib/__init__.py
@@ -0,0 +1,12 @@
+#   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.
+#
diff --git a/openstackclient/tests/object/v1/lib/test_container.py b/openstackclient/tests/object/v1/lib/test_container.py
new file mode 100644
index 0000000000..a241cc021f
--- /dev/null
+++ b/openstackclient/tests/object/v1/lib/test_container.py
@@ -0,0 +1,159 @@
+#   Copyright 2013 Nebula 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.
+#
+
+"""Test Object API library module"""
+
+from __future__ import unicode_literals
+
+import mock
+
+
+from openstackclient.object.v1.lib import container as lib_container
+from openstackclient.tests.common import test_restapi as restapi
+from openstackclient.tests import utils
+
+
+fake_auth = '11223344556677889900'
+fake_url = 'http://gopher.com'
+
+fake_container = 'rainbarrel'
+
+
+class FakeClient(object):
+    def __init__(self, endpoint=None, **kwargs):
+        self.endpoint = fake_url
+        self.token = fake_auth
+
+
+class TestObject(utils.TestCommand):
+
+    def setUp(self):
+        super(TestObject, self).setUp()
+        self.app.client_manager.object = FakeClient()
+        self.app.restapi = mock.MagicMock()
+
+
+class TestObjectListContainers(TestObject):
+
+    def test_list_containers_no_options(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_container.list_containers(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '?format=json',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_containers_marker(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_container.list_containers(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            marker='next',
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '?format=json&marker=next',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_containers_limit(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_container.list_containers(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            limit=5,
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '?format=json&limit=5',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_containers_end_marker(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_container.list_containers(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            end_marker='last',
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '?format=json&end_marker=last',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_containers_prefix(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_container.list_containers(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            prefix='foo/',
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '?format=json&prefix=foo/',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_containers_full_listing(self):
+
+        def side_effect(*args, **kwargs):
+            rv = self.app.restapi.request.return_value
+            self.app.restapi.request.return_value = restapi.FakeResponse(
+                data=[],
+            )
+            self.app.restapi.request.side_effect = None
+            return rv
+
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+        self.app.restapi.request.side_effect = side_effect
+
+        data = lib_container.list_containers(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            full_listing=True,
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '?format=json&marker=is-name',
+        )
+        self.assertEqual(data, resp)
diff --git a/openstackclient/tests/object/v1/lib/test_object.py b/openstackclient/tests/object/v1/lib/test_object.py
new file mode 100644
index 0000000000..ef8ae18dc5
--- /dev/null
+++ b/openstackclient/tests/object/v1/lib/test_object.py
@@ -0,0 +1,203 @@
+#   Copyright 2013 Nebula 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.
+#
+
+"""Test Object API library module"""
+
+from __future__ import unicode_literals
+
+import mock
+
+from openstackclient.object.v1.lib import object as lib_object
+from openstackclient.tests.common import test_restapi as restapi
+from openstackclient.tests import utils
+
+
+fake_auth = '11223344556677889900'
+fake_url = 'http://gopher.com'
+
+fake_container = 'rainbarrel'
+
+
+class FakeClient(object):
+    def __init__(self, endpoint=None, **kwargs):
+        self.endpoint = fake_url
+        self.token = fake_auth
+
+
+class TestObject(utils.TestCommand):
+
+    def setUp(self):
+        super(TestObject, self).setUp()
+        self.app.client_manager.object = FakeClient()
+        self.app.restapi = mock.MagicMock()
+
+
+class TestObjectListObjects(TestObject):
+
+    def test_list_objects_no_options(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            fake_container,
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '/' + fake_container + '?format=json',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_objects_marker(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            fake_container,
+            marker='next',
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '/' + fake_container + '?format=json&marker=next',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_objects_limit(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            fake_container,
+            limit=5,
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '/' + fake_container + '?format=json&limit=5',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_objects_end_marker(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            fake_container,
+            end_marker='last',
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '/' + fake_container + '?format=json&end_marker=last',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_objects_delimiter(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            fake_container,
+            delimiter='|',
+        )
+
+        # Check expected values
+        # NOTE(dtroyer): requests handles the URL encoding and we're
+        #                mocking that so use the otherwise-not-legal
+        #                pipe '|' char in the response.
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '/' + fake_container + '?format=json&delimiter=|',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_objects_prefix(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            fake_container,
+            prefix='foo/',
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '/' + fake_container + '?format=json&prefix=foo/',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_objects_path(self):
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            fake_container,
+            path='next',
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '/' + fake_container + '?format=json&path=next',
+        )
+        self.assertEqual(data, resp)
+
+    def test_list_objects_full_listing(self):
+
+        def side_effect(*args, **kwargs):
+            rv = self.app.restapi.request.return_value
+            self.app.restapi.request.return_value = restapi.FakeResponse(
+                data=[],
+            )
+            self.app.restapi.request.side_effect = None
+            return rv
+
+        resp = [{'name': 'is-name'}]
+        self.app.restapi.request.return_value = restapi.FakeResponse(data=resp)
+        self.app.restapi.request.side_effect = side_effect
+
+        data = lib_object.list_objects(
+            self.app.restapi,
+            self.app.client_manager.object.endpoint,
+            fake_container,
+            full_listing=True,
+        )
+
+        # Check expected values
+        self.app.restapi.request.assert_called_with(
+            'GET',
+            fake_url + '/' + fake_container + '?format=json&marker=is-name',
+        )
+        self.assertEqual(data, resp)
diff --git a/openstackclient/tests/utils.py b/openstackclient/tests/utils.py
index ff7d8a336d..4516318908 100644
--- a/openstackclient/tests/utils.py
+++ b/openstackclient/tests/utils.py
@@ -71,6 +71,7 @@ class TestCommand(TestCase):
         self.fake_stdout = fakes.FakeStdout()
         self.app = fakes.FakeApp(self.fake_stdout)
         self.app.client_manager = fakes.FakeClientManager()
+        self.app.restapi = fakes.FakeRESTApi()
 
     def check_parser(self, cmd, args, verify_args):
         cmd_parser = cmd.get_parser('check_parser')
diff --git a/setup.cfg b/setup.cfg
index ebfcb9fa87..e6fe8475ca 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -239,6 +239,10 @@ openstack.compute.v2 =
     server_unrescue = openstackclient.compute.v2.server:UnrescueServer
     server_unset = openstackclient.compute.v2.server:UnsetServer
 
+openstack.object_store.v1 =
+    container_list = openstackclient.object.v1.container:ListContainer
+    object_list = openstackclient.object.v1.object:ListObject
+
 openstack.volume.v1 =
     snapshot_create = openstackclient.volume.v1.snapshot:CreateSnapshot
     snapshot_delete = openstackclient.volume.v1.snapshot:DeleteSnapshot