diff --git a/openstackclient/compute/v2/keypair.py b/openstackclient/compute/v2/keypair.py
index 71c9d6747b..22d918a4b3 100644
--- a/openstackclient/compute/v2/keypair.py
+++ b/openstackclient/compute/v2/keypair.py
@@ -15,6 +15,7 @@
 
 """Keypair action implementations"""
 
+import io
 import os
 import six
 import sys
@@ -47,7 +48,8 @@ class CreateKeypair(command.ShowOne):
         public_key = parsed_args.public_key
         if public_key:
             try:
-                with open(os.path.expanduser(parsed_args.public_key)) as p:
+                with io.open(os.path.expanduser(parsed_args.public_key),
+                             "rb") as p:
                     public_key = p.read()
             except IOError as e:
                 msg = "Key file %s not found: %s"
diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py
index f4d79ff7c4..a9c7154a2f 100644
--- a/openstackclient/tests/compute/v2/fakes.py
+++ b/openstackclient/tests/compute/v2/fakes.py
@@ -137,6 +137,9 @@ class FakeComputev2Client(object):
         self.networks = mock.Mock()
         self.networks.resource_class = fakes.FakeResource(None, {})
 
+        self.keypairs = mock.Mock()
+        self.keypairs.resource_class = fakes.FakeResource(None, {})
+
         self.auth_token = kwargs['token']
 
         self.management_url = kwargs['endpoint']
@@ -534,6 +537,58 @@ class FakeFlavor(object):
         return mock.MagicMock(side_effect=flavors)
 
 
+class FakeKeypair(object):
+    """Fake one or more keypairs."""
+
+    @staticmethod
+    def create_one_keypair(attrs=None, no_pri=False):
+        """Create a fake keypair
+
+        :param Dictionary attrs:
+            A dictionary with all attributes
+        :return:
+            A FakeResource
+        """
+        # Set default attributes.
+        if attrs is None:
+            attrs = {}
+
+        keypair_info = {
+            'name': 'keypair-name-' + uuid.uuid4().hex,
+            'fingerprint': 'dummy',
+            'public_key': 'dummy',
+            'user_id': 'user'
+        }
+        if not no_pri:
+            keypair_info['private_key'] = 'private_key'
+
+        # Overwrite default attributes.
+        keypair_info.update(attrs)
+
+        keypair = fakes.FakeResource(info=copy.deepcopy(keypair_info),
+                                     loaded=True)
+
+        return keypair
+
+    @staticmethod
+    def create_keypairs(attrs=None, count=2):
+        """Create multiple fake flavors.
+
+        :param Dictionary attrs:
+            A dictionary with all attributes
+        :param int count:
+            The number of flavors to fake
+        :return:
+            A list of FakeFlavorResource objects faking the flavors
+        """
+
+        keypairs = []
+        for i in range(0, count):
+            keypairs.append(FakeKeypair.create_one_keypair(attrs))
+
+        return keypairs
+
+
 class FakeAvailabilityZone(object):
     """Fake one or more compute availability zones (AZs)."""
 
diff --git a/openstackclient/tests/compute/v2/test_keypair.py b/openstackclient/tests/compute/v2/test_keypair.py
new file mode 100644
index 0000000000..a50a532392
--- /dev/null
+++ b/openstackclient/tests/compute/v2/test_keypair.py
@@ -0,0 +1,260 @@
+#   Copyright 2016 IBM
+#
+#   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 mock
+
+from openstackclient.compute.v2 import keypair
+from openstackclient.tests.compute.v2 import fakes as compute_fakes
+from openstackclient.tests import utils as tests_utils
+
+
+class TestKeypair(compute_fakes.TestComputev2):
+
+    def setUp(self):
+        super(TestKeypair, self).setUp()
+
+        # Get a shortcut to the KeypairManager Mock
+        self.keypairs_mock = self.app.client_manager.compute.keypairs
+        self.keypairs_mock.reset_mock()
+
+
+class TestKeypairCreate(TestKeypair):
+
+    keypair = compute_fakes.FakeKeypair.create_one_keypair()
+
+    def setUp(self):
+        super(TestKeypairCreate, self).setUp()
+
+        self.columns = (
+            'fingerprint',
+            'name',
+            'user_id'
+        )
+        self.data = (
+            self.keypair.fingerprint,
+            self.keypair.name,
+            self.keypair.user_id
+        )
+
+        # Get the command object to test
+        self.cmd = keypair.CreateKeypair(self.app, None)
+
+        self.keypairs_mock.create.return_value = self.keypair
+
+    def test_key_pair_create_no_options(self):
+
+        arglist = [
+            self.keypair.name,
+        ]
+        verifylist = [
+            ('name', self.keypair.name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        columns, data = self.cmd.take_action(parsed_args)
+
+        self.keypairs_mock.create.assert_called_with(
+            self.keypair.name,
+            public_key=None
+        )
+
+        self.assertEqual({}, columns)
+        self.assertEqual({}, data)
+
+    def test_keypair_create_public_key(self):
+        # overwrite the setup one because we want to omit private_key
+        self.keypair = compute_fakes.FakeKeypair.create_one_keypair(
+            no_pri=True)
+        self.keypairs_mock.create.return_value = self.keypair
+
+        self.data = (
+            self.keypair.fingerprint,
+            self.keypair.name,
+            self.keypair.user_id
+        )
+
+        arglist = [
+            '--public-key', self.keypair.public_key,
+            self.keypair.name,
+        ]
+        verifylist = [
+            ('public_key', self.keypair.public_key),
+            ('name', self.keypair.name)
+        ]
+
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        with mock.patch('io.open') as mock_open:
+            mock_open.return_value = mock.MagicMock()
+            m_file = mock_open.return_value.__enter__.return_value
+            m_file.read.return_value = 'dummy'
+
+            columns, data = self.cmd.take_action(parsed_args)
+
+            self.keypairs_mock.create.assert_called_with(
+                self.keypair.name,
+                public_key=self.keypair.public_key
+            )
+
+            self.assertEqual(self.columns, columns)
+            self.assertEqual(self.data, data)
+
+
+class TestKeypairDelete(TestKeypair):
+
+    keypair = compute_fakes.FakeKeypair.create_one_keypair()
+
+    def setUp(self):
+        super(TestKeypairDelete, self).setUp()
+
+        self.keypairs_mock.get.return_value = self.keypair
+        self.keypairs_mock.delete.return_value = None
+
+        self.cmd = keypair.DeleteKeypair(self.app, None)
+
+    def test_keypair_delete(self):
+        arglist = [
+            self.keypair.name
+        ]
+        verifylist = [
+            ('name', self.keypair.name),
+        ]
+
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        ret = self.cmd.take_action(parsed_args)
+
+        self.assertIsNone(ret)
+        self.keypairs_mock.delete.assert_called_with(self.keypair.name)
+
+
+class TestKeypairList(TestKeypair):
+
+    # Return value of self.keypairs_mock.list().
+    keypairs = compute_fakes.FakeKeypair.create_keypairs(count=1)
+
+    columns = (
+        "Name",
+        "Fingerprint"
+    )
+
+    data = ((
+        keypairs[0].name,
+        keypairs[0].fingerprint
+    ), )
+
+    def setUp(self):
+        super(TestKeypairList, self).setUp()
+
+        self.keypairs_mock.list.return_value = self.keypairs
+
+        # Get the command object to test
+        self.cmd = keypair.ListKeypair(self.app, None)
+
+    def test_keypair_list_no_options(self):
+        arglist = []
+        verifylist = [
+        ]
+
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # In base command class Lister in cliff, abstract method take_action()
+        # returns a tuple containing the column names and an iterable
+        # containing the data to be listed.
+        columns, data = self.cmd.take_action(parsed_args)
+
+        # Set expected values
+
+        self.keypairs_mock.list.assert_called_with()
+
+        self.assertEqual(self.columns, columns)
+        self.assertEqual(tuple(self.data), tuple(data))
+
+
+class TestKeypairShow(TestKeypair):
+
+    keypair = compute_fakes.FakeKeypair.create_one_keypair()
+
+    def setUp(self):
+        super(TestKeypairShow, self).setUp()
+
+        self.keypairs_mock.get.return_value = self.keypair
+
+        self.cmd = keypair.ShowKeypair(self.app, None)
+
+        self.columns = (
+            "fingerprint",
+            "name",
+            "user_id"
+        )
+
+        self.data = (
+            self.keypair.fingerprint,
+            self.keypair.name,
+            self.keypair.user_id
+        )
+
+    def test_show_no_options(self):
+
+        arglist = []
+        verifylist = []
+
+        # Missing required args should boil here
+        self.assertRaises(tests_utils.ParserException, self.check_parser,
+                          self.cmd, arglist, verifylist)
+
+    def test_keypair_show(self):
+        # overwrite the setup one because we want to omit private_key
+        self.keypair = compute_fakes.FakeKeypair.create_one_keypair(
+            no_pri=True)
+        self.keypairs_mock.get.return_value = self.keypair
+
+        self.data = (
+            self.keypair.fingerprint,
+            self.keypair.name,
+            self.keypair.user_id
+        )
+
+        arglist = [
+            self.keypair.name
+        ]
+        verifylist = [
+            ('name', self.keypair.name)
+        ]
+
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        columns, data = self.cmd.take_action(parsed_args)
+
+        self.assertEqual(self.columns, columns)
+        self.assertEqual(self.data, data)
+
+    def test_keypair_show_public(self):
+
+        arglist = [
+            '--public-key',
+            self.keypair.name
+        ]
+        verifylist = [
+            ('public_key', True),
+            ('name', self.keypair.name)
+        ]
+
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        columns, data = self.cmd.take_action(parsed_args)
+
+        self.assertEqual({}, columns)
+        self.assertEqual({}, data)