1#   Copyright 2016 IBM
2#
3#   Licensed under the Apache License, Version 2.0 (the "License"); you may
4#   not use this file except in compliance with the License. You may obtain
5#   a copy of the License at
6#
7#        http://www.apache.org/licenses/LICENSE-2.0
8#
9#   Unless required by applicable law or agreed to in writing, software
10#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12#   License for the specific language governing permissions and limitations
13#   under the License.
14#
15
16from unittest import mock
17from unittest.mock import call
18import uuid
19
20from osc_lib import exceptions
21from osc_lib import utils
22
23from openstackclient.compute.v2 import keypair
24from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
25from openstackclient.tests.unit import utils as tests_utils
26
27
28class TestKeypair(compute_fakes.TestComputev2):
29
30    def setUp(self):
31        super(TestKeypair, self).setUp()
32
33        # Get a shortcut to the KeypairManager Mock
34        self.keypairs_mock = self.app.client_manager.compute.keypairs
35        self.keypairs_mock.reset_mock()
36
37
38class TestKeypairCreate(TestKeypair):
39
40    keypair = compute_fakes.FakeKeypair.create_one_keypair()
41
42    def setUp(self):
43        super(TestKeypairCreate, self).setUp()
44
45        self.columns = (
46            'fingerprint',
47            'name',
48            'user_id'
49        )
50        self.data = (
51            self.keypair.fingerprint,
52            self.keypair.name,
53            self.keypair.user_id
54        )
55
56        # Get the command object to test
57        self.cmd = keypair.CreateKeypair(self.app, None)
58
59        self.keypairs_mock.create.return_value = self.keypair
60
61    def test_key_pair_create_no_options(self):
62
63        arglist = [
64            self.keypair.name,
65        ]
66        verifylist = [
67            ('name', self.keypair.name),
68        ]
69        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
70
71        columns, data = self.cmd.take_action(parsed_args)
72
73        self.keypairs_mock.create.assert_called_with(
74            self.keypair.name,
75            public_key=None
76        )
77
78        self.assertEqual({}, columns)
79        self.assertEqual({}, data)
80
81    def test_keypair_create_public_key(self):
82        # overwrite the setup one because we want to omit private_key
83        self.keypair = compute_fakes.FakeKeypair.create_one_keypair(
84            no_pri=True)
85        self.keypairs_mock.create.return_value = self.keypair
86
87        self.data = (
88            self.keypair.fingerprint,
89            self.keypair.name,
90            self.keypair.user_id
91        )
92
93        arglist = [
94            '--public-key', self.keypair.public_key,
95            self.keypair.name,
96        ]
97        verifylist = [
98            ('public_key', self.keypair.public_key),
99            ('name', self.keypair.name)
100        ]
101
102        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
103
104        with mock.patch('io.open') as mock_open:
105            mock_open.return_value = mock.MagicMock()
106            m_file = mock_open.return_value.__enter__.return_value
107            m_file.read.return_value = 'dummy'
108
109            columns, data = self.cmd.take_action(parsed_args)
110
111            self.keypairs_mock.create.assert_called_with(
112                self.keypair.name,
113                public_key=self.keypair.public_key
114            )
115
116            self.assertEqual(self.columns, columns)
117            self.assertEqual(self.data, data)
118
119    def test_keypair_create_private_key(self):
120        tmp_pk_file = '/tmp/kp-file-' + uuid.uuid4().hex
121        arglist = [
122            '--private-key', tmp_pk_file,
123            self.keypair.name,
124        ]
125        verifylist = [
126            ('private_key', tmp_pk_file),
127            ('name', self.keypair.name)
128        ]
129
130        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
131
132        with mock.patch('io.open') as mock_open:
133            mock_open.return_value = mock.MagicMock()
134            m_file = mock_open.return_value.__enter__.return_value
135
136            columns, data = self.cmd.take_action(parsed_args)
137
138            self.keypairs_mock.create.assert_called_with(
139                self.keypair.name,
140                public_key=None
141            )
142
143            mock_open.assert_called_once_with(tmp_pk_file, 'w+')
144            m_file.write.assert_called_once_with(self.keypair.private_key)
145
146            self.assertEqual(self.columns, columns)
147            self.assertEqual(self.data, data)
148
149
150class TestKeypairDelete(TestKeypair):
151
152    keypairs = compute_fakes.FakeKeypair.create_keypairs(count=2)
153
154    def setUp(self):
155        super(TestKeypairDelete, self).setUp()
156
157        self.keypairs_mock.get = compute_fakes.FakeKeypair.get_keypairs(
158            self.keypairs)
159        self.keypairs_mock.delete.return_value = None
160
161        self.cmd = keypair.DeleteKeypair(self.app, None)
162
163    def test_keypair_delete(self):
164        arglist = [
165            self.keypairs[0].name
166        ]
167        verifylist = [
168            ('name', [self.keypairs[0].name]),
169        ]
170
171        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
172
173        ret = self.cmd.take_action(parsed_args)
174
175        self.assertIsNone(ret)
176        self.keypairs_mock.delete.assert_called_with(self.keypairs[0].name)
177
178    def test_delete_multiple_keypairs(self):
179        arglist = []
180        for k in self.keypairs:
181            arglist.append(k.name)
182        verifylist = [
183            ('name', arglist),
184        ]
185
186        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
187        result = self.cmd.take_action(parsed_args)
188
189        calls = []
190        for k in self.keypairs:
191            calls.append(call(k.name))
192        self.keypairs_mock.delete.assert_has_calls(calls)
193        self.assertIsNone(result)
194
195    def test_delete_multiple_keypairs_with_exception(self):
196        arglist = [
197            self.keypairs[0].name,
198            'unexist_keypair',
199        ]
200        verifylist = [
201            ('name', arglist),
202        ]
203
204        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
205
206        find_mock_result = [self.keypairs[0], exceptions.CommandError]
207        with mock.patch.object(utils, 'find_resource',
208                               side_effect=find_mock_result) as find_mock:
209            try:
210                self.cmd.take_action(parsed_args)
211                self.fail('CommandError should be raised.')
212            except exceptions.CommandError as e:
213                self.assertEqual('1 of 2 keys failed to delete.', str(e))
214
215            find_mock.assert_any_call(
216                self.keypairs_mock, self.keypairs[0].name)
217            find_mock.assert_any_call(self.keypairs_mock, 'unexist_keypair')
218
219            self.assertEqual(2, find_mock.call_count)
220            self.keypairs_mock.delete.assert_called_once_with(
221                self.keypairs[0].name
222            )
223
224
225class TestKeypairList(TestKeypair):
226
227    # Return value of self.keypairs_mock.list().
228    keypairs = compute_fakes.FakeKeypair.create_keypairs(count=1)
229
230    columns = (
231        "Name",
232        "Fingerprint"
233    )
234
235    data = ((
236        keypairs[0].name,
237        keypairs[0].fingerprint
238    ), )
239
240    def setUp(self):
241        super(TestKeypairList, self).setUp()
242
243        self.keypairs_mock.list.return_value = self.keypairs
244
245        # Get the command object to test
246        self.cmd = keypair.ListKeypair(self.app, None)
247
248    def test_keypair_list_no_options(self):
249        arglist = []
250        verifylist = [
251        ]
252
253        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
254
255        # In base command class Lister in cliff, abstract method take_action()
256        # returns a tuple containing the column names and an iterable
257        # containing the data to be listed.
258        columns, data = self.cmd.take_action(parsed_args)
259
260        # Set expected values
261
262        self.keypairs_mock.list.assert_called_with()
263
264        self.assertEqual(self.columns, columns)
265        self.assertEqual(tuple(self.data), tuple(data))
266
267
268class TestKeypairShow(TestKeypair):
269
270    keypair = compute_fakes.FakeKeypair.create_one_keypair()
271
272    def setUp(self):
273        super(TestKeypairShow, self).setUp()
274
275        self.keypairs_mock.get.return_value = self.keypair
276
277        self.cmd = keypair.ShowKeypair(self.app, None)
278
279        self.columns = (
280            "fingerprint",
281            "name",
282            "user_id"
283        )
284
285        self.data = (
286            self.keypair.fingerprint,
287            self.keypair.name,
288            self.keypair.user_id
289        )
290
291    def test_show_no_options(self):
292
293        arglist = []
294        verifylist = []
295
296        # Missing required args should boil here
297        self.assertRaises(tests_utils.ParserException, self.check_parser,
298                          self.cmd, arglist, verifylist)
299
300    def test_keypair_show(self):
301        # overwrite the setup one because we want to omit private_key
302        self.keypair = compute_fakes.FakeKeypair.create_one_keypair(
303            no_pri=True)
304        self.keypairs_mock.get.return_value = self.keypair
305
306        self.data = (
307            self.keypair.fingerprint,
308            self.keypair.name,
309            self.keypair.user_id
310        )
311
312        arglist = [
313            self.keypair.name
314        ]
315        verifylist = [
316            ('name', self.keypair.name)
317        ]
318
319        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
320
321        columns, data = self.cmd.take_action(parsed_args)
322
323        self.assertEqual(self.columns, columns)
324        self.assertEqual(self.data, data)
325
326    def test_keypair_show_public(self):
327
328        arglist = [
329            '--public-key',
330            self.keypair.name
331        ]
332        verifylist = [
333            ('public_key', True),
334            ('name', self.keypair.name)
335        ]
336
337        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
338
339        columns, data = self.cmd.take_action(parsed_args)
340
341        self.assertEqual({}, columns)
342        self.assertEqual({}, data)
343